2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
3 Ben Kibbey <bjk@luxsci.net>
5 This file is part of libpwmd.
7 Libpwmd is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 2 of the License, or
10 (at your option) any later version.
12 Libpwmd is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Libpwmd. If not, see <http://www.gnu.org/licenses/>.
33 #include <sys/select.h>
35 #include <sys/types.h>
46 #ifdef HAVE_GETOPT_LONG
51 #include "getopt_long.h"
54 #ifdef HAVE_LIBREADLINE
55 #if defined(HAVE_READLINE_READLINE_H)
56 #include <readline/readline.h>
57 #elif defined(HAVE_READLINE_H)
59 #endif /* !defined(HAVE_READLINE_H) */
60 static int interactive_error
;
61 static int interactive
;
62 #endif /* HAVE_LIBREADLINE */
64 #ifdef HAVE_READLINE_HISTORY
65 #if defined(HAVE_READLINE_HISTORY_H)
66 #include <readline/history.h>
67 #elif defined(HAVE_HISTORY_H)
70 #endif /* HAVE_READLINE_HISTORY */
77 #define N_(msgid) gettext(msgid)
81 #define DEFAULT_PIN_TRIES 3
82 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
85 static int no_pinentry
;
87 static char *filename
;
89 static int force_save
;
90 static int no_passphrase
;
93 static char *sign_keygrip
;
94 static char *keyparams
;
95 static char *password
;
97 static char *new_keyfile
;
98 static unsigned long s2k_count
;
99 static uint64_t iterations
;
100 static int iterations_arg
;
102 static int local_pin
;
103 static int inquirefd
;
105 static int no_gpg_agent
;
112 size_t size
; // from stat(2).
116 static gpg_error_t
finalize ();
117 static gpg_error_t
set_inquire (int fd
, const char *line
,
118 struct inquire_s
**result
);
119 static gpg_error_t
parse_dotcommand (const char *line
, char **result
,
120 size_t * len
, struct inquire_s
*inq
);
121 static gpg_error_t
open_command (const char *line
);
123 static gpg_error_t
get_password (char **result
, pwmd_pinentry_t w
, int echo
);
127 show_error (gpg_error_t rc
, const char *str
)
129 fprintf (stderr
, "ERR %i: %s%s%s%s", rc
, gpg_strerror (rc
),
130 str
? ": " : "", str
? str
: "", str
? "" : "\n");
134 usage (const char *pn
, int status
)
136 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
137 N_("Read a PWMD protocol command from standard input.\n\n"
138 "Usage: pwmc [options] [file]\n"
140 " a url string to connect to (see below)\n"
141 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
142 " --connect-timeout <seconds>\n"
143 " seconds before connecting to a remote host fails (120)\n"
144 " --socket-timeout <seconds>\n"
145 " seconds before a remote command fails (0=disabled, default=300)\n"
148 " --ca-cert <filename>\n"
149 " certificate authority (CA) used to sign the server cert\n"
150 " --client-cert <filename>\n"
151 " client certificate to use for authentication\n"
152 " --client-key <filename>\n"
153 " key file used to protect the client certificate\n"
154 " --tls-priority <string>\n"
155 " compression, cipher and hash algorithm string (SECURE256)\n"
157 " verify the hostname against the server certificate\n"
158 " --tls-fingerprint <string>\n"
159 " a SHA-1 hash of the server fingerprint to verify against\n"
163 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
164 " --identity, -i <filename>\n"
165 " the ssh identity file to use for authentication\n"
166 " --knownhosts, -k <filename>\n"
167 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
170 " do not lock the data file upon opening it\n"
171 " --lock-timeout <N>\n"
172 " time in tenths of a second to wait for a locked data file\n"
173 " --name, -n <string>\n"
174 " set the client name\n"
175 " --pinentry <path>\n"
176 " the full path to the pinentry binary (server default)\n"
177 " --local-pinentry\n"
178 " force using a local pinentry\n"
180 " disable pinentry both remotely and locally\n"
181 " --ttyname, -y <path>\n"
182 " tty that pinentry will use\n"
183 " --ttytype, -t <string>\n"
184 " pinentry terminal type (default is $TERM)\n"
186 " pinentry display (default is $DISPLAY)\n"
187 " --lc-ctype <string>\n"
188 " locale setting for pinentry\n"
189 " --lc-messages <string>\n"
190 " locale setting for pinentry\n"
192 " number of pinentry tries before failing (3)\n"
193 " --timeout <seconds>\n"
194 " pinentry timeout\n"
195 " --inquire <COMMAND>\n"
196 " the specified command (with any options) uses a server inquire while\n"
197 " command data is read via the inquire file descriptor (stdin)\n"
198 " --inquire-line, -L <STRING>\n"
199 " the initial line to send (i.e., element path) before the inquire data\n"
200 " --inquire-fd <FD>\n"
201 " read inquire data from the specified file descriptor (stdin)\n"
202 " --inquire-file <filename>\n"
203 " read inquire data from the specified filename\n"
204 " --output-fd <FD>\n"
205 " redirect command output to the specified file descriptor\n"
207 " send the SAVE command before exiting\n"
209 " like --save but always ask for a passphrase\n"
211 " do not require a passphrase when saving a new file\n"
213 " disable use of gpg-agent when saving to a new file\n"
214 " --key-file <filename>\n"
215 " obtain the passphrase from the specified filename\n"
216 " --new-key-file <filename>\n"
217 " obtain the passphrase to save with from the specified filename\n"
218 " --cipher <string>\n"
219 " the cipher to use when saving (see pwmd(1))\n"
220 " --cipher-iterations <N>\n"
221 " the number of times to encrypt the XML data (N+1)\n"
222 " --key-params <string>\n"
223 " the key parameters to use when saving a new file (pwmd default)\n"
224 " --keygrip <string>\n"
225 " the hex string of the keygrip to save to\n"
226 " --sign-keygrip <string>\n"
227 " the hex string of the keygrip to sign with\n"
229 " the number of times to hash the passphrase for a new file\n"
231 " disable showing of status messages from the server\n"
233 " disable showing of extra messages (implies --no-status)\n"
234 #ifdef HAVE_LIBREADLINE
236 " use a shell like interface to pwmd (allows more than one command)\n"
240 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
242 "An optional url may be in the form of:\n"
243 " --url /path/to/socket\n"
244 " --url file://[path/to/socket]\n"
247 " --url ssh[46]://[username@]hostname[:port]\n"
248 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
252 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
253 " --client-key filename\n"
260 inquire_cb (void *user
, const char *keyword
, gpg_error_t rc
,
261 char **data
, size_t * size
)
263 struct inquire_s
*inq
= user
;
265 int is_newpassword
= 0;
273 if (!strcmp (keyword
, "PASSPHRASE"))
275 else if (!strcmp (keyword
, "NEW_PASSPHRASE"))
277 #ifdef HAVE_LIBREADLINE
278 else if (!strcmp (keyword
, "KEYPARAM") && !interactive
)
281 else if (!strcmp (keyword
, "KEYPARAM"))
284 if (!keyparams
|| !*keyparams
)
285 return gpg_error (GPG_ERR_INV_PARAMETER
);
288 *size
= strlen (keyparams
);
289 return gpg_error (GPG_ERR_EOF
);
292 if ((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
))
294 int fd
= open (is_password
? keyfile
: new_keyfile
, O_RDONLY
);
298 fprintf (stderr
, "%s: %s\n", is_newpassword
? new_keyfile
: keyfile
,
300 return gpg_error_from_syserror ();
303 rc
= set_inquire (fd
, NULL
, &inq
);
311 fprintf (stderr
, N_("Using keyfile '%s' as %s.\n"),
312 is_newpassword
? new_keyfile
: keyfile
, keyword
);
314 if (!new_keyfile
|| is_newpassword
)
318 pwmd_socket_type (pwm
, &t
);
319 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
320 if (!no_pinentry
&& t
== PWMD_SOCKET_LOCAL
)
321 pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 0);
324 else if (is_password
&& !keyfile
)
328 rc
= pwmd_password (pwm
, keyword
, &tmp
, &inq
->len
);
329 if (rc
&& gpg_err_code (rc
) != GPG_ERR_EOF
)
332 pwmd_free (inq
->line
);
336 return gpg_error (GPG_ERR_EOF
);
338 #ifdef HAVE_LIBREADLINE
339 else if (!inq
->header
&& interactive
)
343 ("Press CTRL-D to send the current line. Press twice to end. %s:\n"),
349 /* The first part of the command data. */
355 return inq
->fd
== -1 ? gpg_error (GPG_ERR_EOF
) : 0;
358 *size
= read (inq
->fd
, inq
->line
, ASSUAN_LINELENGTH
);
362 return gpg_error (gpg_error_from_syserror ());
366 else if (inq
->fd
!= STDIN_FILENO
&& (is_newpassword
|| is_password
))
374 if (((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
))
375 && *size
== inq
->size
)
376 return gpg_error (GPG_ERR_EOF
);
378 return *size
? 0 : gpg_error (GPG_ERR_EOF
);
382 status_msg_cb (void *data
, const char *line
)
384 char *p
= strchr (line
, ' ');
386 if (!strcmp (line
, "KEEPALIVE"))
389 if (*line
!= '#' && p
&& strchr (p
, ' ') && *++p
)
391 char *p1
= strchr (p
, ' ');
392 int a
= strtol (p
, NULL
, 10);
394 if (isdigit (*p
) && p1
)
396 int b
= strtol (p1
, NULL
, 10);
398 int t
= a
&& b
? a
* 100 / b
: 0;
400 strncpy (l
, line
, strlen (line
) - strlen (p
) - 1);
401 fprintf (stderr
, "\r%s %i/%i %i%%%s", l
, a
, b
, t
,
408 fprintf (stderr
, "%s\n", line
);
410 #ifdef HAVE_LIBREADLINE
419 return pwmd_process (pwm
);
424 get_password (char **result
, pwmd_pinentry_t w
, int echo
)
426 char buf
[LINE_MAX
] = { 0 }, *p
;
427 struct termios told
, tnew
;
432 if (!isatty (STDIN_FILENO
))
434 fprintf (stderr
, N_("Input is not from a terminal! Failing.\n"));
435 return GPG_ERR_ENOTTY
;
440 if (tcgetattr (STDIN_FILENO
, &told
) == -1)
441 return gpg_error_from_syserror ();
443 memcpy (&tnew
, &told
, sizeof (struct termios
));
444 tnew
.c_lflag
&= ~(ECHO
);
445 tnew
.c_lflag
|= ICANON
| ECHONL
;
447 if (tcsetattr (STDIN_FILENO
, TCSANOW
, &tnew
) == -1)
451 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
452 return gpg_error_from_errno (n
);
458 case PWMD_PINENTRY_OPEN
:
459 fprintf (stderr
, N_("Password for %s: "), filename
);
461 case PWMD_PINENTRY_OPEN_FAILED
:
462 fprintf (stderr
, N_("Invalid password. Password for %s: "), filename
);
464 case PWMD_PINENTRY_SAVE
:
465 fprintf (stderr
, N_("New password for %s: "), filename
);
467 case PWMD_PINENTRY_SAVE_CONFIRM
:
468 fprintf (stderr
, N_("Confirm password: "));
474 if ((p
= fgets (buf
, sizeof (buf
), stdin
)) == NULL
)
476 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
481 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
486 return GPG_ERR_CANCELED
;
489 p
[strlen (p
) - 1] = 0;
493 key
= pwmd_strdup_printf ("%s", p
);
494 memset (&buf
, 0, sizeof (buf
));
497 return GPG_ERR_ENOMEM
;
505 knownhost_cb (void *data
, const char *host
, const char *key
, size_t len
)
509 pwmd_strdup_printf (N_
510 ("Password Manager Daemon: %s\n\nWhile attempting an SSH connection to %s there was a problem verifying it's hostkey against the known and trusted hosts file because it's hostkey was not found.\n\nWould you like to treat this connection as trusted for this and future connections by adding %s's hostkey to the known hosts file?"),
511 (char *) data
, host
, host
);
513 if (no_pinentry
&& !isatty (STDIN_FILENO
))
515 fprintf (stderr
, N_("Input is not from a terminal! Failing.\n"));
517 return GPG_ERR_ENOTTY
;
519 else if (no_pinentry
)
521 for (char *p
= buf
, len
= 0; *p
; p
++, len
++)
530 while (!isspace (*(--p
)));
537 fprintf (stderr
, "%s\n\n", buf
);
544 fprintf (stderr
, N_("Trust this connection [y/N]: "));
546 rc
= get_password (&result
, PWMD_PINENTRY_CONFIRM
, 1);
551 if (!result
|| !*result
|| *result
== 'n' || *result
== 'N')
553 if (result
&& *result
)
556 return GPG_ERR_NOT_CONFIRMED
;
559 if ((*result
== 'y' || *result
== 'Y') && *(result
+ 1) == 0)
568 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, buf
);
574 return pwmd_getpin (pwm
, NULL
, NULL
, NULL
, PWMD_PINENTRY_CONFIRM
);
578 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
580 is_remote_url (const char *str
)
583 return PWMD_SOCKET_LOCAL
;
586 if (strstr (str
, "ssh://") || strstr (str
, "ssh4://")
587 || strstr (str
, "ssh6://"))
588 return PWMD_SOCKET_SSH
;
592 if (strstr (str
, "tls://") || strstr (str
, "tls4://")
593 || strstr (str
, "tls6://"))
594 return PWMD_SOCKET_TLS
;
597 return PWMD_SOCKET_LOCAL
;
602 escape (const char *str
)
605 char *buf
= pwmd_malloc (ASSUAN_LINELENGTH
+ 1), *b
= buf
;
608 for (p
= str
; *p
; p
++, len
++)
610 if (len
== ASSUAN_LINELENGTH
)
654 free_inquire (struct inquire_s
*inq
)
659 pwmd_free (inq
->line
);
661 if (inq
->fd
!= -1 && inq
->fd
!= STDIN_FILENO
)
667 /* When *result is not NULL it is updated to the new values and not
670 set_inquire (int fd
, const char *line
, struct inquire_s
**result
)
672 struct inquire_s inq
= { 0 };
673 struct stat st
= { 0 };
678 if (fstat (fd
, &st
) == -1)
679 return gpg_error_from_syserror ();
681 inq
.size
= st
.st_size
;
685 inq
.line
= pwmd_calloc (1, ASSUAN_LINELENGTH
);
687 return GPG_ERR_ENOMEM
;
691 char *s
= escape (line
);
695 pwmd_free (inq
.line
);
696 return GPG_ERR_ENOMEM
;
699 if (strlen (s
) >= ASSUAN_LINELENGTH
)
701 pwmd_free (inq
.line
);
703 return GPG_ERR_LINE_TOO_LONG
;
706 strncpy (inq
.line
, s
, ASSUAN_LINELENGTH
- 1);
707 inq
.len
= strlen (s
);
711 rc
= pwmd_setopt (pwm
, PWMD_OPTION_INQUIRE_TOTAL
,
712 st
.st_size
? st
.st_size
+ strlen (inq
.line
) : 0);
715 pwmd_free (inq
.line
);
720 *result
= pwmd_malloc (sizeof (struct inquire_s
));
723 if ((*result
)->fd
!= -1 && (*result
)->fd
!= STDIN_FILENO
)
724 close ((*result
)->fd
);
726 pwmd_free ((*result
)->line
);
727 (*result
)->line
= NULL
;
732 memcpy (*result
, &inq
, sizeof (struct inquire_s
));
733 memset (&inq
, 0, sizeof (struct inquire_s
));
737 #ifdef HAVE_LIBREADLINE
739 interactive_hook (void)
741 interactive_error
= process_cmd ();
743 if (interactive_error
)
744 rl_event_hook
= NULL
;
754 ("------------------------------------------------------------------------------\n"
755 "Elements are TAB delimited. Press CTRL-V then TAB to insert from the prompt.\n"
757 "Type HELP for protocol commands. Type .help for pwmc commands. Press CTRL-D\n"
759 "------------------------------------------------------------------------------\n"));
764 parse_arg (const char *src
, char *dst
, size_t len
)
770 for (; s
&& *s
&& *s
!= ' ' && n
< len
; s
++, n
++)
778 parse_opt (char **line
, const char *opt
, gpg_error_t
* rc
)
780 static char result
[ASSUAN_LINELENGTH
] = { 0 }, *r
= result
;
782 char *s
= strstr (*line
, opt
);
791 size_t rlen
= strlen (opt
);
795 while (*p
&& *p
== ' ')
801 for (; *p
&& len
< sizeof (result
) - 1; p
++, rlen
++)
803 if (isspace (*p
) && !quote
)
806 if (*p
== '\"' && lastc
!= '\\')
819 if (len
>= sizeof (result
) - 1)
820 *rc
= GPG_ERR_LINE_TOO_LONG
;
825 while (*p
&& *p
== ' ')
836 read_command (const char *line
, char **result
, size_t * len
)
840 char filebuf
[ASSUAN_LINELENGTH
];
841 char *filename
= NULL
;
842 struct inquire_s
*inq
= NULL
;
843 char *p
= (char *) line
;
844 const char *prefix
= parse_opt (&p
, "--prefix", &rc
);
853 while (*p
&& isspace (*p
))
856 filename
= parse_arg (p
, filebuf
, sizeof (filebuf
));
857 if (filename
&& *filename
)
859 p
+= strlen (filename
) + 1;
861 while (*p
&& isspace (*p
))
873 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
876 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\" = \")\n"));
880 fd
= open (filename
, O_RDONLY
);
882 return gpg_error_from_syserror ();
884 rc
= set_inquire (fd
, prefix
&& *prefix
? prefix
: NULL
, &inq
);
892 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, p
);
898 redir_command (const char *line
)
900 const char *p
= line
;
902 gpg_error_t rc
= GPG_ERR_SYNTAX
;
903 char filebuf
[ASSUAN_LINELENGTH
];
904 char *filename
= NULL
;
905 struct inquire_s
*inq
= NULL
;
911 filename
= parse_arg (p
, filebuf
, sizeof (filebuf
));
912 if (filename
&& *filename
)
914 p
+= strlen (filename
) + 1;
916 while (*p
&& isspace (*p
))
926 fprintf (stderr
, N_("Usage: .redir <filename> <command> [args]\n"));
930 fd
= open (filename
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600);
932 return gpg_error_from_syserror ();
934 #ifdef HAVE_LIBREADLINE
935 rc
= set_inquire (interactive
? STDIN_FILENO
: inquirefd
, NULL
, &inq
);
937 rc
= set_inquire (inquirefd
, NULL
, &inq
);
945 rc
= parse_dotcommand (p
, &result
, &len
, inq
);
946 if (!rc
&& result
&& len
--)
947 { // null byte which is always appended
948 if (write (fd
, result
, len
) != len
)
949 rc
= GPG_ERR_TOO_SHORT
;
959 help_command (const char *line
)
962 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
963 " .redir <filename> <command>\n"
964 " redirect the output of a command to the specified file\n"
965 "\n" " .open <filename>\n"
966 " open the specified filename losing any changes to the current one\n"
967 "\n" " .read [--prefix <string>] <filename> <command> [args]\n"
968 " obtain data from the specified filename for an inquire command\n"
969 "\n" " .set help | <name> [<value>]\n"
970 " set option <name> to <value>\n" "\n" " .help\n"
971 " this help text\n"));
976 open_command (const char *line
)
978 struct inquire_s
*inq
= NULL
;
979 const char *filename
= line
;
982 while (filename
&& isspace (*filename
))
985 if (!filename
|| !*filename
)
987 fprintf (stderr
, N_("Usage: .open <filename>\n"));
988 return GPG_ERR_SYNTAX
;
991 #ifdef HAVE_LIBREADLINE
992 if (interactive
|| !quiet
)
996 fprintf (stderr
, N_("Opening data file \"%s\" ...\n"), filename
);
998 #ifdef HAVE_LIBREADLINE
999 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1001 rc
= set_inquire (-1, NULL
, &inq
);
1007 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1009 #ifdef HAVE_LIBREADLINE
1010 // For safety. This file may be a different one. Make the user set it
1014 pwmd_free (new_keyfile
);
1019 rc
= pwmd_open (pwm
, filename
, inquire_cb
, inq
);
1025 set_command (const char *line
)
1028 char name
[256] = { 0 };
1029 char value
[512] = { 0 };
1032 const char *p
= line
;
1034 while (p
&& *p
&& isspace (*p
))
1037 namep
= parse_arg (p
, name
, sizeof (name
));
1038 if (!namep
|| !*namep
)
1040 fprintf (stderr
, N_("Usage: .set help | <name> [<value>]\n"));
1041 return GPG_ERR_SYNTAX
;
1044 p
+= strlen (namep
);
1045 while (p
&& *p
&& isspace (*p
))
1048 valuep
= parse_arg (p
, value
, sizeof (value
));
1050 if (!strcmp (name
, "keyfile") || !strcmp (name
, "new-keyfile"))
1052 int is_newkeyfile
= 1;
1056 if (!strcmp (name
, "keyfile"))
1061 pwmd_free (new_keyfile
);
1066 pwmd_free (keyfile
);
1070 p
+= strlen (valuep
);
1071 while (p
&& *p
&& isspace (*p
))
1074 valuep
= (char *) p
;
1077 memcpy (datafile
, value
, sizeof (datafile
));
1078 valuep
= parse_arg (p
, value
, sizeof (value
));
1080 pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
, "KEYGRIP %s",
1082 if (gpg_err_code (rc
) == GPG_ERR_NOT_SUPPORTED
)
1094 new_keyfile
= pwmd_strdup (value
);
1096 keyfile
= pwmd_strdup (value
);
1101 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1102 "AGENT option pinentry-mode=loopback");
1106 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 1);
1107 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1110 else if (!local_pin
&& !no_pinentry
)
1114 pwmd_socket_type (pwm
, &t
);
1115 if (t
== PWMD_SOCKET_LOCAL
)
1117 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 0);
1118 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1122 else if (!strcmp (name
, "help"))
1126 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1127 "delimited. When no value is specified the option is unset.\n\n"
1128 "keyfile <datafile> [<filename>]\n"
1129 " set or unset the keyfile to be used when a passphrase is required\n"
1130 "\n" "new-keyfile <datafile> [<filename>]\n"
1131 " set or unset the keyfile to be used when a new passphrase is required\n"));
1134 rc
= GPG_ERR_UNKNOWN_OPTION
;
1140 parse_dotcommand (const char *line
, char **result
,
1141 size_t * len
, struct inquire_s
*inq
)
1143 const char *p
= line
;
1146 if (!strncmp (p
, ".read", 5))
1147 rc
= read_command (p
+ 5, result
, len
);
1148 else if (!strncmp (p
, ".redir", 6))
1149 rc
= redir_command (p
+ 6);
1150 else if (!strncmp (p
, ".help", 5))
1151 rc
= help_command (p
+ 5);
1152 else if (!strncmp (p
, ".open", 5))
1153 rc
= open_command (p
+ 5);
1154 else if (!strncmp (p
, ".set", 4))
1155 rc
= set_command (p
+ 4);
1157 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, line
);
1162 #ifdef HAVE_LIBREADLINE
1167 struct inquire_s
*inq
= NULL
;
1170 rc
= process_cmd ();
1174 rc
= set_inquire (STDIN_FILENO
, NULL
, &inq
);
1179 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1181 rl_event_hook
= &interactive_hook
;
1182 rl_set_keyboard_input_timeout (100000);
1187 char *result
= NULL
;
1191 line
= readline ("pwm> ");
1192 if (interactive_error
)
1194 rc
= interactive_error
;
1204 if (gpg_err_code (rc
) != GPG_ERR_CANCELED
&&
1205 gpg_err_code (rc
) != GPG_ERR_EOF
)
1206 fprintf (stderr
, "ERR %i: %s\n", rc
, gpg_strerror (rc
));
1216 #ifdef HAVE_READLINE_HISTORY
1220 rc
= parse_dotcommand (line
, &result
, &len
, inq
);
1226 if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
1227 (void) pwmd_command (pwm
, &tmp
, NULL
, NULL
, NULL
,
1228 "GETINFO last_error");
1230 show_error (rc
, tmp
);
1233 else if (result
&& len
)
1234 printf ("%s%s", result
, result
[len
- 1] != '\n' ? "\n" : "");
1245 itoa (long long int n
)
1247 static char buf
[64];
1249 snprintf (buf
, sizeof (buf
), "%llu", n
);
1257 #ifdef HAVE_LIBREADLINE
1260 if (!force_save
&& interactive
)
1265 fprintf (stderr
, "\n");
1271 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1272 p
= fgets (buf
, sizeof (buf
), stdin
);
1286 return GPG_ERR_CANCELED
;
1290 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1291 "CLEARCACHE %s", filename
);
1295 interactive_hook ();
1311 if (save
&& !filename
)
1315 ("No filename was specified on the command line. Aborting.\n"));
1316 return GPG_ERR_CANCELED
;
1319 if (save
&& filename
)
1322 pwmd_strdup_printf ("%s%s %s%s %s %s%s %s%s %s --s2k-count=%lu",
1323 keygrip
? "--keygrip=" : "",
1324 keygrip
? keygrip
: "",
1325 sign_keygrip
? "--sign-keygrip=" : "",
1326 sign_keygrip
? sign_keygrip
: "",
1327 no_passphrase
? "--no-passphrase" : "",
1328 cipher
? "--cipher=" : "", cipher
? cipher
: "",
1329 iterations_arg
? "--cipher-iterations=" : "",
1330 iterations_arg
? itoa (iterations
) : "",
1331 no_gpg_agent
? "--no-agent" : "",
1334 #ifdef HAVE_LIBREADLINE
1335 if (!quiet
|| interactive
)
1341 fprintf (stderr
, "\n");
1342 fprintf (stderr
, N_("Saving changes ...\n"));
1345 rc
= pwmd_save (pwm
, args
, inquire_cb
, NULL
);
1349 no_passphrase
= 0; // reset to avoid usage error on the next SAVE
1352 #ifdef HAVE_LIBREADLINE
1354 return rc
? rc
: quit
? 0 : GPG_ERR_CANCELED
;
1361 main (int argc
, char *argv
[])
1366 char command
[ASSUAN_LINELENGTH
], *p
= NULL
;
1367 char *result
= NULL
;
1369 char *pinentry_path
= NULL
;
1370 char *display
= NULL
, *tty
= NULL
, *ttytype
= NULL
;
1371 char *lcctype
= NULL
, *lcmessages
= NULL
;
1372 int outfd
= STDOUT_FILENO
;
1373 FILE *outfp
= stdout
;
1374 FILE *inquirefp
= stdin
;
1375 int show_status
= 1;
1376 char *clientname
= "pwmc";
1377 char *inquire
= NULL
;
1378 char *inquire_line
= NULL
;
1381 int use_ssh_agent
= 1;
1382 char *knownhosts
= NULL
;
1383 char *identity
= NULL
;
1386 char *cacert
= NULL
;
1387 char *clientcert
= NULL
;
1388 char *clientkey
= NULL
;
1391 char *tls_fingerprint
= NULL
;
1393 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1394 pwmd_socket_t socktype
;
1395 long socket_timeout
= 300;
1396 int connect_timeout
= 120;
1398 int lock_on_open
= 1;
1399 long lock_timeout
= 0;
1401 /* The order is important. */
1404 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1405 OPT_SOCKET_TIMEOUT
, OPT_CONNECT_TIMEOUT
,
1408 OPT_USE_SSH_AGENT
, OPT_IDENTITY
, OPT_KNOWNHOSTS
,
1411 OPT_CACERT
, OPT_CLIENTCERT
, OPT_CLIENTKEY
, OPT_PRIORITY
, OPT_VERIFY
,
1414 OPT_URL
, OPT_LOCAL
, OPT_FORCE_SAVE
, OPT_TTYNAME
, OPT_TTYTYPE
,
1415 OPT_DISPLAY
, OPT_LC_CTYPE
, OPT_LC_MESSAGES
, OPT_TIMEOUT
, OPT_TRIES
,
1416 OPT_PINENTRY
, OPT_KEYFILE
, OPT_NEW_KEYFILE
, OPT_NOLOCK
,
1417 OPT_LOCK_TIMEOUT
, OPT_SAVE
, OPT_OUTPUT_FD
, OPT_INQUIRE
,
1418 OPT_INQUIRE_FD
, OPT_INQUIRE_FILE
, OPT_INQUIRE_LINE
, OPT_NO_STATUS
,
1419 OPT_NAME
, OPT_VERSION
, OPT_HELP
, OPT_KEYGRIP
, OPT_SIGN_KEYGRIP
,
1420 OPT_NOPASSPHRASE
, OPT_CIPHER
, OPT_KEYPARAMS
, OPT_NO_PINENTRY
,
1421 OPT_S2K_COUNT
, OPT_ITERATIONS
, OPT_QUIET
, OPT_NO_GPG_AGENT
,
1422 #ifdef HAVE_LIBREADLINE
1426 const struct option long_opts
[] = {
1427 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1428 {"socket-timeout", 1, 0, 0},
1429 {"connect-timeout", 1, 0, 0},
1433 {"no-ssh-agent", 0, 0, 0},
1434 {"identity", 1, 0, 'i'},
1435 {"knownhosts", 1, 0, 'k'},
1438 {"ca-cert", 1, 0, 0},
1439 {"client-cert", 1, 0, 0},
1440 {"client-key", 1, 0, 0},
1441 {"tls-priority", 1, 0, 0},
1442 {"tls-verify", 0, 0, 0},
1443 {"tls-fingerprint", 1, 0, 0},
1446 {"local-pinentry", 0, 0},
1447 {"force-save", 0, 0},
1448 {"ttyname", 1, 0, 'y'},
1449 {"ttytype", 1, 0, 't'},
1450 {"display", 1, 0, 'd'},
1451 {"lc-ctype", 1, 0, 0},
1452 {"lc-messages", 1, 0, 0},
1453 {"timeout", 1, 0, 0},
1455 {"pinentry", 1, 0, 0},
1456 {"key-file", 1, 0, 0},
1457 {"new-key-file", 1, 0, 0},
1458 {"no-lock", 0, 0, 0},
1459 {"lock-timeout", 1, 0, 0},
1460 {"save", 0, 0, 'S'},
1461 {"output-fd", 1, 0, 0},
1462 {"inquire", 1, 0, 0},
1463 {"inquire-fd", 1, 0, 0},
1464 {"inquire-file", 1, 0, 0},
1465 {"inquire-line", 1, 0, 'L'},
1466 {"no-status", 0, 0, 0},
1467 {"name", 1, 0, 'n'},
1468 {"version", 0, 0, 0},
1470 {"keygrip", 1, 0, 0},
1471 {"sign-keygrip", 1, 0, 0},
1472 {"no-passphrase", 0, 0, 0},
1473 {"cipher", 1, 0, 0},
1474 {"key-params", 1, 0, 0},
1475 {"no-pinentry", 0, 0, 0},
1476 {"s2k-count", 1, 0, 0},
1477 {"cipher-iterations", 1, 0, 0},
1479 {"no-gpg-agent", 0, 0, 0},
1480 #ifdef HAVE_LIBREADLINE
1481 {"interactive", 0, 0},
1486 const char *optstring
= "L:y:t:d:P:I:Sn:i:k:";
1488 const char *optstring
= "L:y:t:d:P:I:Sn:";
1493 setlocale (LC_ALL
, "");
1494 bindtextdomain ("libpwmd", LOCALEDIR
);
1497 tries
= DEFAULT_PIN_TRIES
;
1498 inquirefd
= STDIN_FILENO
;
1501 getopt_long (argc
, argv
, optstring
, long_opts
, &opt_index
)) != -1)
1505 /* Handle long options without a short option part. */
1509 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1510 case OPT_SOCKET_TIMEOUT
:
1511 socket_timeout
= strtol (optarg
, &p
, 10);
1513 case OPT_CONNECT_TIMEOUT
:
1514 connect_timeout
= strtol (optarg
, &p
, 10);
1518 case OPT_USE_SSH_AGENT
:
1526 case OPT_CLIENTCERT
:
1527 clientcert
= optarg
;
1539 tls_fingerprint
= optarg
;
1542 case OPT_NO_GPG_AGENT
:
1549 keyfile
= pwmd_strdup (optarg
);
1551 case OPT_NEW_KEYFILE
:
1552 new_keyfile
= pwmd_strdup (optarg
);
1557 case OPT_LOCK_TIMEOUT
:
1558 lock_timeout
= strtol (optarg
, &p
, 10);
1566 case OPT_FORCE_SAVE
:
1567 save
= force_save
= 1;
1570 lcctype
= pwmd_strdup (optarg
);
1572 case OPT_LC_MESSAGES
:
1573 lcmessages
= pwmd_strdup (optarg
);
1576 timeout
= strtol (optarg
, &p
, 10);
1579 tries
= strtol (optarg
, &p
, 10);
1584 case OPT_INQUIRE_FD
:
1585 inquirefd
= strtol (optarg
, &p
, 10);
1588 inquirefp
= fdopen (inquirefd
, "r");
1591 pwmd_free (password
);
1592 err (EXIT_FAILURE
, "%i", inquirefd
);
1596 case OPT_INQUIRE_FILE
:
1597 inquirefd
= open (optarg
, O_RDONLY
);
1598 if (inquirefd
== -1)
1600 pwmd_free (password
);
1601 err (EXIT_FAILURE
, "%s", optarg
);
1603 inquirefp
= fdopen (inquirefd
, "r");
1606 outfd
= strtol (optarg
, &p
, 10);
1609 outfp
= fdopen (outfd
, "w");
1612 pwmd_free (password
);
1613 err (EXIT_FAILURE
, "%i", outfd
);
1621 pwmd_free (password
);
1622 printf ("%s (pwmc)\n\n"
1623 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013\n"
1625 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1626 "Compile-time features:\n"
1627 #ifdef HAVE_LIBREADLINE
1642 #ifdef WITH_PINENTRY
1657 "\n", PACKAGE_STRING
, PACKAGE_BUGREPORT
);
1658 exit (EXIT_SUCCESS
);
1660 pinentry_path
= optarg
;
1663 usage (argv
[0], EXIT_SUCCESS
);
1667 case OPT_SIGN_KEYGRIP
:
1668 sign_keygrip
= optarg
;
1671 s2k_count
= strtoul (optarg
, &p
, 10);
1673 case OPT_ITERATIONS
:
1674 iterations
= strtoull (optarg
, &p
, 10);
1681 case OPT_NOPASSPHRASE
:
1687 case OPT_NO_PINENTRY
:
1690 #ifdef HAVE_LIBREADLINE
1691 case OPT_INTERACTIVE
:
1696 usage (argv
[0], EXIT_FAILURE
);
1701 fprintf (stderr
, N_("%s: invalid argument for option '--%s'\n"),
1702 argv
[0], long_opts
[opt_index
].name
);
1703 usage (argv
[0], EXIT_FAILURE
);
1712 knownhosts
= optarg
;
1716 inquire_line
= optarg
;
1731 clientname
= optarg
;
1734 pwmd_free (password
);
1735 usage (argv
[0], EXIT_FAILURE
);
1739 #ifdef HAVE_LIBREADLINE
1740 if (interactive
&& !isatty (STDIN_FILENO
))
1742 pwmd_free (password
);
1743 usage (argv
[0], EXIT_FAILURE
);
1745 else if (isatty (STDIN_FILENO
) && !inquire
&& !inquire_line
)
1749 filename
= argv
[optind
];
1751 gnutls_global_set_mem_functions (pwmd_malloc
, pwmd_malloc
, NULL
,
1752 pwmd_realloc
, pwmd_free
);
1755 rc
= pwmd_new (clientname
, &pwm
);
1759 pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TRIES
, tries
);
1761 fprintf (stderr
, N_("Connecting ...\n"));
1763 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1764 socktype
= is_remote_url (url
);
1765 if (socktype
!= PWMD_SOCKET_LOCAL
)
1768 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1769 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, connect_timeout
);
1774 if (socktype
== PWMD_SOCKET_SSH
)
1777 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_CB
, knownhost_cb
);
1781 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_DATA
, clientname
);
1785 if (!getenv ("SSH_AUTH_SOCK") || identity
)
1788 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_AGENT
, use_ssh_agent
);
1792 rc
= pwmd_connect (pwm
, url
, identity
, knownhosts
);
1798 rc
= pwmd_setopt (pwm
, PWMD_OPTION_TLS_VERIFY
, tls_verify
);
1802 rc
= pwmd_connect (pwm
, url
, clientcert
, clientkey
, cacert
, prio
,
1808 rc
= pwmd_connect (pwm
, url
);
1810 rc
= pwmd_connect (pwm
, url
);
1816 fprintf (stderr
, N_("Connected.\n"));
1819 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1820 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, socket_timeout
);
1827 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1828 "OPTION LOCK-TIMEOUT=%li", lock_timeout
);
1835 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCK_ON_OPEN
, 1);
1840 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, NULL
);
1846 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, timeout
);
1851 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
1855 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
,
1856 (local_pin
|| keyfile
|| new_keyfile
));
1862 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_PATH
, pinentry_path
);
1869 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DISPLAY
, display
);
1876 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TTY
, tty
);
1883 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TERM
, ttytype
);
1890 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_CTYPE
, lcctype
);
1897 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_MESSAGES
, lcmessages
);
1904 rc
= pwmd_setopt (pwm
, PWMD_OPTION_STATUS_CB
, status_msg_cb
);
1911 rc
= open_command (filename
);
1916 #ifdef HAVE_LIBREADLINE
1922 rc
= do_interactive ();
1930 struct inquire_s
*inq
= NULL
;
1932 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
1934 rc
= pwmd_command (pwm
, &result
, &len
, inquire_cb
, inq
, inquire
);
1940 fcntl (STDIN_FILENO
, F_SETFL
, O_NONBLOCK
);
1945 rc
= process_cmd ();
1950 n
= read (STDIN_FILENO
, command
, sizeof (command
));
1953 if (errno
== EAGAIN
)
1959 rc
= gpg_error_from_errno (errno
);
1970 if (!p
|| !*p
|| !strcasecmp (p
, "BYE"))
1974 struct inquire_s
*inq
= NULL
;
1975 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
1978 rc
= parse_dotcommand (command
, &result
, &len
, inq
);
1988 fwrite (result
, 1, result
[len
- 1] == 0 ? len
- 1 : len
, outfp
);
1993 pwmd_free (password
);
1994 password
= result
= NULL
;
1997 else if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
1998 (void) pwmd_command (pwm
, &result
, NULL
, NULL
, NULL
,
1999 "GETINFO last_error");
2001 #ifdef HAVE_LIBREADLINE
2004 memset (command
, 0, sizeof (command
));
2006 pwmd_free (keyfile
);
2007 pwmd_free (new_keyfile
);
2011 show_error (rc
, result
);
2014 if (connected
&& !quiet
)
2015 fprintf (stderr
, N_("Connection closed.\n"));
2017 exit (rc
? EXIT_FAILURE
: EXIT_SUCCESS
);