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>
43 #include "util-string.h"
44 #include "util-slist.h"
47 #include <gnutls/gnutls.h>
54 #ifdef HAVE_GETOPT_LONG
59 #include "getopt_long.h"
62 #ifdef HAVE_LIBREADLINE
63 #if defined(HAVE_READLINE_READLINE_H)
64 #include <readline/readline.h>
65 #elif defined(HAVE_READLINE_H)
67 #endif /* !defined(HAVE_READLINE_H) */
68 static int interactive_error
;
69 static int interactive
;
70 #endif /* HAVE_LIBREADLINE */
72 #ifdef HAVE_READLINE_HISTORY
73 #if defined(HAVE_READLINE_HISTORY_H)
74 #include <readline/history.h>
75 #elif defined(HAVE_HISTORY_H)
78 #endif /* HAVE_READLINE_HISTORY */
85 #define N_(msgid) gettext(msgid)
90 #define DEFAULT_STATUS_IGNORE "KEEPALIVE,GPGME,PASSPHRASE_INFO,PASSPHRASE_HINT"
91 #define DEFAULT_PIN_TIMEOUT 30
92 #define DEFAULT_PIN_TRIES 3
93 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
96 static int no_pinentry
;
98 static char *filename
;
101 static char *sign_keyid
;
102 static int symmetric
;
103 static char *keyparams
;
104 static char *keyfile
;
105 static char *new_keyfile
;
106 static char *sign_keyfile
;
108 static int local_pin
;
109 static int inquirefd
;
113 static char **status_ignore
;
120 size_t size
; // from stat(2).
147 struct slist_s
*userids
;
148 struct slist_s
*subkeys
;
151 static gpg_error_t
finalize ();
152 static gpg_error_t
set_inquire (int fd
, const char *line
,
153 struct inquire_s
**result
);
154 static gpg_error_t
parse_dotcommand (const char *line
, char **result
,
155 size_t * len
, struct inquire_s
*inq
);
156 static gpg_error_t
open_command (char *line
);
159 show_error (pwm_t
*pwm
, gpg_error_t rc
, const char *str
)
163 int e
= pwmd_gnutls_error (pwm
, &tlsstr
);
166 fprintf(stderr
, "TLS: %s\n", tlsstr
);
168 fprintf (stderr
, "ERR %i: %s%s%s%s", rc
, gpg_strerror (rc
),
169 str
? ": " : "", str
? str
: "", str
? "" : "\n");
176 pwmd_free (new_keyfile
);
177 pwmd_free (sign_keyfile
);
178 keyfile
= new_keyfile
= sign_keyfile
= NULL
;
182 usage (const char *pn
, int status
)
184 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
185 N_("Usage: pwmc [options] [file]\n"
187 " a url string to connect to (%s, see below)\n"
188 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
189 " --connect-timeout <seconds>\n"
190 " seconds before connecting to a remote host fails (0=disabled, 120)\n"
191 " --socket-timeout <seconds>\n"
192 " seconds before a remote command fails (0=disabled, 300)\n"
195 " --ca-cert <filename>\n"
196 " certificate authority (CA) used to sign the server cert\n"
197 " --client-cert <filename>\n"
198 " client certificate to use for authentication\n"
199 " --client-key <filename>\n"
200 " key file used to protect the client certificate\n"
201 " --tls-priority <string>\n"
202 " compression, cipher and hash algorithm string\n"
203 " (SECURE256:SECURE192:SECURE128:-VERS-SSL3.0)\n"
205 " verify the hostname against the server certificate\n"
206 " --tls-fingerprint <string>\n"
207 " a SHA-256 hash of the server fingerprint to verify against\n"
211 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
212 " --identity, -i <filename>\n"
213 " the ssh identity file to use for authentication\n"
214 " --knownhosts, -k <filename>\n"
215 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
216 " --ssh-needs-passphrase\n"
217 " prompt for a passphrase for the SSH identity file\n"
218 " --ssh-passphrase-file <filename>\n"
219 " read the SSH private key passphrase from filename\n"
222 " do not lock the data file upon opening it\n"
223 " --lock-timeout <N>\n"
224 " time in tenths of a second to wait for a locked data file (50)\n"
225 " --name, -n <string>\n"
226 " set the client name\n"
227 " --pinentry <path>\n"
228 " the full path to the pinentry binary\n"
229 " --local-pinentry\n"
230 " force using a local pinentry\n"
232 " disable pinentry both remotely and locally\n"
233 " --ttyname, -y <path>\n"
234 " tty that pinentry will use\n"
235 " --ttytype, -t <string>\n"
236 " pinentry terminal type (default is $TERM)\n"
238 " pinentry display (default is $DISPLAY)\n"
239 " --lc-ctype <string>\n"
240 " locale setting for pinentry\n"
241 " --lc-messages <string>\n"
242 " locale setting for pinentry\n"
244 " number of pinentry tries before failing (3)\n"
245 " --timeout <seconds>\n"
246 " pinentry timeout\n"
247 " --inquire <COMMAND>\n"
248 " the specified command (with any options) uses a server inquire while\n"
249 " command data is read via the inquire file descriptor (stdin)\n"
250 " --inquire-line, -L <STRING>\n"
251 " the initial line to send (i.e., element path) before the inquire data\n"
252 " --inquire-fd <FD>\n"
253 " read inquire data from the specified file descriptor (stdin)\n"
254 " --inquire-file <filename>\n"
255 " read inquire data from the specified filename\n"
256 " --output-fd <FD>\n"
257 " redirect command output to the specified file descriptor\n"
259 " send the SAVE command before exiting\n"
260 " --passphrase-file <filename>\n"
261 " obtain the passphrase from the specified filename\n"
262 " --new-passphrase-file <filename>\n"
263 " obtain the passphrase to save with from the specified filename\n"
264 " --sign-passphrase-file <filename>\n"
265 " obtain the passphrase to sign with (symmetric) from the specified filename\n"
266 " --key-params <filename>\n"
267 " key parameters to use for key generation (pwmd default)\n"
268 " --keyid <recipient>[,<recipient>]\n"
269 " the public key ID to u\n"
270 " --sign-keyid <string>\n"
271 " the key ID to sign the data file with\n"
273 " use conventional encryption with optional signer(s) for new files\n"
275 " disable showing of status messages from the server\n"
277 " enable receiving of client STATE status messages\n"
278 " --status-fd <FD>\n"
279 " redirect status messages to the specified file descriptor\n"
280 " --status-ignore <string[,...]>\n"
281 " prevent parsing of the specified status message keywords\n"
283 " disable showing of extra messages (implies --no-status)\n"
284 #ifdef HAVE_LIBREADLINE
285 " --no-interactive\n"
286 " disable interactive mode\n"
290 #ifdef DEFAULT_PWMD_SOCKET
296 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
298 "An optional url may be in the form of:\n"
299 " --url /path/to/socket\n"
300 " --url file://[path/to/socket]\n"
303 " --url ssh[46]://[username@]hostname[:port]\n"
304 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
308 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
309 " --client-key filename\n"
311 #ifdef HAVE_LIBREADLINE
313 "Interactive mode is used when input is from a terminal.\n"
320 inquire_cb (void *user
, const char *keyword
, gpg_error_t rc
,
321 char **data
, size_t * size
)
323 struct inquire_s
*inq
= user
;
325 int is_newpassword
= 0;
335 if (!strcmp (keyword
, "PASSPHRASE"))
337 else if (!strcmp (keyword
, "SIGN_PASSPHRASE"))
339 else if (!strcmp (keyword
, "NEW_PASSPHRASE"))
341 #ifdef HAVE_LIBREADLINE
342 else if (!strcmp (keyword
, "KEYPARAM") && !interactive
)
345 else if (!strcmp (keyword
, "KEYPARAM"))
349 if (!keyparams
|| !*keyparams
)
350 return gpg_error (GPG_ERR_INV_PARAMETER
);
352 fd
= open (keyparams
, O_RDONLY
);
355 fprintf (stderr
, "%s: %s\n", keyparams
, strerror (errno
));
356 return gpg_error_from_syserror ();
359 rc
= set_inquire (fd
, NULL
, &inq
);
367 fprintf (stderr
, N_("Using file '%s' as %s.\n"), keyparams
, keyword
);
372 if ((is_password
&& !keyfile
) || (is_newpassword
&& !new_keyfile
)
373 || (sign
&& !sign_keyfile
))
378 /* Try to use the local pinentry between inquires (new/sign/passphrase).
379 * If --no-pinentry was specified then the passphrase is read from the
380 * terminal as usual. */
381 pwmd_getopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, &local
);
382 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, 1);
383 rc
= pwmd_password (pwm
, keyword
, &tmp
, &inq
->len
);
384 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local
);
385 if (rc
&& gpg_err_code (rc
) != GPG_ERR_EOF
)
388 pwmd_free (inq
->line
);
392 return gpg_error (GPG_ERR_EOF
);
394 else if ((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
)
395 || (sign
&& sign_keyfile
))
400 fd
= open (sign_keyfile
, O_RDONLY
);
402 fd
= open (is_password
|| sign
? keyfile
: new_keyfile
, O_RDONLY
);
407 fprintf (stderr
, "%s: %s\n", sign_keyfile
, strerror (errno
));
409 fprintf (stderr
, "%s: %s\n", is_newpassword
? new_keyfile
410 : keyfile
, strerror (errno
));
411 return gpg_error_from_syserror ();
414 rc
= set_inquire (fd
, NULL
, &inq
);
422 fprintf (stderr
, N_("Using keyfile '%s' as %s.\n"),
423 sign
? sign_keyfile
: is_newpassword
? new_keyfile
426 #ifdef HAVE_LIBREADLINE
427 else if ((!inq
->last_keyword
|| strcmp (keyword
, inq
->last_keyword
))
428 && interactive
&& inq
->fd
== STDIN_FILENO
)
432 ("%sPress CTRL-D to send the current line. Press twice to end. %s:\n"),
433 inq
->last_keyword
? "\n" : "", keyword
);
434 pwmd_free (inq
->last_keyword
);
435 inq
->last_keyword
= pwmd_strdup (keyword
);
439 /* The first part of the command data. */
445 return inq
->fd
== -1 ? gpg_error (GPG_ERR_EOF
) : 0;
448 *size
= read (inq
->fd
, inq
->line
, ASSUAN_LINELENGTH
);
452 return gpg_error (gpg_error_from_syserror ());
456 else if (inq
->fd
!= STDIN_FILENO
&&
457 (is_newpassword
|| is_password
|| sign
|| is_keyparam
))
465 if (((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
)
466 || (sign
&& sign_keyfile
) || (keyparams
&& is_keyparam
))
467 && *size
== inq
->size
)
468 return gpg_error (GPG_ERR_EOF
);
470 return *size
? 0 : gpg_error (GPG_ERR_EOF
);
474 status_msg_cb (void *data
, const char *line
)
476 char *p
= strchr (line
, ' ');
479 /* Ignore status messages specified by the client via --status-ignore. */
480 for (s
= status_ignore
; s
&& *s
; s
++)
482 char *tmp
= strchr (line
, ' ');
483 size_t len
= tmp
? strlen (line
) - strlen (tmp
) : strlen (line
);
485 if (!strncmp (line
, *s
, len
) && len
== strlen (*s
))
489 #ifdef HAVE_LIBREADLINE
490 if (interactive
&& !strncmp (line
, "XFER ", 5)
492 if (!strncmp (line
, "XFER ", 5)
494 && *line
!= '#' && p
&& strchr (p
, ' ') && *++p
)
496 char *p1
= strchr (p
, ' ');
497 int a
= strtol (p
, NULL
, 10);
499 if (isdigit (*p
) && p1
)
501 int b
= strtol (p1
, NULL
, 10);
503 int t
= a
&& b
? a
* 100 / b
: 0;
505 strncpy (l
, line
, strlen (line
) - strlen (p
) - 1);
506 fprintf (statusfp
, "\rS:%s %i/%i %i%%%s", l
, a
, b
, t
,
513 fprintf (statusfp
, "S:%s\n", line
);
515 #ifdef HAVE_LIBREADLINE
524 return pwmd_process (pwm
);
529 knownhost_cb (void *data
, const char *host
, const char *key
, size_t len
)
533 pwmd_strdup_printf (N_
534 ("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"),
535 (char *) data
, host
, host
);
537 if (no_pinentry
&& !isatty (STDIN_FILENO
))
539 fprintf (stderr
, N_("Input is not from a terminal! Failing.\n"));
541 return GPG_ERR_ENOTTY
;
543 else if (no_pinentry
)
545 for (char *p
= buf
, len
= 0; *p
; p
++, len
++)
554 while (len
&& !isspace (*(--p
)))
563 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_PROMPT
, N_("Accept [y/N]:"));
567 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, buf
);
573 return pwmd_getpin (pwm
, NULL
, NULL
, NULL
, PWMD_PINENTRY_CONFIRM
);
577 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
579 is_remote_url (const char *str
)
582 return PWMD_SOCKET_LOCAL
;
585 if (strstr (str
, "ssh://") || strstr (str
, "ssh4://")
586 || strstr (str
, "ssh6://"))
587 return PWMD_SOCKET_SSH
;
591 if (strstr (str
, "tls://") || strstr (str
, "tls4://")
592 || strstr (str
, "tls6://"))
593 return PWMD_SOCKET_TLS
;
596 return PWMD_SOCKET_LOCAL
;
601 escape (const char *str
)
604 char *buf
= pwmd_malloc (ASSUAN_LINELENGTH
+ 1), *b
= buf
;
607 for (p
= str
; *p
; p
++, len
++)
609 if (len
== ASSUAN_LINELENGTH
)
653 free_inquire (struct inquire_s
*inq
)
658 pwmd_free (inq
->line
);
660 if (inq
->fd
!= -1 && inq
->fd
!= STDIN_FILENO
)
663 pwmd_free (inq
->last_keyword
);
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
;
750 get_readline_char (FILE *fp
)
753 && (!strncmp (rl_line_buffer
, ".set passphrase-file ", 16)
754 || !strncmp (rl_line_buffer
, ".set new-passphrase-file ", 20)
755 || !strncmp (rl_line_buffer
, ".set sign-passphrase-file ", 21)))
756 rl_inhibit_completion
= 0;
757 else if (rl_line_buffer
758 && !strncmp (rl_line_buffer
, ".redir ", 7))
760 char *p
= strchr (rl_line_buffer
, ' ');
762 if (strchr (++p
, ' '))
763 rl_inhibit_completion
= 1;
765 rl_inhibit_completion
= 0;
767 else if (rl_line_buffer
768 && !strncmp (rl_line_buffer
, ".read ", 6))
770 char *p
= rl_line_buffer
+ 6;
772 if (strstr (p
, "--prefix "))
774 p
= strstr (p
, "--prefix ");
781 if (!p
|| strchr (p
, ' '))
782 rl_inhibit_completion
= 1;
784 rl_inhibit_completion
= 0;
787 rl_inhibit_completion
= 1;
797 ("------------------------------------------------------------\n"
798 "Elements are TAB delimited. Type HELP for protocol commands.\n"
799 "Type .help for pwmc commands. Press CTRL-D to quit.\n"
800 "------------------------------------------------------------\n"));
805 parse_arg (const char *src
, char *dst
, size_t len
)
811 for (; s
&& *s
&& *s
!= ' ' && n
< len
; s
++, n
++)
819 parse_opt (char **line
, const char *opt
, gpg_error_t
* rc
)
821 static char result
[ASSUAN_LINELENGTH
] = { 0 }, *r
= result
;
822 char *s
= strstr (*line
, opt
);
832 size_t rlen
= strlen (opt
);
836 while (*p
&& *p
== ' ')
842 for (; *p
&& len
< sizeof (result
) - 1; p
++, rlen
++)
844 if (isspace (*p
) && !quote
)
847 if (*p
== '\"' && lastc
!= '\\')
860 if (len
>= sizeof (result
) - 1)
861 *rc
= GPG_ERR_LINE_TOO_LONG
;
866 while (*p
&& *p
== ' ')
877 read_command (const char *line
, char **result
, size_t * len
)
882 struct inquire_s
*inq
= NULL
;
883 char *p
= (char *) line
;
884 const char *prefix
= parse_opt (&p
, "--prefix", &rc
);
885 char filebuf
[ASSUAN_LINELENGTH
];
894 while (*p
&& isspace (*p
))
897 file
= parse_arg (p
, filebuf
, sizeof (filebuf
));
900 p
+= strlen (file
) + 1;
902 while (*p
&& isspace (*p
))
914 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
917 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\\ = \\)\n"));
921 fd
= open (file
, O_RDONLY
);
923 return gpg_error_from_syserror ();
925 rc
= set_inquire (fd
, prefix
&& *prefix
? prefix
: NULL
, &inq
);
932 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, "%s", p
);
938 redir_command (const char *line
)
940 const char *p
= line
;
942 gpg_error_t rc
= GPG_ERR_SYNTAX
;
944 struct inquire_s
*inq
= NULL
;
947 char filebuf
[ASSUAN_LINELENGTH
];
951 file
= parse_arg (p
, filebuf
, sizeof (filebuf
));
954 p
+= strlen (file
) + 1;
956 while (*p
&& isspace (*p
))
966 fprintf (stderr
, N_("Usage: .redir <filename> <command> [args]\n"));
970 fd
= open (file
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600);
972 return gpg_error_from_syserror ();
974 #ifdef HAVE_LIBREADLINE
975 rc
= set_inquire (interactive
? STDIN_FILENO
: inquirefd
, NULL
, &inq
);
977 rc
= set_inquire (inquirefd
, NULL
, &inq
);
985 rc
= parse_dotcommand (p
, &result
, &len
, inq
);
986 if (!rc
&& result
&& len
--)
987 { // null byte which is always appended
988 if (write (fd
, result
, len
) != len
)
989 rc
= GPG_ERR_TOO_SHORT
;
999 help_command (const char *line
)
1002 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
1003 " .redir <filename> <command>\n"
1004 " redirect the output of a command to the specified file\n"
1006 " .open <filename>\n"
1007 " open the specified filename losing any changes to the current one\n"
1009 " .read [--prefix <string>] <filename> <command> [args]\n"
1010 " obtain data from the specified filename for an inquire command\n"
1012 " .set help | <name> [<value>]\n"
1013 " set option <name> to <value>\n"
1016 " write changes of the file to disk\n"
1019 " change the passphrase of a data file\n"
1021 " .listkeys [--options] [pattern[,..]]\n"
1022 " show human readable output of the LISTKEYS command\n"
1025 " this help text\n"));
1030 open_command (char *line
)
1032 struct inquire_s
*inq
= NULL
;
1033 const char *file
= line
;
1037 while (file
&& isspace (*file
))
1040 if (!file
|| !*file
)
1042 fprintf (stderr
, N_("Usage: .open <filename>\n"));
1043 return GPG_ERR_SYNTAX
;
1046 #ifdef HAVE_LIBREADLINE
1047 if (interactive
|| !quiet
)
1051 fprintf (stderr
, N_("Opening data file \"%s\" ...\n"), file
);
1053 #ifdef HAVE_LIBREADLINE
1054 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1056 rc
= set_inquire (-1, NULL
, &inq
);
1061 pwmd_getopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, &local
);
1065 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1067 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, 1);
1070 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1073 rc
= pwmd_open (pwm
, file
, inquire_cb
, inq
);
1075 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local
);
1077 #ifdef HAVE_LIBREADLINE
1083 if (!rc
&& file
!= filename
)
1085 pwmd_free (filename
);
1086 filename
= pwmd_strdup (file
);
1093 set_command (const char *line
)
1096 char name
[256] = { 0 };
1097 char value
[512] = { 0 };
1100 const char *p
= line
;
1102 while (p
&& *p
&& isspace (*p
))
1105 namep
= parse_arg (p
, name
, sizeof (name
));
1106 if (!namep
|| !*namep
)
1108 fprintf (stderr
, N_("Usage: .set help | <name> [<value>]\n"));
1109 return GPG_ERR_SYNTAX
;
1112 p
+= strlen (namep
);
1113 while (p
&& *p
&& isspace (*p
))
1116 valuep
= parse_arg (p
, value
, sizeof (value
));
1118 if (!strcmp (name
, "passphrase-file") || !strcmp (name
, "new-passphrase-file")
1119 || !strcmp (name
, "sign-passphrase-file"))
1121 int is_newkeyfile
= 1;
1122 int sign
= !strcmp (name
, "sign-passphrase-file");
1124 if (!strcmp (name
, "passphrase-file") || sign
)
1129 pwmd_free (new_keyfile
);
1134 pwmd_free (sign_keyfile
);
1135 sign_keyfile
= NULL
;
1139 pwmd_free (keyfile
);
1146 new_keyfile
= pwmd_strdup (value
);
1148 sign_keyfile
= pwmd_strdup (value
);
1150 keyfile
= pwmd_strdup (value
);
1152 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1154 else if (!local_pin
&& !no_pinentry
)
1158 pwmd_socket_type (pwm
, &t
);
1159 if (t
== PWMD_SOCKET_LOCAL
)
1160 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1163 else if (!strcmp(name
, "pinentry-timeout"))
1166 int n
= strtol(valuep
, &e
, 10);
1169 return gpg_error (GPG_ERR_INV_VALUE
);
1172 n
= DEFAULT_PIN_TIMEOUT
;
1174 rc
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, n
);
1176 else if (!strcmp (name
, "help"))
1180 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1181 "delimited. When no value is specified the option is unset.\n\n"
1182 "passphrase-file [<filename>]\n"
1183 " set or unset the file to be used when a passphrase is required (*)\n"
1185 "new-passphrase-file [<filename>]\n"
1186 " set or unset the file to be used when a new passphrase is required (*)\n"
1188 "sign-passphrase-file [<filename>]\n"
1189 " set or unset the file to be used when a passphrase is required for\n"
1190 " signing (symmetric) (*)\n"
1192 "pinentry-timeout <seconds>\n"
1193 " the amount of seconds before pinentry gives up waiting for input\n"
1195 "* = the next protocol command will unset this value\n"
1199 rc
= GPG_ERR_UNKNOWN_OPTION
;
1205 do_save_passwd_command (const char *line
, int save
)
1207 struct inquire_s
*inq
= NULL
;
1211 #ifdef HAVE_LIBREADLINE
1212 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1214 rc
= set_inquire (-1, NULL
, &inq
);
1219 pwmd_getopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, &local
);
1221 if (new_keyfile
|| keyfile
|| sign_keyfile
)
1223 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1225 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, 1);
1228 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1233 rc
= pwmd_save (pwm
, line
, inquire_cb
, inq
);
1235 rc
= pwmd_passwd (pwm
, line
, inquire_cb
, inq
);
1238 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local
);
1240 #ifdef HAVE_LIBREADLINE
1250 save_command (const char *line
)
1252 return do_save_passwd_command (line
, 1);
1256 search_and_replace (char *str
, const char *s
, const char r
)
1260 p
= strstr (str
, s
);
1266 search_and_replace (str
, s
, r
);
1272 openpgp_unescape (char *str
)
1274 search_and_replace (str
, "\\x3a", ':');
1275 search_and_replace (str
, "\\x5c", '\\');
1280 free_listkeys (struct slist_s
*keys
)
1284 t
= slist_length (keys
);
1285 for (i
= 0; i
< t
; i
++)
1287 struct keyid_s
*key
= slist_nth_data (keys
, i
);
1290 nt
= slist_length (key
->userids
);
1291 for (n
= 0; n
< nt
; n
++)
1293 struct userid_s
*userid
= slist_nth_data (key
->userids
, n
);
1295 pwmd_free (userid
->userid
);
1296 pwmd_free (userid
->name
);
1297 pwmd_free (userid
->email
);
1298 pwmd_free (userid
->comment
);
1302 slist_free (key
->userids
);
1303 nt
= slist_length (key
->subkeys
);
1304 for (n
= 0; n
< nt
; n
++)
1306 struct keyid_s
*sub
= slist_nth_data (key
->subkeys
, n
);
1308 pwmd_free (sub
->keyid
);
1309 pwmd_free (sub
->fpr
);
1310 pwmd_free (sub
->card
);
1311 pwmd_free (sub
->curve
);
1315 slist_free (key
->subkeys
);
1323 openpgp_algorithm (struct keyid_s
*key
)
1344 return N_("Unknown");
1348 display_listkeys (struct slist_s
*keys
)
1352 t
= slist_length (keys
);
1353 for (i
= 0; i
< t
; i
++)
1355 struct keyid_s
*key
= slist_nth_data (keys
, i
);
1356 unsigned st
= slist_length (key
->subkeys
);
1358 unsigned ut
= slist_length (key
->userids
);
1361 for (u
= 0; u
< ut
; u
++)
1363 struct userid_s
*userid
= slist_nth_data (key
->userids
, u
);
1365 fprintf(stdout
, N_("User ID: %s\n"), userid
->userid
);
1368 for (s
= 0; s
< st
; s
++)
1370 struct keyid_s
*sub
= slist_nth_data (key
->subkeys
, s
);
1373 char expires
[11] = { 0 };
1374 char created
[11] = { 0 };
1378 tmp
= localtime (&sub
->expires
);
1379 strftime (expires
, sizeof (expires
), "%F", tmp
);
1382 tmp
= localtime (&sub
->created
);
1383 strftime (created
, sizeof (created
), "%F", tmp
);
1385 if (sub
->can_encrypt
)
1387 else if (sub
->can_sign
)
1389 else if (sub
->can_auth
)
1391 else if (sub
->can_certify
)
1395 " Subkey %u: %s [%s]%s%s %s-%u%s%s\n"
1396 " Created: %s %s%s\n"
1397 " Fingerprint: %s\n"
1402 sub
->secret
|| sub
->card
? "[P]" : "",
1403 sub
->revoked
? "[R]" : "",
1404 openpgp_algorithm (sub
),
1406 sub
->curve
? "-" : "",
1407 sub
->curve
? sub
->curve
: "",
1409 sub
->expired
? N_("Expired: ") : expires
[0] ? N_("Expires: ") : "",
1410 sub
->expired
|| expires
[0] ? expires
: "",
1412 sub
->card
? N_(" Card: ") : "",
1413 sub
->card
? sub
->card
: "",
1414 sub
->card
? "\n" : "");
1418 fprintf (stdout
, "\n");
1423 listkeys_command (const char *pattern
)
1427 char **lines
= NULL
, **p
;
1428 struct slist_s
*keys
= NULL
;
1430 rc
= pwmd_command (pwm
, &result
, NULL
, NULL
, NULL
, "LISTKEYS %s", pattern
);
1434 lines
= str_split (result
, "\n", 0);
1437 return GPG_ERR_ENOMEM
;
1439 for (p
= lines
; *p
; p
++)
1441 struct keyid_s
*key
;
1442 char **fields
= str_split (*p
, ":", 0);
1445 unsigned n_subkeys
= 0;
1446 struct slist_s
*tlist
;
1450 rc
= GPG_ERR_ENOMEM
;
1454 key
= pwmd_calloc (1, sizeof (struct keyid_s
));
1458 rc
= GPG_ERR_ENOMEM
;
1462 for (f
= i
= 0; i
< 17; i
++, f
++)
1467 b
= atoi (fields
[f
]) != 0;
1471 case 0: key
->revoked
= b
; break;
1472 case 1: key
->expired
= b
; break;
1473 case 4: key
->can_encrypt
= b
; break;
1474 case 5: key
->can_sign
= b
; break;
1475 case 7: key
->secret
= b
; break;
1476 case 16: n_subkeys
= strtoul (fields
[f
], NULL
, 10); break;
1482 for (s
= 0; s
< n_subkeys
; s
++)
1484 struct keyid_s
*sub
;
1487 sub
= pwmd_calloc (1, sizeof (struct keyid_s
));
1491 rc
= GPG_ERR_ENOMEM
;
1495 for (i
= 0; i
< 20; i
++, f
++)
1498 b
= atoi (fields
[f
]) != 0;
1502 case 0: sub
->revoked
= b
; break;
1503 case 1: sub
->expired
= b
; break;
1504 case 4: sub
->can_encrypt
= b
; break;
1505 case 5: sub
->can_sign
= b
; break;
1506 case 6: sub
->can_certify
= b
; break;
1507 case 7: sub
->secret
= b
; break;
1508 case 8: sub
->can_auth
= b
; break;
1509 case 11: sub
->algo
= atoi (fields
[f
]); break;
1510 case 12: sub
->bits
= atoi (fields
[f
]); break;
1511 case 13: sub
->keyid
= pwmd_strdup (fields
[f
]); break;
1512 case 14: sub
->fpr
= pwmd_strdup (fields
[f
]); break;
1513 case 16: sub
->created
= strtoul (fields
[f
], NULL
, 10); break;
1514 case 17: sub
->expires
= strtoul (fields
[f
], NULL
, 10); break;
1515 case 18: sub
->card
= fields
[f
] && strlen(fields
[f
]) > 1
1516 ? pwmd_strdup (fields
[f
]) : NULL
; break;
1517 case 19: sub
->curve
= strlen (fields
[f
]) > 1 ? pwmd_strdup (openpgp_unescape(fields
[f
])) : NULL
; break;
1523 tlist
= slist_append (key
->subkeys
, sub
);
1526 rc
= GPG_ERR_ENOMEM
;
1530 key
->subkeys
= tlist
;
1539 // Re-create a line containing the userIds.
1540 for (; f
< strv_length (fields
); f
++)
1542 struct userid_s
*userid
;
1544 userid
= pwmd_calloc (1, sizeof (struct userid_s
));
1547 rc
= GPG_ERR_ENOMEM
;
1558 userid
->userid
= pwmd_strdup (openpgp_unescape (fields
[f
++]));
1559 userid
->name
= pwmd_strdup (openpgp_unescape (fields
[f
++]));
1560 userid
->email
= pwmd_strdup (openpgp_unescape (fields
[f
++]));
1561 userid
->comment
= pwmd_strdup (openpgp_unescape (fields
[f
]));
1563 tlist
= slist_append (key
->userids
, userid
);
1566 rc
= GPG_ERR_ENOMEM
;
1570 key
->userids
= tlist
;
1577 tlist
= slist_append (keys
, key
);
1580 rc
= GPG_ERR_ENOMEM
;
1590 display_listkeys (keys
);
1592 free_listkeys (keys
);
1597 parse_dotcommand (const char *line
, char **result
,
1598 size_t * len
, struct inquire_s
*inq
)
1600 const char *p
= line
;
1603 if (!strncmp (p
, ".read", 5))
1604 rc
= read_command (p
+ 5, result
, len
);
1605 else if (!strncmp (p
, ".redir", 6))
1606 rc
= redir_command (p
+ 6);
1607 else if (!strncmp (p
, ".help", 5))
1608 rc
= help_command (p
+ 5);
1609 else if (!strncmp (p
, ".open", 5))
1610 rc
= open_command ((char *)p
+ 5);
1611 else if (!strncmp (p
, ".set", 4))
1612 rc
= set_command (p
+ 4);
1613 else if (!strncmp (p
, ".save", 5))
1614 rc
= do_save_passwd_command (p
+ 5, 1);
1615 else if (!strncmp (p
, ".passwd", 7))
1616 rc
= do_save_passwd_command (p
+ 7, 0);
1617 else if (!strncmp (p
, ".listkeys", 9))
1618 rc
= listkeys_command (p
+9);
1621 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, "%s", line
);
1622 #ifdef HAVE_LIBREADLINE
1627 #ifdef HAVE_LIBREADLINE
1631 if (!rc
&& !strncasecmp (line
, "RESET", 5))
1633 pwmd_free (filename
);
1641 #ifdef HAVE_LIBREADLINE
1642 #ifdef HAVE_READLINE_HISTORY
1644 add_history_item (const char *line
)
1646 HIST_ENTRY
**list
, *p
= NULL
;
1649 list
= history_list ();
1650 for (i
= 0; list
&& list
[i
]; i
++)
1652 if (!strcmp (list
[i
]->line
, line
))
1663 p
= remove_history (i
);
1664 s
= free_history_entry (p
);
1676 struct inquire_s
*inq
= NULL
;
1679 rc
= process_cmd ();
1683 rc
= set_inquire (STDIN_FILENO
, NULL
, &inq
);
1688 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1690 rl_event_hook
= &interactive_hook
;
1691 rl_getc_function
= get_readline_char
;
1692 rl_set_keyboard_input_timeout (100000);
1697 char *result
= NULL
;
1702 snprintf (buf
, sizeof (buf
), "pwmc%s%s> ",
1703 filename
? ":" : "", filename
? filename
: "");
1704 line
= readline (buf
);
1705 if (interactive_error
)
1708 rc
= interactive_error
;
1718 if (gpg_err_code (rc
) != GPG_ERR_CANCELED
&&
1719 gpg_err_code (rc
) != GPG_ERR_EOF
)
1720 fprintf (stderr
, "ERR %i: %s\n", rc
, gpg_strerror (rc
));
1730 #ifdef HAVE_READLINE_HISTORY
1731 add_history_item (line
);
1733 rc
= parse_dotcommand (line
, &result
, &len
, inq
);
1739 if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
1740 (void) pwmd_command (pwm
, &tmp
, NULL
, NULL
, NULL
,
1741 "GETINFO last_error");
1743 show_error (pwm
, rc
, tmp
);
1746 else if (result
&& len
)
1747 printf ("%s%s", result
, result
[len
- 1] != '\n' ? "\n" : "");
1761 #ifdef HAVE_LIBREADLINE
1768 fprintf (stderr
, "\n");
1776 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1777 p
= fgets (buf
, sizeof (buf
), stdin
);
1791 return GPG_ERR_CANCELED
;
1795 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1796 "CLEARCACHE %s", filename
);
1800 interactive_hook ();
1816 if (save
&& !filename
)
1820 ("No filename was specified on the command line. Aborting.\n"));
1821 return GPG_ERR_CANCELED
;
1824 if (save
&& filename
)
1827 pwmd_strdup_printf ("%s %s%s %s%s %s",
1828 symmetric
? "--symmetric" : "",
1829 keyid
? "--keyid=" : "",
1831 sign_keyid
? "--sign-keyid=" : "",
1832 sign_keyid
? sign_keyid
: "",
1833 keyparams
? "--inquire-keyparam" : "");
1835 #ifdef HAVE_LIBREADLINE
1836 if (!quiet
|| interactive
)
1842 fprintf (stderr
, "\n");
1843 fprintf (stderr
, N_("Saving changes ...\n"));
1846 rc
= save_command (args
);
1850 #ifdef HAVE_LIBREADLINE
1852 return rc
? rc
: quit
? 0 : GPG_ERR_CANCELED
;
1859 parse_status_ignore (char *str
)
1864 for (p
= status_ignore
; p
&& *p
; p
++)
1867 pwmd_free (status_ignore
);
1868 status_ignore
= NULL
;
1872 while ((s
= strsep (&str
, ",")))
1874 p
= pwmd_realloc (status_ignore
, (n
+ 2) * sizeof (char *));
1875 p
[n
++] = pwmd_strdup (s
);
1882 main (int argc
, char *argv
[])
1885 int status_state
= 0;
1888 char command
[ASSUAN_LINELENGTH
], *p
= NULL
;
1889 char *result
= NULL
;
1891 char *pinentry_path
= NULL
;
1892 char *display
= NULL
, *tty
= NULL
, *ttytype
= NULL
;
1893 char *lcctype
= NULL
, *lcmessages
= NULL
;
1894 int outfd
= STDOUT_FILENO
;
1895 FILE *outfp
= stdout
;
1896 FILE *inquirefp
= stdin
;
1897 int show_status
= 1;
1898 char *clientname
= "pwmc";
1899 char *inquire
= NULL
;
1900 char *inquire_line
= NULL
;
1903 int use_ssh_agent
= 1;
1904 char *knownhosts
= NULL
;
1905 char *identity
= NULL
;
1906 int needs_passphrase
= 0;
1907 char *ssh_passphrase_file
= NULL
;
1910 char *cacert
= NULL
;
1911 char *clientcert
= NULL
;
1912 char *clientkey
= NULL
;
1915 char *tls_fingerprint
= NULL
;
1917 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1918 pwmd_socket_t socktype
;
1919 long socket_timeout
= 300;
1920 int connect_timeout
= 120;
1922 #ifdef HAVE_LIBREADLINE
1923 int no_interactive
= 0;
1925 int lock_on_open
= 1;
1926 long lock_timeout
= 50;
1929 /* The order is important. */
1932 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1933 OPT_SOCKET_TIMEOUT
, OPT_CONNECT_TIMEOUT
,
1936 OPT_USE_SSH_AGENT
, OPT_IDENTITY
, OPT_KNOWNHOSTS
, OPT_SSH_NEEDS_PASSPHRASE
,
1937 OPT_SSH_PASSPHRASE_FILE
,
1940 OPT_CACERT
, OPT_CLIENTCERT
, OPT_CLIENTKEY
, OPT_PRIORITY
, OPT_VERIFY
,
1943 OPT_URL
, OPT_LOCAL
, OPT_TTYNAME
, OPT_TTYTYPE
, OPT_DISPLAY
, OPT_LC_CTYPE
,
1944 OPT_LC_MESSAGES
, OPT_TIMEOUT
, OPT_TRIES
, OPT_PINENTRY
, OPT_KEYFILE
,
1945 OPT_PASSPHRASE_FILE
, OPT_NEW_KEYFILE
, OPT_NEW_PASSPHRASE_FILE
,
1946 OPT_SIGN_KEYFILE
, OPT_SIGN_PASSPHRASE_FILE
, OPT_NOLOCK
, OPT_LOCK_TIMEOUT
,
1947 OPT_SAVE
, OPT_OUTPUT_FD
, OPT_INQUIRE
, OPT_INQUIRE_FD
, OPT_INQUIRE_FILE
,
1948 OPT_INQUIRE_LINE
, OPT_NO_STATUS
, OPT_STATUS_IGNORE
, OPT_STATUSFD
, OPT_NAME
,
1949 OPT_VERSION
, OPT_HELP
, OPT_KEYID
, OPT_SIGN_KEYID
, OPT_SYMMETRIC
,
1950 OPT_KEYPARAMS
, OPT_NO_PINENTRY
, OPT_QUIET
, OPT_STATUS_STATE
,
1951 #ifdef HAVE_LIBREADLINE
1955 const struct option long_opts
[] = {
1956 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1957 {"socket-timeout", 1, 0, 0},
1958 {"connect-timeout", 1, 0, 0},
1962 {"no-ssh-agent", 0, 0, 0},
1963 {"identity", 1, 0, 'i'},
1964 {"knownhosts", 1, 0, 'k'},
1965 {"ssh-needs-passphrase", 0, 0, 0},
1966 {"ssh-passphrase-file", 1, 0, 0},
1969 {"ca-cert", 1, 0, 0},
1970 {"client-cert", 1, 0, 0},
1971 {"client-key", 1, 0, 0},
1972 {"tls-priority", 1, 0, 0},
1973 {"tls-verify", 0, 0, 0},
1974 {"tls-fingerprint", 1, 0, 0},
1977 {"local-pinentry", 0, 0},
1978 {"ttyname", 1, 0, 'y'},
1979 {"ttytype", 1, 0, 't'},
1980 {"display", 1, 0, 'd'},
1981 {"lc-ctype", 1, 0, 0},
1982 {"lc-messages", 1, 0, 0},
1983 {"timeout", 1, 0, 0},
1985 {"pinentry", 1, 0, 0},
1986 {"key-file", 1, 0, 0},
1987 {"passphrase-file", 1, 0, 0},
1988 {"new-key-file", 1, 0, 0},
1989 {"new-passphrase-file", 1, 0, 0},
1990 {"sign-key-file", 1, 0, 0},
1991 {"sign-passphrase-file", 1, 0, 0},
1992 {"no-lock", 0, 0, 0},
1993 {"lock-timeout", 1, 0, 0},
1994 {"save", 0, 0, 'S'},
1995 {"output-fd", 1, 0, 0},
1996 {"inquire", 1, 0, 0},
1997 {"inquire-fd", 1, 0, 0},
1998 {"inquire-file", 1, 0, 0},
1999 {"inquire-line", 1, 0, 'L'},
2000 {"no-status", 0, 0, 0},
2001 {"status-ignore", 1, 0, 0},
2002 {"status-fd", 1, 0, 0},
2003 {"name", 1, 0, 'n'},
2004 {"version", 0, 0, 0},
2007 {"sign-keyid", 1, 0, 0},
2008 {"symmetric", 0, 0, 0},
2009 {"key-params", 1, 0, 0},
2010 {"no-pinentry", 0, 0, 0},
2012 {"status-state", 0, 0, 0},
2013 #ifdef HAVE_LIBREADLINE
2014 {"no-interactive", 0, 0},
2019 const char *optstring
= "L:y:t:d:P:I:Sn:i:k:s";
2021 const char *optstring
= "L:y:t:d:P:I:Sn:s";
2026 setlocale (LC_ALL
, "");
2027 bindtextdomain ("libpwmd", LOCALEDIR
);
2030 tries
= DEFAULT_PIN_TRIES
;
2031 inquirefd
= STDIN_FILENO
;
2032 statusfd
= STDERR_FILENO
;
2034 tmp
= pwmd_strdup (DEFAULT_STATUS_IGNORE
);
2035 parse_status_ignore (tmp
);
2039 getopt_long (argc
, argv
, optstring
, long_opts
, &opt_index
)) != -1)
2043 /* Handle long options without a short option part. */
2047 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2048 case OPT_SOCKET_TIMEOUT
:
2049 socket_timeout
= strtol (optarg
, &p
, 10);
2051 case OPT_CONNECT_TIMEOUT
:
2052 connect_timeout
= strtol (optarg
, &p
, 10);
2056 case OPT_USE_SSH_AGENT
:
2059 case OPT_SSH_NEEDS_PASSPHRASE
:
2060 needs_passphrase
= 1;
2062 case OPT_SSH_PASSPHRASE_FILE
:
2063 ssh_passphrase_file
= optarg
;
2070 case OPT_CLIENTCERT
:
2071 clientcert
= optarg
;
2083 tls_fingerprint
= optarg
;
2093 case OPT_PASSPHRASE_FILE
:
2094 keyfile
= pwmd_strdup (optarg
);
2096 case OPT_NEW_KEYFILE
:
2097 case OPT_NEW_PASSPHRASE_FILE
:
2098 new_keyfile
= pwmd_strdup (optarg
);
2100 case OPT_SIGN_KEYFILE
:
2101 case OPT_SIGN_PASSPHRASE_FILE
:
2102 sign_keyfile
= pwmd_strdup (optarg
);
2107 case OPT_LOCK_TIMEOUT
:
2108 lock_timeout
= strtol (optarg
, &p
, 10);
2117 lcctype
= pwmd_strdup (optarg
);
2119 case OPT_LC_MESSAGES
:
2120 lcmessages
= pwmd_strdup (optarg
);
2123 timeout
= strtol (optarg
, &p
, 10);
2126 tries
= strtol (optarg
, &p
, 10);
2129 inquire
= escape (optarg
);
2131 case OPT_INQUIRE_FD
:
2132 inquirefd
= strtol (optarg
, &p
, 10);
2135 inquirefp
= fdopen (inquirefd
, "r");
2137 err (EXIT_FAILURE
, "%i", inquirefd
);
2140 case OPT_INQUIRE_FILE
:
2141 inquirefd
= open (optarg
, O_RDONLY
);
2142 if (inquirefd
== -1)
2143 err (EXIT_FAILURE
, "%s", optarg
);
2144 inquirefp
= fdopen (inquirefd
, "r");
2147 outfd
= strtol (optarg
, &p
, 10);
2150 outfp
= fdopen (outfd
, "w");
2152 err (EXIT_FAILURE
, "%i", outfd
);
2159 statusfd
= strtol (optarg
, &p
, 10);
2162 statusfp
= fdopen (statusfd
, "w");
2164 err (EXIT_FAILURE
, "%i", statusfd
);
2167 case OPT_STATUS_IGNORE
:
2168 parse_status_ignore (optarg
);
2171 printf ("%s (pwmc)\n\n"
2172 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016\n"
2174 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
2175 "Compile-time features:\n"
2176 #ifdef HAVE_LIBREADLINE
2191 #ifdef WITH_PINENTRY
2206 "\n", PACKAGE_STRING
, PACKAGE_BUGREPORT
);
2207 exit (EXIT_SUCCESS
);
2209 pinentry_path
= optarg
;
2212 usage (argv
[0], EXIT_SUCCESS
);
2216 case OPT_SIGN_KEYID
:
2217 sign_keyid
= optarg
;
2223 case OPT_STATUS_STATE
:
2226 case OPT_NO_PINENTRY
:
2229 #ifdef HAVE_LIBREADLINE
2230 case OPT_NO_INTERACTIVE
:
2235 usage (argv
[0], EXIT_FAILURE
);
2240 fprintf (stderr
, N_("%s: invalid argument for option '--%s'\n"),
2241 argv
[0], long_opts
[opt_index
].name
);
2242 usage (argv
[0], EXIT_FAILURE
);
2251 knownhosts
= optarg
;
2255 inquire_line
= optarg
;
2270 clientname
= optarg
;
2273 usage (argv
[0], EXIT_FAILURE
);
2277 #ifdef HAVE_LIBREADLINE
2278 if (isatty (STDIN_FILENO
) && !inquire
&& !inquire_line
&& !no_interactive
)
2283 rc
= pwmd_new (clientname
, &pwm
);
2287 filename
= argv
[optind
] ? pwmd_strdup (argv
[optind
]) : NULL
;
2288 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
2292 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local_pin
);
2296 pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TRIES
, tries
);
2298 fprintf (stderr
, N_("Connecting ...\n"));
2300 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
2301 socktype
= is_remote_url (url
);
2302 if (socktype
!= PWMD_SOCKET_LOCAL
)
2305 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2306 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, connect_timeout
);
2311 if (socktype
== PWMD_SOCKET_SSH
)
2314 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_CB
, knownhost_cb
);
2318 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_DATA
, clientname
);
2322 if (!getenv ("SSH_AUTH_SOCK") || identity
)
2325 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_AGENT
, use_ssh_agent
);
2329 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_NEEDS_PASSPHRASE
,
2334 if (ssh_passphrase_file
)
2339 if (stat (ssh_passphrase_file
, &st
) == -1)
2341 rc
= gpg_error_from_syserror ();
2342 fprintf(stderr
, "%s: %s\n", ssh_passphrase_file
,
2347 result
= pwmd_calloc (1, st
.st_size
+1);
2350 rc
= GPG_ERR_ENOMEM
;
2354 fd
= open (ssh_passphrase_file
, O_RDONLY
);
2357 len
= read (fd
, result
, st
.st_size
);
2358 if (len
== st
.st_size
)
2359 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_PASSPHRASE
, result
);
2361 rc
= gpg_error_from_syserror ();
2366 rc
= gpg_error_from_syserror ();
2374 fprintf(stderr
, "%s: %s\n", ssh_passphrase_file
,
2380 rc
= pwmd_connect (pwm
, url
, identity
, knownhosts
);
2386 rc
= pwmd_setopt (pwm
, PWMD_OPTION_TLS_VERIFY
, tls_verify
);
2390 rc
= pwmd_connect (pwm
, url
, clientcert
, clientkey
, cacert
, prio
,
2396 rc
= pwmd_connect (pwm
, url
);
2398 rc
= pwmd_connect (pwm
, url
);
2404 fprintf (stderr
, N_("Connected.\n"));
2407 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2408 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, socket_timeout
);
2415 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
2416 "OPTION LOCK-TIMEOUT=%li", lock_timeout
);
2423 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
, "OPTION CLIENT-STATE=1");
2430 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCK_ON_OPEN
, 1);
2435 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, NULL
, NULL
);
2441 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, timeout
);
2448 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_PATH
, pinentry_path
);
2455 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DISPLAY
, display
);
2462 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TTY
, tty
);
2469 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TERM
, ttytype
);
2476 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_CTYPE
, lcctype
);
2483 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_MESSAGES
, lcmessages
);
2490 rc
= pwmd_setopt (pwm
, PWMD_OPTION_STATUS_CB
, status_msg_cb
);
2497 rc
= open_command (filename
);
2502 #ifdef HAVE_LIBREADLINE
2505 rc
= do_interactive ();
2513 struct inquire_s
*inq
= NULL
;
2515 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2517 rc
= pwmd_command (pwm
, &result
, &len
, inquire_cb
, inq
, "%s", inquire
);
2523 if (fcntl (STDIN_FILENO
, F_SETFL
, O_NONBLOCK
) == -1)
2525 rc
= gpg_error_from_errno (errno
);
2533 rc
= process_cmd ();
2538 n
= read (STDIN_FILENO
, command
, sizeof (command
)-1);
2541 if (errno
== EAGAIN
)
2547 rc
= gpg_error_from_errno (errno
);
2558 if (!p
|| !*p
|| !strcasecmp (p
, "BYE"))
2562 struct inquire_s
*inq
= NULL
;
2563 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2566 rc
= parse_dotcommand (command
, &result
, &len
, inq
);
2576 fwrite (result
, 1, result
[len
- 1] == 0 ? len
- 1 : len
, outfp
);
2584 else if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
2585 (void) pwmd_command (pwm
, &result
, NULL
, NULL
, NULL
,
2586 "GETINFO last_error");
2588 #ifdef HAVE_LIBREADLINE
2591 wipememory (command
, 0, sizeof (command
));
2594 show_error (pwm
, rc
, result
);
2600 pwmd_free (filename
);
2601 parse_status_ignore (NULL
);
2602 if (connected
&& !quiet
)
2603 fprintf (stderr
, N_("Connection closed.\n"));
2605 exit (rc
? EXIT_FAILURE
: EXIT_SUCCESS
);