2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014
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>
43 #include <gnutls/gnutls.h>
50 #ifdef HAVE_GETOPT_LONG
55 #include "getopt_long.h"
58 #ifdef HAVE_LIBREADLINE
59 #if defined(HAVE_READLINE_READLINE_H)
60 #include <readline/readline.h>
61 #elif defined(HAVE_READLINE_H)
63 #endif /* !defined(HAVE_READLINE_H) */
64 static int interactive_error
;
65 static int interactive
;
66 #endif /* HAVE_LIBREADLINE */
68 #ifdef HAVE_READLINE_HISTORY
69 #if defined(HAVE_READLINE_HISTORY_H)
70 #include <readline/history.h>
71 #elif defined(HAVE_HISTORY_H)
74 #endif /* HAVE_READLINE_HISTORY */
81 #define N_(msgid) gettext(msgid)
85 #define DEFAULT_PIN_TIMEOUT 30
86 #define DEFAULT_PIN_TRIES 3
87 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
90 static int no_pinentry
;
92 static char *filename
;
95 static char *sign_keyid
;
96 static char *keyparams
;
98 static char *new_keyfile
;
100 static int local_pin
;
101 static int inquirefd
;
111 size_t size
; // from stat(2).
115 static gpg_error_t
finalize ();
116 static gpg_error_t
set_inquire (int fd
, const char *line
,
117 struct inquire_s
**result
);
118 static gpg_error_t
parse_dotcommand (const char *line
, char **result
,
119 size_t * len
, struct inquire_s
*inq
);
120 static gpg_error_t
open_command (const char *line
);
122 static gpg_error_t
get_password (char **result
, pwmd_pinentry_t w
, int echo
);
126 show_error (pwm_t
*pwm
, gpg_error_t rc
, const char *str
)
129 if (pwmd_tls_error (pwm
))
130 fprintf(stderr
, "TLS: %s\n", gnutls_strerror(pwmd_tls_error(pwm
)));
132 fprintf (stderr
, "ERR %i: %s%s%s%s", rc
, gpg_strerror (rc
),
133 str
? ": " : "", str
? str
: "", str
? "" : "\n");
137 usage (const char *pn
, int status
)
139 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
140 N_("Usage: pwmc [options] [file]\n"
142 " a url string to connect to (%s, see below)\n"
143 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
144 " --connect-timeout <seconds>\n"
145 " seconds before connecting to a remote host fails (0=disabled, 120)\n"
146 " --socket-timeout <seconds>\n"
147 " seconds before a remote command fails (0=disabled, 300)\n"
150 " --ca-cert <filename>\n"
151 " certificate authority (CA) used to sign the server cert\n"
152 " --client-cert <filename>\n"
153 " client certificate to use for authentication\n"
154 " --client-key <filename>\n"
155 " key file used to protect the client certificate\n"
156 " --tls-priority <string>\n"
157 " compression, cipher and hash algorithm string (SECURE256)\n"
159 " verify the hostname against the server certificate\n"
160 " --tls-fingerprint <string>\n"
161 " a SHA-256 hash of the server fingerprint to verify against\n"
165 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
166 " --identity, -i <filename>\n"
167 " the ssh identity file to use for authentication\n"
168 " --knownhosts, -k <filename>\n"
169 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
172 " do not lock the data file upon opening it\n"
173 " --lock-timeout <N>\n"
174 " time in tenths of a second to wait for a locked data file (50)\n"
175 " --name, -n <string>\n"
176 " set the client name\n"
177 " --pinentry <path>\n"
178 " the full path to the pinentry binary\n"
179 " --local-pinentry\n"
180 " force using a local pinentry\n"
182 " disable pinentry both remotely and locally\n"
183 " --ttyname, -y <path>\n"
184 " tty that pinentry will use\n"
185 " --ttytype, -t <string>\n"
186 " pinentry terminal type (default is $TERM)\n"
188 " pinentry display (default is $DISPLAY)\n"
189 " --lc-ctype <string>\n"
190 " locale setting for pinentry\n"
191 " --lc-messages <string>\n"
192 " locale setting for pinentry\n"
194 " number of pinentry tries before failing (3)\n"
195 " --timeout <seconds>\n"
196 " pinentry timeout\n"
197 " --inquire <COMMAND>\n"
198 " the specified command (with any options) uses a server inquire while\n"
199 " command data is read via the inquire file descriptor (stdin)\n"
200 " --inquire-line, -L <STRING>\n"
201 " the initial line to send (i.e., element path) before the inquire data\n"
202 " --inquire-fd <FD>\n"
203 " read inquire data from the specified file descriptor (stdin)\n"
204 " --inquire-file <filename>\n"
205 " read inquire data from the specified filename\n"
206 " --output-fd <FD>\n"
207 " redirect command output to the specified file descriptor\n"
209 " send the SAVE command before exiting\n"
210 " --key-file <filename>\n"
211 " obtain the passphrase from the specified filename\n"
212 " --new-key-file <filename>\n"
213 " obtain the passphrase to save with from the specified filename\n"
214 " --key-params <string>\n"
215 " the key parameters to use when saving a new file (pwmd default)\n"
216 " --keyid <recipient>[,<recipient>]\n"
217 " the public key ID to u\n"
218 " --sign-keyid <string>\n"
219 " the key ID to sign the data file with\n"
221 " disable showing of status messages from the server\n"
223 " disable showing of extra messages (implies --no-status)\n"
224 " --status-fd <FD>\n"
225 " redirect status messages to the specified file descriptor\n"
226 #ifdef HAVE_LIBREADLINE
228 " use a shell like interface to pwmd (allows more than one command)\n"
232 #ifdef DEFAULT_PWMD_SOCKET
238 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
240 "An optional url may be in the form of:\n"
241 " --url /path/to/socket\n"
242 " --url file://[path/to/socket]\n"
245 " --url ssh[46]://[username@]hostname[:port]\n"
246 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
250 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
251 " --client-key filename\n"
253 #ifdef HAVE_LIBREADLINE
255 "Interactive mode is used when input is from a terminal.\n"
262 inquire_cb (void *user
, const char *keyword
, gpg_error_t rc
,
263 char **data
, size_t * size
)
265 struct inquire_s
*inq
= user
;
267 int is_newpassword
= 0;
275 if (!strcmp (keyword
, "PASSPHRASE"))
277 else if (!strcmp (keyword
, "NEW_PASSPHRASE"))
279 #ifdef HAVE_LIBREADLINE
280 else if (!strcmp (keyword
, "KEYPARAM") && !interactive
)
283 else if (!strcmp (keyword
, "KEYPARAM"))
286 if (!keyparams
|| !*keyparams
)
287 return gpg_error (GPG_ERR_INV_PARAMETER
);
290 *size
= strlen (keyparams
);
291 return gpg_error (GPG_ERR_EOF
);
294 if ((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
))
296 int fd
= open (is_password
? keyfile
: new_keyfile
, O_RDONLY
);
300 fprintf (stderr
, "%s: %s\n", is_newpassword
? new_keyfile
: keyfile
,
302 return gpg_error_from_syserror ();
305 rc
= set_inquire (fd
, NULL
, &inq
);
313 fprintf (stderr
, N_("Using keyfile '%s' as %s.\n"),
314 is_newpassword
? new_keyfile
: keyfile
, keyword
);
316 if (!new_keyfile
|| is_newpassword
)
320 pwmd_socket_type (pwm
, &t
);
321 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
322 if (!no_pinentry
&& t
== PWMD_SOCKET_LOCAL
)
323 pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 0);
326 else if ((is_password
&& !keyfile
) || (is_newpassword
&& !new_keyfile
))
330 rc
= pwmd_password (pwm
, keyword
, &tmp
, &inq
->len
);
331 if (rc
&& gpg_err_code (rc
) != GPG_ERR_EOF
)
334 pwmd_free (inq
->line
);
338 return gpg_error (GPG_ERR_EOF
);
340 #ifdef HAVE_LIBREADLINE
341 else if ((!inq
->last_keyword
|| strcmp (keyword
, inq
->last_keyword
))
346 ("%sPress CTRL-D to send the current line. Press twice to end. %s:\n"),
347 inq
->last_keyword
? "\n" : "", keyword
);
348 pwmd_free (inq
->last_keyword
);
349 inq
->last_keyword
= pwmd_strdup (keyword
);
353 /* The first part of the command data. */
359 return inq
->fd
== -1 ? gpg_error (GPG_ERR_EOF
) : 0;
362 *size
= read (inq
->fd
, inq
->line
, ASSUAN_LINELENGTH
);
366 return gpg_error (gpg_error_from_syserror ());
370 else if (inq
->fd
!= STDIN_FILENO
&& (is_newpassword
|| is_password
))
378 if (((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
))
379 && *size
== inq
->size
)
380 return gpg_error (GPG_ERR_EOF
);
382 return *size
? 0 : gpg_error (GPG_ERR_EOF
);
386 status_msg_cb (void *data
, const char *line
)
388 char *p
= strchr (line
, ' ');
390 if (!strcmp (line
, "KEEPALIVE"))
392 else if (!strncmp (line
, "GPGME", 5))
394 else if (!strncmp (line
, "PASSPHRASE_HINT", 15))
396 else if (!strncmp (line
, "PASSPHRASE_INFO", 15))
398 else if (!strncmp (line
, "STATE", 5))
401 if (statusfd
!= STDERR_FILENO
&& *line
!= '#'
402 && p
&& strchr (p
, ' ') && *++p
)
404 char *p1
= strchr (p
, ' ');
405 int a
= strtol (p
, NULL
, 10);
407 if (isdigit (*p
) && p1
)
409 int b
= strtol (p1
, NULL
, 10);
411 int t
= a
&& b
? a
* 100 / b
: 0;
413 strncpy (l
, line
, strlen (line
) - strlen (p
) - 1);
414 fprintf (statusfp
, "\r%s %i/%i %i%%%s", l
, a
, b
, t
,
421 fprintf (statusfp
, "%s\n", line
);
423 #ifdef HAVE_LIBREADLINE
432 return pwmd_process (pwm
);
437 get_password (char **result
, pwmd_pinentry_t w
, int echo
)
439 char buf
[LINE_MAX
] = { 0 }, *p
;
440 struct termios told
, tnew
;
445 if (!isatty (STDIN_FILENO
))
447 fprintf (stderr
, N_("Input is not from a terminal! Failing.\n"));
448 return GPG_ERR_ENOTTY
;
453 if (tcgetattr (STDIN_FILENO
, &told
) == -1)
454 return gpg_error_from_syserror ();
456 memcpy (&tnew
, &told
, sizeof (struct termios
));
457 tnew
.c_lflag
&= ~(ECHO
);
458 tnew
.c_lflag
|= ICANON
| ECHONL
;
460 if (tcsetattr (STDIN_FILENO
, TCSANOW
, &tnew
) == -1)
464 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
465 return gpg_error_from_errno (n
);
471 case PWMD_PINENTRY_OPEN
:
472 fprintf (stderr
, N_("Password for %s: "), filename
);
474 case PWMD_PINENTRY_OPEN_FAILED
:
475 fprintf (stderr
, N_("Invalid password. Password for %s: "), filename
);
477 case PWMD_PINENTRY_SAVE
:
478 fprintf (stderr
, N_("New password for %s: "), filename
);
480 case PWMD_PINENTRY_SAVE_CONFIRM
:
481 fprintf (stderr
, N_("Confirm password: "));
487 if ((p
= fgets (buf
, sizeof (buf
), stdin
)) == NULL
)
489 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
494 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
499 return GPG_ERR_CANCELED
;
502 p
[strlen (p
) - 1] = 0;
506 key
= pwmd_strdup_printf ("%s", p
);
507 memset (&buf
, 0, sizeof (buf
));
510 return GPG_ERR_ENOMEM
;
518 knownhost_cb (void *data
, const char *host
, const char *key
, size_t len
)
522 pwmd_strdup_printf (N_
523 ("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?"),
524 (char *) data
, host
, host
);
526 if (no_pinentry
&& !isatty (STDIN_FILENO
))
528 fprintf (stderr
, N_("Input is not from a terminal! Failing.\n"));
530 return GPG_ERR_ENOTTY
;
532 else if (no_pinentry
)
534 for (char *p
= buf
, len
= 0; *p
; p
++, len
++)
543 while (!isspace (*(--p
)));
550 fprintf (stderr
, "%s\n\n", buf
);
557 fprintf (stderr
, N_("Trust this connection [y/N]: "));
559 rc
= get_password (&result
, PWMD_PINENTRY_CONFIRM
, 1);
564 if (!result
|| !*result
|| *result
== 'n' || *result
== 'N')
566 if (result
&& *result
)
569 return GPG_ERR_NOT_CONFIRMED
;
572 if ((*result
== 'y' || *result
== 'Y') && *(result
+ 1) == 0)
581 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, buf
);
587 return pwmd_getpin (pwm
, NULL
, NULL
, NULL
, PWMD_PINENTRY_CONFIRM
);
591 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
593 is_remote_url (const char *str
)
596 return PWMD_SOCKET_LOCAL
;
599 if (strstr (str
, "ssh://") || strstr (str
, "ssh4://")
600 || strstr (str
, "ssh6://"))
601 return PWMD_SOCKET_SSH
;
605 if (strstr (str
, "tls://") || strstr (str
, "tls4://")
606 || strstr (str
, "tls6://"))
607 return PWMD_SOCKET_TLS
;
610 return PWMD_SOCKET_LOCAL
;
615 escape (const char *str
)
618 char *buf
= pwmd_malloc (ASSUAN_LINELENGTH
+ 1), *b
= buf
;
621 for (p
= str
; *p
; p
++, len
++)
623 if (len
== ASSUAN_LINELENGTH
)
667 free_inquire (struct inquire_s
*inq
)
672 pwmd_free (inq
->line
);
674 if (inq
->fd
!= -1 && inq
->fd
!= STDIN_FILENO
)
677 pwmd_free (inq
->last_keyword
);
681 /* When *result is not NULL it is updated to the new values and not
684 set_inquire (int fd
, const char *line
, struct inquire_s
**result
)
686 struct inquire_s inq
= { 0 };
687 struct stat st
= { 0 };
692 if (fstat (fd
, &st
) == -1)
693 return gpg_error_from_syserror ();
695 inq
.size
= st
.st_size
;
699 inq
.line
= pwmd_calloc (1, ASSUAN_LINELENGTH
);
701 return GPG_ERR_ENOMEM
;
705 char *s
= escape (line
);
709 pwmd_free (inq
.line
);
710 return GPG_ERR_ENOMEM
;
713 if (strlen (s
) >= ASSUAN_LINELENGTH
)
715 pwmd_free (inq
.line
);
717 return GPG_ERR_LINE_TOO_LONG
;
720 strncpy (inq
.line
, s
, ASSUAN_LINELENGTH
- 1);
721 inq
.len
= strlen (s
);
725 rc
= pwmd_setopt (pwm
, PWMD_OPTION_INQUIRE_TOTAL
,
726 st
.st_size
? st
.st_size
+ strlen (inq
.line
) : 0);
729 pwmd_free (inq
.line
);
734 *result
= pwmd_malloc (sizeof (struct inquire_s
));
737 if ((*result
)->fd
!= -1 && (*result
)->fd
!= STDIN_FILENO
)
738 close ((*result
)->fd
);
740 pwmd_free ((*result
)->line
);
741 (*result
)->line
= NULL
;
746 memcpy (*result
, &inq
, sizeof (struct inquire_s
));
747 memset (&inq
, 0, sizeof (struct inquire_s
));
751 #ifdef HAVE_LIBREADLINE
753 interactive_hook (void)
755 interactive_error
= process_cmd ();
757 if (interactive_error
)
758 rl_event_hook
= NULL
;
768 ("------------------------------------------------------------------------------\n"
769 "Elements are TAB delimited. Press CTRL-V then TAB to insert from the prompt.\n"
771 "Type HELP for protocol commands. Type .help for pwmc commands. Press CTRL-D\n"
773 "------------------------------------------------------------------------------\n"));
778 parse_arg (const char *src
, char *dst
, size_t len
)
784 for (; s
&& *s
&& *s
!= ' ' && n
< len
; s
++, n
++)
792 parse_opt (char **line
, const char *opt
, gpg_error_t
* rc
)
794 static char result
[ASSUAN_LINELENGTH
] = { 0 }, *r
= result
;
795 char *s
= strstr (*line
, opt
);
805 size_t rlen
= strlen (opt
);
809 while (*p
&& *p
== ' ')
815 for (; *p
&& len
< sizeof (result
) - 1; p
++, rlen
++)
817 if (isspace (*p
) && !quote
)
820 if (*p
== '\"' && lastc
!= '\\')
833 if (len
>= sizeof (result
) - 1)
834 *rc
= GPG_ERR_LINE_TOO_LONG
;
839 while (*p
&& *p
== ' ')
850 read_command (const char *line
, char **result
, size_t * len
)
854 char *filename
= NULL
;
855 struct inquire_s
*inq
= NULL
;
856 char *p
= (char *) line
;
857 const char *prefix
= parse_opt (&p
, "--prefix", &rc
);
866 char filebuf
[ASSUAN_LINELENGTH
];
868 while (*p
&& isspace (*p
))
871 filename
= parse_arg (p
, filebuf
, sizeof (filebuf
));
872 if (filename
&& *filename
)
874 p
+= strlen (filename
) + 1;
876 while (*p
&& isspace (*p
))
888 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
891 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\" = \")\n"));
895 fd
= open (filename
, O_RDONLY
);
897 return gpg_error_from_syserror ();
899 rc
= set_inquire (fd
, prefix
&& *prefix
? prefix
: NULL
, &inq
);
906 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, p
);
912 redir_command (const char *line
)
914 const char *p
= line
;
916 gpg_error_t rc
= GPG_ERR_SYNTAX
;
917 char *filename
= NULL
;
918 struct inquire_s
*inq
= NULL
;
924 char filebuf
[ASSUAN_LINELENGTH
];
926 filename
= parse_arg (p
, filebuf
, sizeof (filebuf
));
927 if (filename
&& *filename
)
929 p
+= strlen (filename
) + 1;
931 while (*p
&& isspace (*p
))
941 fprintf (stderr
, N_("Usage: .redir <filename> <command> [args]\n"));
945 fd
= open (filename
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600);
947 return gpg_error_from_syserror ();
949 #ifdef HAVE_LIBREADLINE
950 rc
= set_inquire (interactive
? STDIN_FILENO
: inquirefd
, NULL
, &inq
);
952 rc
= set_inquire (inquirefd
, NULL
, &inq
);
960 rc
= parse_dotcommand (p
, &result
, &len
, inq
);
961 if (!rc
&& result
&& len
--)
962 { // null byte which is always appended
963 if (write (fd
, result
, len
) != len
)
964 rc
= GPG_ERR_TOO_SHORT
;
974 help_command (const char *line
)
977 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
978 " .redir <filename> <command>\n"
979 " redirect the output of a command to the specified file\n"
981 " .open <filename>\n"
982 " open the specified filename losing any changes to the current one\n"
984 " .read [--prefix <string>] <filename> <command> [args]\n"
985 " obtain data from the specified filename for an inquire command\n"
987 " .set help | <name> [<value>]\n"
988 " set option <name> to <value>\n"
991 " write changes of the file to disk\n"
994 " change the passphrase of a data file\n"
997 " this help text\n"));
1002 open_command (const char *line
)
1004 struct inquire_s
*inq
= NULL
;
1005 const char *filename
= line
;
1008 while (filename
&& isspace (*filename
))
1011 if (!filename
|| !*filename
)
1013 fprintf (stderr
, N_("Usage: .open <filename>\n"));
1014 return GPG_ERR_SYNTAX
;
1017 #ifdef HAVE_LIBREADLINE
1018 if (interactive
|| !quiet
)
1022 fprintf (stderr
, N_("Opening data file \"%s\" ...\n"), filename
);
1024 #ifdef HAVE_LIBREADLINE
1025 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1027 rc
= set_inquire (-1, NULL
, &inq
);
1033 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1035 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1037 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
1038 rc
= pwmd_open (pwm
, filename
, inquire_cb
, inq
);
1044 set_command (const char *line
)
1047 char name
[256] = { 0 };
1048 char value
[512] = { 0 };
1051 const char *p
= line
;
1053 while (p
&& *p
&& isspace (*p
))
1056 namep
= parse_arg (p
, name
, sizeof (name
));
1057 if (!namep
|| !*namep
)
1059 fprintf (stderr
, N_("Usage: .set help | <name> [<value>]\n"));
1060 return GPG_ERR_SYNTAX
;
1063 p
+= strlen (namep
);
1064 while (p
&& *p
&& isspace (*p
))
1067 valuep
= parse_arg (p
, value
, sizeof (value
));
1069 if (!strcmp (name
, "keyfile") || !strcmp (name
, "new-keyfile"))
1071 int is_newkeyfile
= 1;
1073 if (!strcmp (name
, "keyfile"))
1078 pwmd_free (new_keyfile
);
1083 pwmd_free (keyfile
);
1087 p
+= strlen (valuep
);
1088 while (p
&& *p
&& isspace (*p
))
1091 valuep
= (char *) p
;
1095 new_keyfile
= pwmd_strdup (value
);
1097 keyfile
= pwmd_strdup (value
);
1101 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 1);
1103 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1106 else if (!local_pin
&& !no_pinentry
)
1110 pwmd_socket_type (pwm
, &t
);
1111 if (t
== PWMD_SOCKET_LOCAL
)
1113 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 0);
1115 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1119 else if (!strcmp(name
, "pinentry-timeout"))
1122 int n
= strtol(valuep
, &e
, 10);
1125 return gpg_error (GPG_ERR_INV_VALUE
);
1127 if (!valuep
|| !*valuep
)
1128 n
= DEFAULT_PIN_TIMEOUT
;
1130 rc
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, n
);
1132 else if (!strcmp (name
, "help"))
1136 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1137 "delimited. When no value is specified the option is unset.\n\n"
1138 "keyfile <datafile> [<filename>]\n"
1139 " set or unset the keyfile to be used when a passphrase is required (*)\n"
1141 "new-keyfile <datafile> [<filename>]\n"
1142 " set or unset the keyfile to be used when a new passphrase is required (*)\n"
1144 "pinentry-timeout <seconds>\n"
1145 " the amount of seconds before pinentry gives up waiting for input\n"
1147 "* = the next protocol command will unset this value\n"
1151 rc
= GPG_ERR_UNKNOWN_OPTION
;
1157 save_command (const char *line
)
1159 struct inquire_s
*inq
= NULL
;
1162 #ifdef HAVE_LIBREADLINE
1163 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1165 rc
= set_inquire (-1, NULL
, &inq
);
1170 if (new_keyfile
|| keyfile
)
1171 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1173 rc
= pwmd_save (pwm
, line
, inquire_cb
, inq
);
1174 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1180 do_save_passwd_command (const char *line
, int save
)
1182 struct inquire_s
*inq
= NULL
;
1185 #ifdef HAVE_LIBREADLINE
1186 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1188 rc
= set_inquire (-1, NULL
, &inq
);
1193 if (new_keyfile
|| keyfile
)
1194 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1197 rc
= pwmd_save (pwm
, line
, inquire_cb
, inq
);
1199 rc
= pwmd_passwd (pwm
, line
, inquire_cb
, inq
);
1201 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1207 parse_dotcommand (const char *line
, char **result
,
1208 size_t * len
, struct inquire_s
*inq
)
1210 const char *p
= line
;
1213 if (!strncmp (p
, ".read", 5))
1214 rc
= read_command (p
+ 5, result
, len
);
1215 else if (!strncmp (p
, ".redir", 6))
1216 rc
= redir_command (p
+ 6);
1217 else if (!strncmp (p
, ".help", 5))
1218 rc
= help_command (p
+ 5);
1219 else if (!strncmp (p
, ".open", 5))
1220 rc
= open_command (p
+ 5);
1221 else if (!strncmp (p
, ".set", 4))
1222 rc
= set_command (p
+ 4);
1223 else if (!strncmp (p
, ".save", 5))
1224 rc
= do_save_passwd_command (p
+ 5, 1);
1225 else if (!strncmp (p
, ".passwd", 7))
1226 rc
= do_save_passwd_command (p
+ 7, 0);
1229 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, line
);
1230 #ifdef HAVE_LIBREADLINE
1234 pwmd_free (keyfile
);
1235 pwmd_free (new_keyfile
);
1236 keyfile
= new_keyfile
= NULL
;
1237 #ifdef HAVE_LIBREADLINE
1245 #ifdef HAVE_LIBREADLINE
1250 struct inquire_s
*inq
= NULL
;
1253 rc
= process_cmd ();
1257 rc
= set_inquire (STDIN_FILENO
, NULL
, &inq
);
1262 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1264 rl_event_hook
= &interactive_hook
;
1265 rl_set_keyboard_input_timeout (100000);
1270 char *result
= NULL
;
1274 line
= readline ("pwm> ");
1275 if (interactive_error
)
1278 rc
= interactive_error
;
1288 if (gpg_err_code (rc
) != GPG_ERR_CANCELED
&&
1289 gpg_err_code (rc
) != GPG_ERR_EOF
)
1290 fprintf (stderr
, "ERR %i: %s\n", rc
, gpg_strerror (rc
));
1300 #ifdef HAVE_READLINE_HISTORY
1303 rc
= parse_dotcommand (line
, &result
, &len
, inq
);
1309 if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
1310 (void) pwmd_command (pwm
, &tmp
, NULL
, NULL
, NULL
,
1311 "GETINFO last_error");
1313 show_error (pwm
, rc
, tmp
);
1316 else if (result
&& len
)
1317 printf ("%s%s", result
, result
[len
- 1] != '\n' ? "\n" : "");
1331 #ifdef HAVE_LIBREADLINE
1338 fprintf (stderr
, "\n");
1346 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1347 p
= fgets (buf
, sizeof (buf
), stdin
);
1361 return GPG_ERR_CANCELED
;
1365 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1366 "CLEARCACHE %s", filename
);
1370 interactive_hook ();
1386 if (save
&& !filename
)
1390 ("No filename was specified on the command line. Aborting.\n"));
1391 return GPG_ERR_CANCELED
;
1394 if (save
&& filename
)
1397 pwmd_strdup_printf ("%s%s %s%s %s",
1398 keyid
? "--keyid=" : "",
1400 sign_keyid
? "--sign-keyid=" : "",
1401 sign_keyid
? sign_keyid
: "",
1402 keyparams
? "--inquire-keyparam" : "");
1404 #ifdef HAVE_LIBREADLINE
1405 if (!quiet
|| interactive
)
1411 fprintf (stderr
, "\n");
1412 fprintf (stderr
, N_("Saving changes ...\n"));
1415 rc
= save_command (args
);
1419 #ifdef HAVE_LIBREADLINE
1421 return rc
? rc
: quit
? 0 : GPG_ERR_CANCELED
;
1428 main (int argc
, char *argv
[])
1433 char command
[ASSUAN_LINELENGTH
], *p
= NULL
;
1434 char *result
= NULL
;
1436 char *pinentry_path
= NULL
;
1437 char *display
= NULL
, *tty
= NULL
, *ttytype
= NULL
;
1438 char *lcctype
= NULL
, *lcmessages
= NULL
;
1439 int outfd
= STDOUT_FILENO
;
1440 FILE *outfp
= stdout
;
1441 FILE *inquirefp
= stdin
;
1442 int show_status
= 1;
1443 char *clientname
= "pwmc";
1444 char *inquire
= NULL
;
1445 char *inquire_line
= NULL
;
1448 int use_ssh_agent
= 1;
1449 char *knownhosts
= NULL
;
1450 char *identity
= NULL
;
1453 char *cacert
= NULL
;
1454 char *clientcert
= NULL
;
1455 char *clientkey
= NULL
;
1458 char *tls_fingerprint
= NULL
;
1460 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1461 pwmd_socket_t socktype
;
1462 long socket_timeout
= 300;
1463 int connect_timeout
= 120;
1465 int lock_on_open
= 1;
1466 long lock_timeout
= 50;
1468 /* The order is important. */
1471 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1472 OPT_SOCKET_TIMEOUT
, OPT_CONNECT_TIMEOUT
,
1475 OPT_USE_SSH_AGENT
, OPT_IDENTITY
, OPT_KNOWNHOSTS
,
1478 OPT_CACERT
, OPT_CLIENTCERT
, OPT_CLIENTKEY
, OPT_PRIORITY
, OPT_VERIFY
,
1481 OPT_URL
, OPT_LOCAL
, OPT_TTYNAME
, OPT_TTYTYPE
,
1482 OPT_DISPLAY
, OPT_LC_CTYPE
, OPT_LC_MESSAGES
, OPT_TIMEOUT
, OPT_TRIES
,
1483 OPT_PINENTRY
, OPT_KEYFILE
, OPT_NEW_KEYFILE
, OPT_NOLOCK
,
1484 OPT_LOCK_TIMEOUT
, OPT_SAVE
, OPT_OUTPUT_FD
, OPT_INQUIRE
,
1485 OPT_INQUIRE_FD
, OPT_INQUIRE_FILE
, OPT_INQUIRE_LINE
, OPT_NO_STATUS
,
1486 OPT_statusfd
, OPT_NAME
, OPT_VERSION
, OPT_HELP
, OPT_KEYID
, OPT_SIGN_KEYID
,
1487 OPT_KEYPARAMS
, OPT_NO_PINENTRY
, OPT_QUIET
,
1488 #ifdef HAVE_LIBREADLINE
1492 const struct option long_opts
[] = {
1493 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1494 {"socket-timeout", 1, 0, 0},
1495 {"connect-timeout", 1, 0, 0},
1499 {"no-ssh-agent", 0, 0, 0},
1500 {"identity", 1, 0, 'i'},
1501 {"knownhosts", 1, 0, 'k'},
1504 {"ca-cert", 1, 0, 0},
1505 {"client-cert", 1, 0, 0},
1506 {"client-key", 1, 0, 0},
1507 {"tls-priority", 1, 0, 0},
1508 {"tls-verify", 0, 0, 0},
1509 {"tls-fingerprint", 1, 0, 0},
1512 {"local-pinentry", 0, 0},
1513 {"ttyname", 1, 0, 'y'},
1514 {"ttytype", 1, 0, 't'},
1515 {"display", 1, 0, 'd'},
1516 {"lc-ctype", 1, 0, 0},
1517 {"lc-messages", 1, 0, 0},
1518 {"timeout", 1, 0, 0},
1520 {"pinentry", 1, 0, 0},
1521 {"key-file", 1, 0, 0},
1522 {"new-key-file", 1, 0, 0},
1523 {"no-lock", 0, 0, 0},
1524 {"lock-timeout", 1, 0, 0},
1525 {"save", 0, 0, 'S'},
1526 {"output-fd", 1, 0, 0},
1527 {"inquire", 1, 0, 0},
1528 {"inquire-fd", 1, 0, 0},
1529 {"inquire-file", 1, 0, 0},
1530 {"inquire-line", 1, 0, 'L'},
1531 {"no-status", 0, 0, 0},
1532 {"status-fd", 1, 0, 0},
1533 {"name", 1, 0, 'n'},
1534 {"version", 0, 0, 0},
1537 {"sign-keyid", 1, 0, 0},
1538 {"key-params", 1, 0, 0},
1539 {"no-pinentry", 0, 0, 0},
1541 #ifdef HAVE_LIBREADLINE
1542 {"interactive", 0, 0},
1547 const char *optstring
= "L:y:t:d:P:I:Sn:i:k:";
1549 const char *optstring
= "L:y:t:d:P:I:Sn:";
1554 setlocale (LC_ALL
, "");
1555 bindtextdomain ("libpwmd", LOCALEDIR
);
1558 tries
= DEFAULT_PIN_TRIES
;
1559 inquirefd
= STDIN_FILENO
;
1560 statusfd
= STDERR_FILENO
;
1561 statusfp
= fdopen (statusfd
, "w");
1564 getopt_long (argc
, argv
, optstring
, long_opts
, &opt_index
)) != -1)
1568 /* Handle long options without a short option part. */
1572 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1573 case OPT_SOCKET_TIMEOUT
:
1574 socket_timeout
= strtol (optarg
, &p
, 10);
1576 case OPT_CONNECT_TIMEOUT
:
1577 connect_timeout
= strtol (optarg
, &p
, 10);
1581 case OPT_USE_SSH_AGENT
:
1589 case OPT_CLIENTCERT
:
1590 clientcert
= optarg
;
1602 tls_fingerprint
= optarg
;
1609 keyfile
= pwmd_strdup (optarg
);
1611 case OPT_NEW_KEYFILE
:
1612 new_keyfile
= pwmd_strdup (optarg
);
1617 case OPT_LOCK_TIMEOUT
:
1618 lock_timeout
= strtol (optarg
, &p
, 10);
1627 lcctype
= pwmd_strdup (optarg
);
1629 case OPT_LC_MESSAGES
:
1630 lcmessages
= pwmd_strdup (optarg
);
1633 timeout
= strtol (optarg
, &p
, 10);
1636 tries
= strtol (optarg
, &p
, 10);
1639 inquire
= escape (optarg
);
1641 case OPT_INQUIRE_FD
:
1642 inquirefd
= strtol (optarg
, &p
, 10);
1645 inquirefp
= fdopen (inquirefd
, "r");
1647 err (EXIT_FAILURE
, "%i", inquirefd
);
1650 case OPT_INQUIRE_FILE
:
1651 inquirefd
= open (optarg
, O_RDONLY
);
1652 if (inquirefd
== -1)
1653 err (EXIT_FAILURE
, "%s", optarg
);
1654 inquirefp
= fdopen (inquirefd
, "r");
1657 outfd
= strtol (optarg
, &p
, 10);
1660 outfp
= fdopen (outfd
, "w");
1662 err (EXIT_FAILURE
, "%i", outfd
);
1669 statusfd
= strtol (optarg
, &p
, 10);
1672 statusfp
= fdopen (statusfd
, "w");
1674 err (EXIT_FAILURE
, "%i", statusfd
);
1678 printf ("%s (pwmc)\n\n"
1679 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014\n"
1681 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1682 "Compile-time features:\n"
1683 #ifdef HAVE_LIBREADLINE
1698 #ifdef WITH_PINENTRY
1713 "\n", PACKAGE_STRING
, PACKAGE_BUGREPORT
);
1714 exit (EXIT_SUCCESS
);
1716 pinentry_path
= optarg
;
1719 usage (argv
[0], EXIT_SUCCESS
);
1723 case OPT_SIGN_KEYID
:
1724 sign_keyid
= optarg
;
1730 case OPT_NO_PINENTRY
:
1733 #ifdef HAVE_LIBREADLINE
1734 case OPT_INTERACTIVE
:
1739 usage (argv
[0], EXIT_FAILURE
);
1744 fprintf (stderr
, N_("%s: invalid argument for option '--%s'\n"),
1745 argv
[0], long_opts
[opt_index
].name
);
1746 usage (argv
[0], EXIT_FAILURE
);
1755 knownhosts
= optarg
;
1759 inquire_line
= optarg
;
1774 clientname
= optarg
;
1777 usage (argv
[0], EXIT_FAILURE
);
1781 #ifdef HAVE_LIBREADLINE
1782 if (interactive
&& !isatty (STDIN_FILENO
))
1783 usage (argv
[0], EXIT_FAILURE
);
1784 else if (isatty (STDIN_FILENO
) && !inquire
&& !inquire_line
)
1788 filename
= argv
[optind
];
1790 gnutls_global_set_mem_functions (pwmd_malloc
, pwmd_malloc
, NULL
,
1791 pwmd_realloc
, pwmd_free
);
1794 rc
= pwmd_new (clientname
, &pwm
);
1798 pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TRIES
, tries
);
1800 fprintf (stderr
, N_("Connecting ...\n"));
1802 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1803 socktype
= is_remote_url (url
);
1804 if (socktype
!= PWMD_SOCKET_LOCAL
)
1807 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1808 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, connect_timeout
);
1813 if (socktype
== PWMD_SOCKET_SSH
)
1816 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_CB
, knownhost_cb
);
1820 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_DATA
, clientname
);
1824 if (!getenv ("SSH_AUTH_SOCK") || identity
)
1827 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_AGENT
, use_ssh_agent
);
1831 rc
= pwmd_connect (pwm
, url
, identity
, knownhosts
);
1837 rc
= pwmd_setopt (pwm
, PWMD_OPTION_TLS_VERIFY
, tls_verify
);
1841 rc
= pwmd_connect (pwm
, url
, clientcert
, clientkey
, cacert
, prio
,
1847 rc
= pwmd_connect (pwm
, url
);
1849 rc
= pwmd_connect (pwm
, url
);
1855 fprintf (stderr
, N_("Connected.\n"));
1858 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1859 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, socket_timeout
);
1866 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1867 "OPTION LOCK-TIMEOUT=%li", lock_timeout
);
1874 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCK_ON_OPEN
, 1);
1879 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, NULL
, NULL
);
1885 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, timeout
);
1890 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
1894 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
,
1895 (local_pin
|| keyfile
|| new_keyfile
));
1901 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_PATH
, pinentry_path
);
1908 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DISPLAY
, display
);
1915 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TTY
, tty
);
1922 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TERM
, ttytype
);
1929 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_CTYPE
, lcctype
);
1936 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_MESSAGES
, lcmessages
);
1943 rc
= pwmd_setopt (pwm
, PWMD_OPTION_STATUS_CB
, status_msg_cb
);
1950 rc
= open_command (filename
);
1955 #ifdef HAVE_LIBREADLINE
1958 rc
= do_interactive ();
1966 struct inquire_s
*inq
= NULL
;
1968 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
1970 rc
= pwmd_command (pwm
, &result
, &len
, inquire_cb
, inq
, inquire
);
1976 fcntl (STDIN_FILENO
, F_SETFL
, O_NONBLOCK
);
1981 rc
= process_cmd ();
1986 n
= read (STDIN_FILENO
, command
, sizeof (command
));
1989 if (errno
== EAGAIN
)
1995 rc
= gpg_error_from_errno (errno
);
2006 if (!p
|| !*p
|| !strcasecmp (p
, "BYE"))
2010 struct inquire_s
*inq
= NULL
;
2011 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2014 rc
= parse_dotcommand (command
, &result
, &len
, inq
);
2024 fwrite (result
, 1, result
[len
- 1] == 0 ? len
- 1 : len
, outfp
);
2032 else if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
2033 (void) pwmd_command (pwm
, &result
, NULL
, NULL
, NULL
,
2034 "GETINFO last_error");
2036 #ifdef HAVE_LIBREADLINE
2039 memset (command
, 0, sizeof (command
));
2042 show_error (pwm
, rc
, result
);
2045 pwmd_free (keyfile
);
2046 pwmd_free (new_keyfile
);
2049 if (connected
&& !quiet
)
2050 fprintf (stderr
, N_("Connection closed.\n"));
2052 exit (rc
? EXIT_FAILURE
: EXIT_SUCCESS
);