2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015,
4 Ben Kibbey <bjk@luxsci.net>
6 This file is part of libpwmd.
8 Libpwmd is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
13 Libpwmd is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Libpwmd. If not, see <http://www.gnu.org/licenses/>.
34 #include <sys/select.h>
36 #include <sys/types.h>
44 #include "util-string.h"
45 #include "util-slist.h"
48 #include <gnutls/gnutls.h>
55 #ifdef HAVE_GETOPT_LONG
60 #include "getopt_long.h"
63 #ifdef HAVE_LIBREADLINE
64 #if defined(HAVE_READLINE_READLINE_H)
65 #include <readline/readline.h>
66 #elif defined(HAVE_READLINE_H)
68 #endif /* !defined(HAVE_READLINE_H) */
69 static int interactive_error
;
70 static int interactive
;
71 #endif /* HAVE_LIBREADLINE */
73 #ifdef HAVE_READLINE_HISTORY
74 #if defined(HAVE_READLINE_HISTORY_H)
75 #include <readline/history.h>
76 #elif defined(HAVE_HISTORY_H)
79 #endif /* HAVE_READLINE_HISTORY */
86 #define N_(msgid) gettext(msgid)
91 #define DEFAULT_STATUS_IGNORE "KEEPALIVE,GPGME,PASSPHRASE_INFO,PASSPHRASE_HINT"
92 #define DEFAULT_PIN_TIMEOUT 30
93 #define DEFAULT_PIN_TRIES 3
94 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
97 static int no_pinentry
;
99 static char *filename
;
102 static char *sign_keyid
;
103 static int symmetric
;
104 static char *keyparams
;
105 static char *keyfile
;
106 static char *new_keyfile
;
107 static char *sign_keyfile
;
109 static int local_pin
;
110 static int inquirefd
;
114 static char **status_ignore
;
121 size_t size
; // from stat(2).
148 struct slist_s
*userids
;
149 struct slist_s
*subkeys
;
152 static gpg_error_t
finalize ();
153 static gpg_error_t
set_inquire (int fd
, const char *line
,
154 struct inquire_s
**result
);
155 static gpg_error_t
parse_dotcommand (const char *line
, char **result
,
156 size_t * len
, struct inquire_s
*inq
);
157 static gpg_error_t
open_command (char *line
);
160 show_error (pwm_t
*h
, gpg_error_t rc
, const char *str
)
164 int e
= pwmd_gnutls_error (h
, &tlsstr
);
167 fprintf(stderr
, "TLS: %s\n", tlsstr
);
171 fprintf (stderr
, "ERR %i: %s%s%s%s", rc
, gpg_strerror (rc
),
172 str
? ": " : "", str
? str
: "", str
? "" : "\n");
179 pwmd_free (new_keyfile
);
180 pwmd_free (sign_keyfile
);
181 keyfile
= new_keyfile
= sign_keyfile
= NULL
;
185 usage (const char *pn
, int status
)
187 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
188 N_("Usage: %s [options] [file]\n"
190 " a url string to connect to (%s, see below)\n"
191 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
192 " --connect-timeout <seconds>\n"
193 " seconds before connecting to a remote host fails (0=disabled, 120)\n"
194 " --socket-timeout <seconds>\n"
195 " seconds before a remote command fails (0=disabled, 300)\n"
198 " --ca-cert <filename>\n"
199 " certificate authority (CA) used to sign the server cert\n"
200 " --client-cert <filename>\n"
201 " client certificate to use for authentication\n"
202 " --client-key <filename>\n"
203 " key file used to protect the client certificate\n"
204 " --tls-priority <string>\n"
205 " compression, cipher and hash algorithm string\n"
206 " (SECURE256:SECURE192:SECURE128:-VERS-SSL3.0:-VERS-TLS1.0)\n"
208 " disable verifying the hostname against the server certificate\n"
209 " --tls-fingerprint <string>\n"
210 " a SHA-256 hash of the server fingerprint to verify against\n"
214 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
215 " --identity, -i <filename>\n"
216 " the ssh identity file to use for authentication\n"
217 " --knownhosts, -k <filename>\n"
218 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
219 " --ssh-needs-passphrase\n"
220 " prompt for a passphrase for the SSH identity file\n"
221 " --ssh-passphrase-file <filename>\n"
222 " read the SSH private key passphrase from filename\n"
225 " do not lock the data file upon opening it\n"
226 " --lock-timeout <N>\n"
227 " time in tenths of a second to wait for a locked data file (50)\n"
228 " --name, -n <string>\n"
229 " set the client name\n"
230 " --pinentry <path>\n"
231 " the full path to the pinentry binary\n"
232 " --local-pinentry\n"
233 " force using a local pinentry\n"
235 " disable pinentry both remotely and locally\n"
236 " --ttyname, -y <path>\n"
237 " tty that pinentry will use\n"
238 " --ttytype, -t <string>\n"
239 " pinentry terminal type (default is $TERM)\n"
241 " pinentry display (default is $DISPLAY)\n"
242 " --lc-ctype <string>\n"
243 " locale setting for pinentry\n"
244 " --lc-messages <string>\n"
245 " locale setting for pinentry\n"
247 " number of pinentry tries before failing (3)\n"
248 " --timeout <seconds>\n"
249 " pinentry timeout\n"
250 " --inquire <COMMAND>\n"
251 " the specified command (with any options) uses a server inquire while\n"
252 " command data is read via the inquire file descriptor (stdin)\n"
253 " --inquire-line, -L <STRING>\n"
254 " the initial line to send (i.e., element path) before the inquire data\n"
255 " --inquire-fd <FD>\n"
256 " read inquire data from the specified file descriptor (stdin)\n"
257 " --inquire-file <filename>\n"
258 " read inquire data from the specified filename\n"
259 " --output-fd <FD>\n"
260 " redirect command output to the specified file descriptor\n"
262 " send the SAVE command before exiting\n"
263 " --passphrase-file <filename>\n"
264 " obtain the passphrase from the specified filename\n"
265 " --new-passphrase-file <filename>\n"
266 " obtain the passphrase to save with from the specified filename\n"
267 " --sign-passphrase-file <filename>\n"
268 " obtain the passphrase to sign with from the specified filename\n"
269 " --key-params <filename>\n"
270 " key parameters to use for key generation (pwmd default)\n"
271 " --keyid <recipient>[,<recipient>]\n"
272 " the public key ID to u\n"
273 " --sign-keyid <string>\n"
274 " the key ID to sign the data file with\n"
276 " use conventional encryption with optional signer(s) for new files\n"
278 " disable showing of status messages from the server\n"
280 " enable receiving of client STATE status messages\n"
281 " --status-fd <FD>\n"
282 " redirect status messages to the specified file descriptor\n"
283 " --status-ignore <string[,...]>\n"
284 " prevent parsing of the specified status message keywords\n"
286 " disable showing of extra messages (implies --no-status)\n"
287 #ifdef HAVE_LIBREADLINE
288 " --no-interactive\n"
289 " disable interactive mode\n"
294 #ifdef DEFAULT_PWMD_SOCKET
300 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
302 "An optional url may be in the form of:\n"
303 " --url /path/to/socket\n"
304 " --url file://[/path/to/socket]\n"
307 " --url ssh[46]://[username@]hostname[:port] (uses ssh-agent)\n"
308 " -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
312 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
313 " --client-key filename\n"
315 #ifdef HAVE_LIBREADLINE
317 "Interactive mode is used when input is from a terminal.\n"
324 inquire_cb (void *user
, const char *keyword
, gpg_error_t rc
,
325 char **data
, size_t * size
)
327 struct inquire_s
*inq
= user
;
329 int is_newpassword
= 0;
339 if (!strcmp (keyword
, "PASSPHRASE"))
341 else if (!strcmp (keyword
, "SIGN_PASSPHRASE"))
343 else if (!strcmp (keyword
, "NEW_PASSPHRASE"))
345 #ifdef HAVE_LIBREADLINE
346 else if (!strcmp (keyword
, "KEYPARAM") && !interactive
)
349 else if (!strcmp (keyword
, "KEYPARAM"))
353 if (!keyparams
|| !*keyparams
)
354 return gpg_error (GPG_ERR_INV_PARAMETER
);
356 fd
= open (keyparams
, O_RDONLY
);
359 fprintf (stderr
, "%s: %s\n", keyparams
, strerror (errno
));
360 return gpg_error_from_syserror ();
363 rc
= set_inquire (fd
, NULL
, &inq
);
371 fprintf (stderr
, N_("Using file '%s' as %s.\n"), keyparams
, keyword
);
376 if ((is_password
&& !keyfile
) || (is_newpassword
&& !new_keyfile
)
377 || (sign
&& !sign_keyfile
))
382 /* Try to use the local pinentry between inquires (new/sign/passphrase).
383 * If --no-pinentry was specified then the passphrase is read from the
384 * terminal as usual. */
385 pwmd_getopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, &local
);
386 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, 1);
387 rc
= pwmd_password (pwm
, keyword
, &tmp
, &inq
->len
);
388 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local
);
389 if (rc
&& gpg_err_code (rc
) != GPG_ERR_EOF
)
392 pwmd_free (inq
->line
);
396 return gpg_error (GPG_ERR_EOF
);
398 else if ((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
)
399 || (sign
&& sign_keyfile
))
404 fd
= open (sign_keyfile
, O_RDONLY
);
406 fd
= open (is_password
|| sign
? keyfile
: new_keyfile
, O_RDONLY
);
411 fprintf (stderr
, "%s: %s\n", sign_keyfile
, strerror (errno
));
413 fprintf (stderr
, "%s: %s\n", is_newpassword
? new_keyfile
414 : keyfile
, strerror (errno
));
415 return gpg_error_from_syserror ();
418 rc
= set_inquire (fd
, NULL
, &inq
);
426 fprintf (stderr
, N_("Using keyfile '%s' as %s.\n"),
427 sign
? sign_keyfile
: is_newpassword
? new_keyfile
430 #ifdef HAVE_LIBREADLINE
431 else if ((!inq
->last_keyword
|| strcmp (keyword
, inq
->last_keyword
))
432 && interactive
&& inq
->fd
== STDIN_FILENO
)
436 ("%sPress CTRL-D to send the current line. Press twice to end. %s:\n"),
437 inq
->last_keyword
? "\n" : "", keyword
);
438 pwmd_free (inq
->last_keyword
);
439 inq
->last_keyword
= pwmd_strdup (keyword
);
443 /* The first part of the command data. */
449 return inq
->fd
== -1 ? gpg_error (GPG_ERR_EOF
) : 0;
452 *size
= read (inq
->fd
, inq
->line
, ASSUAN_LINELENGTH
);
456 return gpg_error (gpg_error_from_syserror ());
460 else if (inq
->fd
!= STDIN_FILENO
&&
461 (is_newpassword
|| is_password
|| sign
|| is_keyparam
))
469 if (((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
)
470 || (sign
&& sign_keyfile
) || (keyparams
&& is_keyparam
))
471 && *size
== inq
->size
)
472 return gpg_error (GPG_ERR_EOF
);
474 return *size
? 0 : gpg_error (GPG_ERR_EOF
);
478 status_msg_cb (void *data
, const char *line
)
480 char *p
= strchr (line
, ' ');
485 /* Ignore status messages specified by the client via --status-ignore. */
486 for (s
= status_ignore
; s
&& *s
; s
++)
488 char *tmp
= strchr (line
, ' ');
489 size_t len
= tmp
? strlen (line
) - strlen (tmp
) : strlen (line
);
491 if (!strncmp (line
, *s
, len
) && len
== strlen (*s
))
495 #ifdef HAVE_LIBREADLINE
496 if (interactive
&& !strncmp (line
, "XFER ", 5)
498 if (!strncmp (line
, "XFER ", 5)
500 && *line
!= '#' && p
&& strchr (p
, ' ') && *++p
)
502 char *p1
= strchr (p
, ' ');
503 int a
= strtol (p
, NULL
, 10);
505 if (isdigit (*p
) && p1
)
507 int b
= strtol (p1
, NULL
, 10);
509 int t
= a
&& b
? a
* 100 / b
: 0;
511 strncpy (l
, line
, strlen (line
) - strlen (p
) - 1);
512 fprintf (statusfp
, "\rS:%s %i/%i %i%%%s", l
, a
, b
, t
,
519 fprintf (statusfp
, "S:%s\n", line
);
521 #ifdef HAVE_LIBREADLINE
530 return pwmd_process (pwm
);
535 knownhost_cb (void *data
, const char *host
, const char *key
, size_t len
)
539 pwmd_strdup_printf (N_
540 ("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?\n"),
541 (char *) data
, host
, host
);
544 if (no_pinentry
&& !isatty (STDIN_FILENO
))
546 fprintf (stderr
, N_("Input is not from a terminal! Failing.\n"));
548 return GPG_ERR_ENOTTY
;
550 else if (no_pinentry
)
553 for (char *p
= buf
; *p
; p
++, len
++)
562 while (len
&& !isspace (*(--p
)))
571 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_PROMPT
, N_("Accept [y/N]:"));
575 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, buf
);
581 return pwmd_getpin (pwm
, NULL
, NULL
, NULL
, PWMD_PINENTRY_CONFIRM
);
585 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
587 is_remote_url (const char *str
)
590 return PWMD_SOCKET_LOCAL
;
593 if (strstr (str
, "ssh://") || strstr (str
, "ssh4://")
594 || strstr (str
, "ssh6://"))
595 return PWMD_SOCKET_SSH
;
599 if (strstr (str
, "tls://") || strstr (str
, "tls4://")
600 || strstr (str
, "tls6://"))
601 return PWMD_SOCKET_TLS
;
604 return PWMD_SOCKET_LOCAL
;
609 escape (const char *str
)
612 char *buf
= pwmd_malloc (ASSUAN_LINELENGTH
+ 1), *b
= buf
;
615 for (p
= str
; *p
; p
++, len
++)
617 if (len
== ASSUAN_LINELENGTH
)
661 free_inquire (struct inquire_s
*inq
)
666 pwmd_free (inq
->line
);
668 if (inq
->fd
!= -1 && inq
->fd
!= STDIN_FILENO
)
671 pwmd_free (inq
->last_keyword
);
675 /* When *result is not NULL it is updated to the new values and not
678 set_inquire (int fd
, const char *line
, struct inquire_s
**result
)
680 struct inquire_s inq
= { 0 };
681 struct stat st
= { 0 };
686 if (fstat (fd
, &st
) == -1)
687 return gpg_error_from_syserror ();
689 inq
.size
= st
.st_size
;
693 inq
.line
= pwmd_calloc (1, ASSUAN_LINELENGTH
);
695 return GPG_ERR_ENOMEM
;
699 char *s
= escape (line
);
703 pwmd_free (inq
.line
);
704 return GPG_ERR_ENOMEM
;
707 if (strlen (s
) >= ASSUAN_LINELENGTH
)
709 pwmd_free (inq
.line
);
711 return GPG_ERR_LINE_TOO_LONG
;
714 strncpy (inq
.line
, s
, ASSUAN_LINELENGTH
- 1);
715 inq
.len
= strlen (s
);
719 rc
= pwmd_setopt (pwm
, PWMD_OPTION_INQUIRE_TOTAL
,
720 st
.st_size
? st
.st_size
+ strlen (inq
.line
) : 0);
723 pwmd_free (inq
.line
);
728 *result
= pwmd_malloc (sizeof (struct inquire_s
));
731 if ((*result
)->fd
!= -1 && (*result
)->fd
!= STDIN_FILENO
)
732 close ((*result
)->fd
);
734 pwmd_free ((*result
)->line
);
735 (*result
)->line
= NULL
;
740 memcpy (*result
, &inq
, sizeof (struct inquire_s
));
741 memset (&inq
, 0, sizeof (struct inquire_s
));
745 #ifdef HAVE_LIBREADLINE
747 interactive_hook (void)
749 interactive_error
= process_cmd ();
751 if (interactive_error
)
752 rl_event_hook
= NULL
;
758 get_readline_char (FILE *fp
)
761 && (!strncmp (rl_line_buffer
, ".set passphrase-file ", 16)
762 || !strncmp (rl_line_buffer
, ".set new-passphrase-file ", 20)
763 || !strncmp (rl_line_buffer
, ".set sign-passphrase-file ", 21)))
764 rl_inhibit_completion
= 0;
765 else if (rl_line_buffer
766 && !strncmp (rl_line_buffer
, ".redir ", 7))
768 char *p
= strchr (rl_line_buffer
, ' ');
770 if (p
&& strchr (++p
, ' '))
771 rl_inhibit_completion
= 1;
773 rl_inhibit_completion
= 0;
775 else if (rl_line_buffer
776 && !strncmp (rl_line_buffer
, ".read ", 6))
778 char *p
= rl_line_buffer
+ 6;
780 if (strstr (p
, "--prefix "))
782 p
= strstr (p
, "--prefix ");
789 if (!p
|| strchr (p
, ' '))
790 rl_inhibit_completion
= 1;
792 rl_inhibit_completion
= 0;
795 rl_inhibit_completion
= 1;
805 ("------------------------------------------------------------\n"
806 "Elements are TAB delimited. Type HELP for protocol commands.\n"
807 "Type .help for pwmc commands. Press CTRL-D to quit.\n"
808 "------------------------------------------------------------\n"));
813 parse_arg (const char *src
, char *dst
, size_t len
)
819 for (; s
&& *s
&& *s
!= ' ' && n
< len
; s
++, n
++)
827 parse_opt (char **line
, const char *opt
, gpg_error_t
* rc
)
829 static char result
[ASSUAN_LINELENGTH
] = { 0 }, *r
= result
;
830 char *s
= strstr (*line
, opt
);
840 size_t rlen
= strlen (opt
);
844 while (*p
&& *p
== ' ')
850 for (; *p
&& len
< sizeof (result
) - 1; p
++, rlen
++)
852 if (isspace (*p
) && !quote
)
855 if (*p
== '\"' && lastc
!= '\\')
868 if (len
>= sizeof (result
) - 1)
869 *rc
= GPG_ERR_LINE_TOO_LONG
;
874 while (*p
&& *p
== ' ')
885 read_command (const char *line
, char **result
, size_t * len
)
890 struct inquire_s
*inq
= NULL
;
891 char *p
= (char *) line
;
892 const char *prefix
= parse_opt (&p
, "--prefix", &rc
);
893 char filebuf
[ASSUAN_LINELENGTH
];
902 while (*p
&& isspace (*p
))
905 file
= parse_arg (p
, filebuf
, sizeof (filebuf
));
908 p
+= strlen (file
) + 1;
910 while (*p
&& isspace (*p
))
922 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
925 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\\ = \\)\n"));
929 fd
= open (file
, O_RDONLY
);
931 return gpg_error_from_syserror ();
933 rc
= set_inquire (fd
, prefix
&& *prefix
? prefix
: NULL
, &inq
);
940 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, "%s", p
);
946 redir_command (const char *line
)
948 const char *p
= line
;
950 gpg_error_t rc
= GPG_ERR_SYNTAX
;
952 struct inquire_s
*inq
= NULL
;
955 char filebuf
[ASSUAN_LINELENGTH
];
959 file
= parse_arg (p
, filebuf
, sizeof (filebuf
));
962 p
+= strlen (file
) + 1;
964 while (*p
&& isspace (*p
))
974 fprintf (stderr
, N_("Usage: .redir <filename> <command> [args]\n"));
978 fd
= open (file
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600);
980 return gpg_error_from_syserror ();
982 #ifdef HAVE_LIBREADLINE
983 rc
= set_inquire (interactive
? STDIN_FILENO
: inquirefd
, NULL
, &inq
);
985 rc
= set_inquire (inquirefd
, NULL
, &inq
);
993 rc
= parse_dotcommand (p
, &result
, &len
, inq
);
994 if (!rc
&& result
&& len
--)
995 { // null byte which is always appended
996 if (write (fd
, result
, len
) != len
)
997 rc
= GPG_ERR_TOO_SHORT
;
1007 help_command (const char *line
)
1011 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
1012 " .redir <filename> <command>\n"
1013 " redirect the output of a command to the specified file\n"
1015 " .open <filename>\n"
1016 " open the specified filename losing any changes to the current one\n"
1018 " .read [--prefix <string>] <filename> <command> [args]\n"
1019 " obtain data from the specified filename for an inquire command\n"
1021 " .set help | <name> [<value>]\n"
1022 " set option <name> to <value>\n"
1025 " write changes of the file to disk\n"
1028 " change the passphrase of a data file\n"
1030 " .listkeys [--options] [pattern[,..]]\n"
1031 " show human readable output of the LISTKEYS command\n"
1034 " this help text\n"));
1039 open_command (char *line
)
1041 struct inquire_s
*inq
= NULL
;
1042 const char *file
= line
;
1046 while (file
&& isspace (*file
))
1049 if (!file
|| !*file
)
1051 fprintf (stderr
, N_("Usage: .open <filename>\n"));
1052 return GPG_ERR_SYNTAX
;
1055 #ifdef HAVE_LIBREADLINE
1056 if (interactive
|| !quiet
)
1060 fprintf (stderr
, N_("Opening data file \"%s\" ...\n"), file
);
1062 #ifdef HAVE_LIBREADLINE
1063 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1065 rc
= set_inquire (-1, NULL
, &inq
);
1070 pwmd_getopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, &local
);
1074 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1076 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, 1);
1079 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1082 rc
= pwmd_open (pwm
, file
, inquire_cb
, inq
);
1084 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local
);
1086 #ifdef HAVE_LIBREADLINE
1092 if (!rc
&& file
!= filename
)
1094 pwmd_free (filename
);
1095 filename
= pwmd_strdup (file
);
1102 set_command (const char *line
)
1105 char name
[256] = { 0 };
1106 char value
[512] = { 0 };
1109 const char *p
= line
;
1111 while (p
&& *p
&& isspace (*p
))
1114 namep
= parse_arg (p
, name
, sizeof (name
));
1115 if (!namep
|| !*namep
)
1117 fprintf (stderr
, N_("Usage: .set help | <name> [<value>]\n"));
1118 return GPG_ERR_SYNTAX
;
1121 p
+= strlen (namep
);
1122 while (p
&& *p
&& isspace (*p
))
1125 valuep
= parse_arg (p
, value
, sizeof (value
));
1127 if (!strcmp (name
, "passphrase-file") || !strcmp (name
, "new-passphrase-file")
1128 || !strcmp (name
, "sign-passphrase-file"))
1130 int is_newkeyfile
= 1;
1131 int sign
= !strcmp (name
, "sign-passphrase-file");
1133 if (!strcmp (name
, "passphrase-file") || sign
)
1138 pwmd_free (new_keyfile
);
1143 pwmd_free (sign_keyfile
);
1144 sign_keyfile
= NULL
;
1148 pwmd_free (keyfile
);
1155 new_keyfile
= pwmd_strdup (value
);
1157 sign_keyfile
= pwmd_strdup (value
);
1159 keyfile
= pwmd_strdup (value
);
1161 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1163 else if (!local_pin
&& !no_pinentry
)
1167 pwmd_socket_type (pwm
, &t
);
1168 if (t
== PWMD_SOCKET_LOCAL
)
1169 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1172 else if (!strcmp(name
, "pinentry-timeout"))
1175 int n
= strtol(valuep
, &e
, 10);
1178 return gpg_error (GPG_ERR_INV_VALUE
);
1181 n
= DEFAULT_PIN_TIMEOUT
;
1183 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, n
);
1185 else if (!strcmp (name
, "help"))
1189 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1190 "delimited. When no value is specified the option is unset.\n\n"
1191 "passphrase-file [<filename>]\n"
1192 " set or unset the file to be used when a passphrase is required (*)\n"
1194 "new-passphrase-file [<filename>]\n"
1195 " set or unset the file to be used when a new passphrase is required (*)\n"
1197 "sign-passphrase-file [<filename>]\n"
1198 " set or unset the file to be used when a passphrase is required for\n"
1199 " signing (symmetric) (*)\n"
1201 "pinentry-timeout <seconds>\n"
1202 " the amount of seconds before pinentry gives up waiting for input\n"
1204 "* = the next protocol command will unset this value\n"
1208 rc
= GPG_ERR_UNKNOWN_OPTION
;
1214 do_save_passwd_command (const char *line
, int do_save
)
1216 struct inquire_s
*inq
= NULL
;
1220 #ifdef HAVE_LIBREADLINE
1221 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1223 rc
= set_inquire (-1, NULL
, &inq
);
1228 pwmd_getopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, &local
);
1230 if (new_keyfile
|| keyfile
|| sign_keyfile
)
1232 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1234 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, 1);
1237 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1242 rc
= pwmd_save (pwm
, line
, inquire_cb
, inq
);
1244 rc
= pwmd_passwd (pwm
, line
, inquire_cb
, inq
);
1247 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local
);
1249 #ifdef HAVE_LIBREADLINE
1259 save_command (const char *line
)
1261 return do_save_passwd_command (line
, 1);
1265 search_and_replace (char *str
, const char *s
, const char r
)
1269 p
= strstr (str
, s
);
1275 search_and_replace (str
, s
, r
);
1281 openpgp_unescape (char *str
)
1283 search_and_replace (str
, "\\x3a", ':');
1284 search_and_replace (str
, "\\x5c", '\\');
1289 free_listkeys (struct slist_s
*keys
)
1293 t
= slist_length (keys
);
1294 for (i
= 0; i
< t
; i
++)
1296 struct keyid_s
*key
= slist_nth_data (keys
, i
);
1299 nt
= slist_length (key
->userids
);
1300 for (n
= 0; n
< nt
; n
++)
1302 struct userid_s
*userid
= slist_nth_data (key
->userids
, n
);
1304 pwmd_free (userid
->userid
);
1305 pwmd_free (userid
->name
);
1306 pwmd_free (userid
->email
);
1307 pwmd_free (userid
->comment
);
1311 slist_free (key
->userids
);
1312 nt
= slist_length (key
->subkeys
);
1313 for (n
= 0; n
< nt
; n
++)
1315 struct keyid_s
*sub
= slist_nth_data (key
->subkeys
, n
);
1317 pwmd_free (sub
->keyid
);
1318 pwmd_free (sub
->fpr
);
1319 pwmd_free (sub
->card
);
1320 pwmd_free (sub
->curve
);
1324 slist_free (key
->subkeys
);
1332 openpgp_algorithm (struct keyid_s
*key
)
1353 return N_("Unknown");
1357 display_listkeys (struct slist_s
*keys
)
1361 t
= slist_length (keys
);
1362 for (i
= 0; i
< t
; i
++)
1364 struct keyid_s
*key
= slist_nth_data (keys
, i
);
1365 unsigned st
= slist_length (key
->subkeys
);
1367 unsigned ut
= slist_length (key
->userids
);
1370 for (u
= 0; u
< ut
; u
++)
1372 struct userid_s
*userid
= slist_nth_data (key
->userids
, u
);
1374 fprintf(stdout
, N_("User ID: %s\n"), userid
->userid
);
1377 for (s
= 0; s
< st
; s
++)
1379 struct keyid_s
*sub
= slist_nth_data (key
->subkeys
, s
);
1381 const char *caps
= NULL
;
1382 char expires
[11] = { 0 };
1383 char created
[11] = { 0 };
1387 tmp
= localtime (&sub
->expires
);
1388 strftime (expires
, sizeof (expires
), "%F", tmp
);
1391 tmp
= localtime (&sub
->created
);
1392 strftime (created
, sizeof (created
), "%F", tmp
);
1394 if (sub
->can_encrypt
)
1396 else if (sub
->can_sign
)
1398 else if (sub
->can_auth
)
1400 else if (sub
->can_certify
)
1404 " Subkey %u: %s [%s]%s%s %s-%u%s%s\n"
1405 " Created: %s %s%s\n"
1406 " Fingerprint: %s\n"
1411 sub
->secret
|| sub
->card
? "[P]" : "",
1412 sub
->revoked
? "[R]" : "",
1413 openpgp_algorithm (sub
),
1415 sub
->curve
? "-" : "",
1416 sub
->curve
? sub
->curve
: "",
1418 sub
->expired
? N_("Expired: ") : expires
[0] ? N_("Expires: ") : "",
1419 sub
->expired
|| expires
[0] ? expires
: "",
1421 sub
->card
? N_(" Card: ") : "",
1422 sub
->card
? sub
->card
: "",
1423 sub
->card
? "\n" : "");
1427 fprintf (stdout
, "\n");
1432 listkeys_command (const char *pattern
)
1436 char **lines
= NULL
, **p
;
1437 struct slist_s
*keys
= NULL
;
1439 rc
= pwmd_command (pwm
, &result
, NULL
, NULL
, NULL
, "LISTKEYS %s", pattern
);
1443 lines
= str_split (result
, "\n", 0);
1446 return GPG_ERR_ENOMEM
;
1448 for (p
= lines
; *p
; p
++)
1450 struct keyid_s
*key
;
1451 char **fields
= str_split (*p
, ":", 0);
1454 unsigned n_subkeys
= 0;
1455 struct slist_s
*tlist
;
1459 rc
= GPG_ERR_ENOMEM
;
1463 key
= pwmd_calloc (1, sizeof (struct keyid_s
));
1467 rc
= GPG_ERR_ENOMEM
;
1471 for (f
= i
= 0; i
< 17; i
++, f
++)
1476 b
= atoi (fields
[f
]) != 0;
1480 case 0: key
->revoked
= b
; break;
1481 case 1: key
->expired
= b
; break;
1482 case 4: key
->can_encrypt
= b
; break;
1483 case 5: key
->can_sign
= b
; break;
1484 case 7: key
->secret
= b
; break;
1485 case 16: n_subkeys
= strtoul (fields
[f
], NULL
, 10); break;
1491 for (s
= 0; s
< n_subkeys
; s
++)
1493 struct keyid_s
*sub
;
1496 sub
= pwmd_calloc (1, sizeof (struct keyid_s
));
1500 rc
= GPG_ERR_ENOMEM
;
1504 for (i
= 0; i
< 20; i
++, f
++)
1507 b
= atoi (fields
[f
]) != 0;
1511 case 0: sub
->revoked
= b
; break;
1512 case 1: sub
->expired
= b
; break;
1513 case 4: sub
->can_encrypt
= b
; break;
1514 case 5: sub
->can_sign
= b
; break;
1515 case 6: sub
->can_certify
= b
; break;
1516 case 7: sub
->secret
= b
; break;
1517 case 8: sub
->can_auth
= b
; break;
1518 case 11: sub
->algo
= atoi (fields
[f
]); break;
1519 case 12: sub
->bits
= atoi (fields
[f
]); break;
1520 case 13: sub
->keyid
= pwmd_strdup (fields
[f
]); break;
1521 case 14: sub
->fpr
= pwmd_strdup (fields
[f
]); break;
1522 case 16: sub
->created
= strtoul (fields
[f
], NULL
, 10); break;
1523 case 17: sub
->expires
= strtoul (fields
[f
], NULL
, 10); break;
1524 case 18: sub
->card
= fields
[f
] && strlen(fields
[f
]) > 1
1525 ? pwmd_strdup (fields
[f
]) : NULL
; break;
1526 case 19: sub
->curve
= strlen (fields
[f
]) > 1 ? pwmd_strdup (openpgp_unescape(fields
[f
])) : NULL
; break;
1532 tlist
= slist_append (key
->subkeys
, sub
);
1535 rc
= GPG_ERR_ENOMEM
;
1539 key
->subkeys
= tlist
;
1548 // Re-create a line containing the userIds.
1549 for (; f
< strv_length (fields
); f
++)
1551 struct userid_s
*userid
;
1553 userid
= pwmd_calloc (1, sizeof (struct userid_s
));
1556 rc
= GPG_ERR_ENOMEM
;
1567 userid
->userid
= pwmd_strdup (openpgp_unescape (fields
[f
++]));
1568 userid
->name
= pwmd_strdup (openpgp_unescape (fields
[f
++]));
1569 userid
->email
= pwmd_strdup (openpgp_unescape (fields
[f
++]));
1570 userid
->comment
= pwmd_strdup (openpgp_unescape (fields
[f
]));
1572 tlist
= slist_append (key
->userids
, userid
);
1575 rc
= GPG_ERR_ENOMEM
;
1579 key
->userids
= tlist
;
1586 tlist
= slist_append (keys
, key
);
1589 rc
= GPG_ERR_ENOMEM
;
1599 display_listkeys (keys
);
1601 free_listkeys (keys
);
1606 parse_dotcommand (const char *line
, char **result
,
1607 size_t * len
, struct inquire_s
*inq
)
1609 const char *p
= line
;
1612 if (!strncmp (p
, ".read", 5))
1613 rc
= read_command (p
+ 5, result
, len
);
1614 else if (!strncmp (p
, ".redir", 6))
1615 rc
= redir_command (p
+ 6);
1616 else if (!strncmp (p
, ".help", 5))
1617 rc
= help_command (p
+ 5);
1618 else if (!strncmp (p
, ".open", 5))
1619 rc
= open_command ((char *)p
+ 5);
1620 else if (!strncmp (p
, ".set", 4))
1621 rc
= set_command (p
+ 4);
1622 else if (!strncmp (p
, ".save", 5))
1623 rc
= do_save_passwd_command (p
+ 5, 1);
1624 else if (!strncmp (p
, ".passwd", 7))
1625 rc
= do_save_passwd_command (p
+ 7, 0);
1626 else if (!strncmp (p
, ".listkeys", 9))
1627 rc
= listkeys_command (p
+9);
1630 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, "%s", line
);
1631 #ifdef HAVE_LIBREADLINE
1636 #ifdef HAVE_LIBREADLINE
1640 if (!rc
&& !strncasecmp (line
, "RESET", 5))
1642 pwmd_free (filename
);
1650 #ifdef HAVE_LIBREADLINE
1651 #ifdef HAVE_READLINE_HISTORY
1653 add_history_item (const char *line
)
1655 HIST_ENTRY
**list
, *p
= NULL
;
1658 list
= history_list ();
1659 for (i
= 0; list
&& list
[i
]; i
++)
1661 if (!strcmp (list
[i
]->line
, line
))
1672 p
= remove_history (i
);
1673 #ifdef HAVE_FREE_HISTORY_ENTRY
1674 s
= free_history_entry (p
);
1687 struct inquire_s
*inq
= NULL
;
1690 rc
= process_cmd ();
1694 rc
= set_inquire (STDIN_FILENO
, NULL
, &inq
);
1699 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1701 rl_event_hook
= &interactive_hook
;
1702 rl_getc_function
= get_readline_char
;
1703 rl_set_keyboard_input_timeout (100000);
1708 char *result
= NULL
;
1713 snprintf (buf
, sizeof (buf
), "pwmc%s%s> ",
1714 filename
? ":" : "", filename
? filename
: "");
1715 line
= readline (buf
);
1716 if (interactive_error
)
1719 rc
= interactive_error
;
1729 if (gpg_err_code (rc
) != GPG_ERR_CANCELED
&&
1730 gpg_err_code (rc
) != GPG_ERR_EOF
)
1731 fprintf (stderr
, "ERR %i: %s\n", rc
, gpg_strerror (rc
));
1741 #ifdef HAVE_READLINE_HISTORY
1742 add_history_item (line
);
1744 rc
= parse_dotcommand (line
, &result
, &len
, inq
);
1750 if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
1751 (void) pwmd_command (pwm
, &tmp
, NULL
, NULL
, NULL
,
1752 "GETINFO last_error");
1754 show_error (pwm
, rc
, tmp
);
1757 else if (result
&& len
)
1758 printf ("%s%s", result
, result
[len
- 1] != '\n' ? "\n" : "");
1772 #ifdef HAVE_LIBREADLINE
1779 fprintf (stderr
, "\n");
1787 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1788 p
= fgets (buf
, sizeof (buf
), stdin
);
1802 return GPG_ERR_CANCELED
;
1806 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1807 "CLEARCACHE %s", filename
);
1811 interactive_hook ();
1827 if (save
&& !filename
)
1831 ("No filename was specified on the command line. Aborting.\n"));
1832 return GPG_ERR_CANCELED
;
1835 if (save
&& filename
)
1838 pwmd_strdup_printf ("%s %s%s %s%s %s",
1839 symmetric
? "--symmetric" : "",
1840 keyid
? "--keyid=" : "",
1842 sign_keyid
? "--sign-keyid=" : "",
1843 sign_keyid
? sign_keyid
: "",
1844 keyparams
? "--inquire-keyparam" : "");
1846 #ifdef HAVE_LIBREADLINE
1847 if (!quiet
|| interactive
)
1853 fprintf (stderr
, "\n");
1854 fprintf (stderr
, N_("Saving changes ...\n"));
1857 rc
= save_command (args
);
1861 #ifdef HAVE_LIBREADLINE
1863 return rc
? rc
: quit
? 0 : GPG_ERR_CANCELED
;
1870 parse_status_ignore (char *str
)
1875 for (p
= status_ignore
; p
&& *p
; p
++)
1878 pwmd_free (status_ignore
);
1879 status_ignore
= NULL
;
1883 while ((s
= strsep (&str
, ",")))
1885 p
= pwmd_realloc (status_ignore
, (n
+ 2) * sizeof (char *));
1886 p
[n
++] = pwmd_strdup (s
);
1893 main (int argc
, char *argv
[])
1896 int status_state
= 0;
1899 char command
[ASSUAN_LINELENGTH
], *p
= NULL
;
1900 char *result
= NULL
;
1902 char *pinentry_path
= NULL
;
1903 char *display
= NULL
, *tty
= NULL
, *ttytype
= NULL
;
1904 char *lcctype
= NULL
, *lcmessages
= NULL
;
1905 int outfd
= STDOUT_FILENO
;
1906 FILE *outfp
= stdout
;
1907 FILE *inquirefp
= stdin
;
1908 int show_status
= 1;
1909 const char *clientname
= "pwmc";
1910 char *inquire
= NULL
;
1911 char *inquire_line
= NULL
;
1914 int use_ssh_agent
= -1;
1915 char *knownhosts
= NULL
;
1916 char *identity
= NULL
;
1917 int needs_passphrase
= 0;
1918 char *ssh_passphrase_file
= NULL
;
1921 char *cacert
= NULL
;
1922 char *clientcert
= NULL
;
1923 char *clientkey
= NULL
;
1925 int tls_verify
= -1;
1926 char *tls_fingerprint
= NULL
;
1928 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1929 pwmd_socket_t socktype
;
1930 long socket_timeout
= 300;
1931 int connect_timeout
= 120;
1933 #ifdef HAVE_LIBREADLINE
1934 int no_interactive
= 0;
1936 int lock_on_open
= -1;
1937 long lock_timeout
= 50;
1940 /* The order is important. */
1943 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1944 OPT_SOCKET_TIMEOUT
, OPT_CONNECT_TIMEOUT
,
1947 OPT_USE_SSH_AGENT
, OPT_IDENTITY
, OPT_KNOWNHOSTS
, OPT_SSH_NEEDS_PASSPHRASE
,
1948 OPT_SSH_PASSPHRASE_FILE
,
1951 OPT_CACERT
, OPT_CLIENTCERT
, OPT_CLIENTKEY
, OPT_PRIORITY
, OPT_VERIFY
,
1954 OPT_URL
, OPT_LOCAL
, OPT_TTYNAME
, OPT_TTYTYPE
, OPT_DISPLAY
, OPT_LC_CTYPE
,
1955 OPT_LC_MESSAGES
, OPT_TIMEOUT
, OPT_TRIES
, OPT_PINENTRY
, OPT_KEYFILE
,
1956 OPT_PASSPHRASE_FILE
, OPT_NEW_KEYFILE
, OPT_NEW_PASSPHRASE_FILE
,
1957 OPT_SIGN_KEYFILE
, OPT_SIGN_PASSPHRASE_FILE
, OPT_NOLOCK
, OPT_LOCK_TIMEOUT
,
1958 OPT_SAVE
, OPT_OUTPUT_FD
, OPT_INQUIRE
, OPT_INQUIRE_FD
, OPT_INQUIRE_FILE
,
1959 OPT_INQUIRE_LINE
, OPT_NO_STATUS
, OPT_STATUS_IGNORE
, OPT_STATUSFD
, OPT_NAME
,
1960 OPT_VERSION
, OPT_HELP
, OPT_KEYID
, OPT_SIGN_KEYID
, OPT_SYMMETRIC
,
1961 OPT_KEYPARAMS
, OPT_NO_PINENTRY
, OPT_QUIET
, OPT_STATUS_STATE
,
1962 #ifdef HAVE_LIBREADLINE
1966 const struct option long_opts
[] = {
1967 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1968 {"socket-timeout", 1, 0, 0},
1969 {"connect-timeout", 1, 0, 0},
1973 {"no-ssh-agent", 0, 0, 0},
1974 {"identity", 1, 0, 'i'},
1975 {"knownhosts", 1, 0, 'k'},
1976 {"ssh-needs-passphrase", 0, 0, 0},
1977 {"ssh-passphrase-file", 1, 0, 0},
1980 {"ca-cert", 1, 0, 0},
1981 {"client-cert", 1, 0, 0},
1982 {"client-key", 1, 0, 0},
1983 {"tls-priority", 1, 0, 0},
1984 {"no-tls-verify", 0, 0, 0},
1985 {"tls-fingerprint", 1, 0, 0},
1988 {"local-pinentry", 0, 0},
1989 {"ttyname", 1, 0, 'y'},
1990 {"ttytype", 1, 0, 't'},
1991 {"display", 1, 0, 'd'},
1992 {"lc-ctype", 1, 0, 0},
1993 {"lc-messages", 1, 0, 0},
1994 {"timeout", 1, 0, 0},
1996 {"pinentry", 1, 0, 0},
1997 {"key-file", 1, 0, 0},
1998 {"passphrase-file", 1, 0, 0},
1999 {"new-key-file", 1, 0, 0},
2000 {"new-passphrase-file", 1, 0, 0},
2001 {"sign-key-file", 1, 0, 0},
2002 {"sign-passphrase-file", 1, 0, 0},
2003 {"no-lock", 0, 0, 0},
2004 {"lock-timeout", 1, 0, 0},
2005 {"save", 0, 0, 'S'},
2006 {"output-fd", 1, 0, 0},
2007 {"inquire", 1, 0, 0},
2008 {"inquire-fd", 1, 0, 0},
2009 {"inquire-file", 1, 0, 0},
2010 {"inquire-line", 1, 0, 'L'},
2011 {"no-status", 0, 0, 0},
2012 {"status-ignore", 1, 0, 0},
2013 {"status-fd", 1, 0, 0},
2014 {"name", 1, 0, 'n'},
2015 {"version", 0, 0, 0},
2018 {"sign-keyid", 1, 0, 0},
2019 {"symmetric", 0, 0, 0},
2020 {"key-params", 1, 0, 0},
2021 {"no-pinentry", 0, 0, 0},
2023 {"status-state", 0, 0, 0},
2024 #ifdef HAVE_LIBREADLINE
2025 {"no-interactive", 0, 0},
2030 const char *optstring
= "L:y:t:d:P:I:Sn:i:k:s";
2032 const char *optstring
= "L:y:t:d:P:I:Sn:s";
2037 setlocale (LC_ALL
, "");
2038 bindtextdomain ("libpwmd", LOCALEDIR
);
2041 tries
= DEFAULT_PIN_TRIES
;
2042 inquirefd
= STDIN_FILENO
;
2043 statusfd
= STDERR_FILENO
;
2045 tmp
= pwmd_strdup (DEFAULT_STATUS_IGNORE
);
2046 parse_status_ignore (tmp
);
2052 getopt_long (argc
, argv
, optstring
, long_opts
, &opt_index
)) != -1)
2056 /* Handle long options without a short option part. */
2060 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2061 case OPT_SOCKET_TIMEOUT
:
2062 socket_timeout
= strtol (optarg
, &p
, 10);
2064 case OPT_CONNECT_TIMEOUT
:
2065 connect_timeout
= strtol (optarg
, &p
, 10);
2069 case OPT_USE_SSH_AGENT
:
2072 case OPT_SSH_NEEDS_PASSPHRASE
:
2073 needs_passphrase
= 1;
2075 case OPT_SSH_PASSPHRASE_FILE
:
2076 ssh_passphrase_file
= optarg
;
2083 case OPT_CLIENTCERT
:
2084 clientcert
= optarg
;
2096 tls_fingerprint
= optarg
;
2106 case OPT_PASSPHRASE_FILE
:
2107 keyfile
= pwmd_strdup (optarg
);
2109 case OPT_NEW_KEYFILE
:
2110 case OPT_NEW_PASSPHRASE_FILE
:
2111 new_keyfile
= pwmd_strdup (optarg
);
2113 case OPT_SIGN_KEYFILE
:
2114 case OPT_SIGN_PASSPHRASE_FILE
:
2115 sign_keyfile
= pwmd_strdup (optarg
);
2120 case OPT_LOCK_TIMEOUT
:
2121 lock_timeout
= strtol (optarg
, &p
, 10);
2130 lcctype
= pwmd_strdup (optarg
);
2132 case OPT_LC_MESSAGES
:
2133 lcmessages
= pwmd_strdup (optarg
);
2136 timeout
= strtol (optarg
, &p
, 10);
2139 tries
= strtol (optarg
, &p
, 10);
2142 inquire
= escape (optarg
);
2144 case OPT_INQUIRE_FD
:
2145 inquirefd
= strtol (optarg
, &p
, 10);
2148 inquirefp
= fdopen (inquirefd
, "r");
2150 err (EXIT_FAILURE
, "%i", inquirefd
);
2153 case OPT_INQUIRE_FILE
:
2154 inquirefd
= open (optarg
, O_RDONLY
);
2155 if (inquirefd
== -1)
2156 err (EXIT_FAILURE
, "%s", optarg
);
2157 inquirefp
= fdopen (inquirefd
, "r");
2160 outfd
= strtol (optarg
, &p
, 10);
2163 outfp
= fdopen (outfd
, "w");
2165 err (EXIT_FAILURE
, "%i", outfd
);
2172 statusfd
= strtol (optarg
, &p
, 10);
2175 statusfp
= fdopen (statusfd
, "w");
2177 err (EXIT_FAILURE
, "%i", statusfd
);
2180 case OPT_STATUS_IGNORE
:
2181 parse_status_ignore (optarg
);
2184 printf ("%s (pwmc)\n\n"
2185 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016\n"
2187 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
2188 "Compile-time features:\n"
2189 #ifdef HAVE_LIBREADLINE
2204 #ifdef WITH_PINENTRY
2219 "\n", PACKAGE_STRING
, PACKAGE_BUGREPORT
);
2220 exit (EXIT_SUCCESS
);
2222 pinentry_path
= optarg
;
2225 usage (argv
[0], EXIT_SUCCESS
);
2229 case OPT_SIGN_KEYID
:
2230 sign_keyid
= optarg
;
2236 case OPT_STATUS_STATE
:
2239 case OPT_NO_PINENTRY
:
2242 #ifdef HAVE_LIBREADLINE
2243 case OPT_NO_INTERACTIVE
:
2248 usage (argv
[0], EXIT_FAILURE
);
2253 fprintf (stderr
, N_("%s: invalid argument for option '--%s'\n"),
2254 argv
[0], long_opts
[opt_index
].name
);
2255 usage (argv
[0], EXIT_FAILURE
);
2264 knownhosts
= optarg
;
2268 inquire_line
= optarg
;
2283 clientname
= optarg
;
2286 usage (argv
[0], EXIT_FAILURE
);
2290 #ifdef HAVE_LIBREADLINE
2291 if (isatty (STDIN_FILENO
) && !inquire
&& !inquire_line
&& !no_interactive
)
2296 rc
= pwmd_new (clientname
, &pwm
);
2300 filename
= argv
[optind
] ? pwmd_strdup (argv
[optind
]) : NULL
;
2301 if (no_pinentry
!= -1)
2302 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
2304 rc
= pwmd_getopt (pwm
, PWMD_OPTION_NO_PINENTRY
, &no_pinentry
);
2308 if (local_pin
!= -1)
2309 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local_pin
);
2311 rc
= pwmd_getopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, &local_pin
);
2315 pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TRIES
, tries
);
2317 fprintf (stderr
, N_("Connecting ...\n"));
2319 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
2320 socktype
= is_remote_url (url
);
2321 if (socktype
!= PWMD_SOCKET_LOCAL
)
2324 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2325 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, connect_timeout
);
2330 if (socktype
== PWMD_SOCKET_SSH
)
2333 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_CB
, knownhost_cb
);
2337 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_DATA
, clientname
);
2341 if (use_ssh_agent
== -1)
2342 rc
= pwmd_getopt (pwm
, PWMD_OPTION_SSH_AGENT
, &use_ssh_agent
);
2346 if (!getenv ("SSH_AUTH_SOCK") || identity
)
2349 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_AGENT
, use_ssh_agent
);
2356 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_NEEDS_PASSPHRASE
,
2361 if (ssh_passphrase_file
)
2366 if (stat (ssh_passphrase_file
, &st
) == -1)
2368 rc
= gpg_error_from_syserror ();
2369 fprintf(stderr
, "%s: %s\n", ssh_passphrase_file
,
2374 result
= pwmd_calloc (1, st
.st_size
+1);
2377 rc
= GPG_ERR_ENOMEM
;
2381 fd
= open (ssh_passphrase_file
, O_RDONLY
);
2384 len
= read (fd
, result
, st
.st_size
);
2385 if (len
== st
.st_size
)
2386 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_PASSPHRASE
, result
);
2388 rc
= gpg_error_from_syserror ();
2393 rc
= gpg_error_from_syserror ();
2401 fprintf(stderr
, "%s: %s\n", ssh_passphrase_file
,
2407 rc
= pwmd_connect (pwm
, url
, identity
, knownhosts
);
2413 if (tls_verify
!= -1)
2415 rc
= pwmd_setopt (pwm
, PWMD_OPTION_TLS_VERIFY
, tls_verify
);
2421 rc
= pwmd_setopt (pwm
, PWMD_OPTION_TLS_PRIORITY
, prio
);
2424 rc
= pwmd_connect (pwm
, url
, clientcert
, clientkey
, cacert
,
2430 rc
= pwmd_connect (pwm
, url
);
2432 rc
= pwmd_connect (pwm
, url
);
2438 fprintf (stderr
, N_("Connected.\n"));
2441 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2442 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, socket_timeout
);
2449 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
2450 "OPTION LOCK-TIMEOUT=%li", lock_timeout
);
2457 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
, "OPTION CLIENT-STATE=1");
2462 if (lock_on_open
!= -1)
2464 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCK_ON_OPEN
, lock_on_open
);
2469 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, NULL
, NULL
);
2475 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, timeout
);
2482 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_PATH
, pinentry_path
);
2489 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DISPLAY
, display
);
2496 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TTY
, tty
);
2503 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TERM
, ttytype
);
2510 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_CTYPE
, lcctype
);
2517 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_MESSAGES
, lcmessages
);
2524 rc
= pwmd_setopt (pwm
, PWMD_OPTION_STATUS_CB
, status_msg_cb
);
2531 rc
= open_command (filename
);
2536 #ifdef HAVE_LIBREADLINE
2539 rc
= do_interactive ();
2547 struct inquire_s
*inq
= NULL
;
2549 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2551 rc
= pwmd_command (pwm
, &result
, &len
, inquire_cb
, inq
, "%s", inquire
);
2557 if (fcntl (STDIN_FILENO
, F_SETFL
, O_NONBLOCK
) == -1)
2559 rc
= gpg_error_from_errno (errno
);
2567 rc
= process_cmd ();
2572 n
= read (STDIN_FILENO
, command
, sizeof (command
)-1);
2575 if (errno
== EAGAIN
)
2581 rc
= gpg_error_from_errno (errno
);
2592 if (!p
|| !*p
|| !strcasecmp (p
, "BYE"))
2596 struct inquire_s
*inq
= NULL
;
2597 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2600 rc
= parse_dotcommand (command
, &result
, &len
, inq
);
2610 fwrite (result
, 1, result
[len
- 1] == 0 ? len
- 1 : len
, outfp
);
2618 else if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
2619 (void) pwmd_command (pwm
, &result
, NULL
, NULL
, NULL
,
2620 "GETINFO last_error");
2622 #ifdef HAVE_LIBREADLINE
2625 wipememory (command
, 0, sizeof (command
));
2628 show_error (pwm
, rc
, result
);
2634 pwmd_free (filename
);
2635 parse_status_ignore (NULL
);
2636 if (connected
&& !quiet
)
2637 fprintf (stderr
, N_("Connection closed.\n"));
2639 exit (rc
? EXIT_FAILURE
: EXIT_SUCCESS
);