2 Copyright (C) 2006-2016, 2017 Ben Kibbey <bjk@luxsci.net>
4 This file is part of libpwmd.
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
34 #include <sys/types.h>
44 #include <sys/select.h>
48 #include "util-string.h"
49 #include "util-slist.h"
52 #include <gnutls/gnutls.h>
59 #ifdef HAVE_GETOPT_LONG
64 #include "getopt_long.h"
67 #ifdef HAVE_LIBREADLINE
68 #if defined(HAVE_READLINE_READLINE_H)
69 #include <readline/readline.h>
70 #elif defined(HAVE_READLINE_H)
72 #endif /* !defined(HAVE_READLINE_H) */
73 static int interactive_error
;
74 static int interactive
;
75 #endif /* HAVE_LIBREADLINE */
77 #ifdef HAVE_READLINE_HISTORY
78 #if defined(HAVE_READLINE_HISTORY_H)
79 #include <readline/history.h>
80 #elif defined(HAVE_HISTORY_H)
83 #endif /* HAVE_READLINE_HISTORY */
90 #define N_(msgid) gettext(msgid)
95 #define DEFAULT_STATUS_IGNORE "KEEPALIVE,GPGME,PASSPHRASE_INFO,PASSPHRASE_HINT"
96 #define DEFAULT_PIN_TIMEOUT 30
97 #define DEFAULT_PIN_TRIES 3
99 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
109 static int no_pinentry
;
111 static char *filename
;
114 static char *sign_keyid
;
115 static int symmetric
;
116 static char *keyparams
;
117 static char *keyfile
;
118 static char *new_keyfile
;
119 static char *sign_keyfile
;
121 static int local_pin
;
122 static int inquirefd
;
126 static char **status_ignore
;
133 size_t size
; // from stat(2).
161 struct slist_s
*userids
;
162 struct slist_s
*subkeys
;
165 static gpg_error_t
finalize ();
166 static gpg_error_t
set_inquire (int fd
, const char *line
,
167 struct inquire_s
**result
);
168 static gpg_error_t
parse_dotcommand (const char *line
, char **result
,
169 size_t * len
, struct inquire_s
*inq
);
170 static gpg_error_t
open_command (char *line
);
172 char *strsep (char **, const char *);
175 int err (int, const char *, ...);
179 show_error (pwm_t
*h
, gpg_error_t rc
, const char *str
)
183 int e
= pwmd_gnutls_error (h
, &tlsstr
);
186 fprintf(stderr
, "TLS: %s\n", tlsstr
);
190 fprintf (stderr
, "ERR %i: %s%s%s%s", rc
, gpg_strerror (rc
),
191 str
? ": " : "", str
? str
: "", str
? "" : "\n");
198 pwmd_free (new_keyfile
);
199 pwmd_free (sign_keyfile
);
200 keyfile
= new_keyfile
= sign_keyfile
= NULL
;
204 usage (const char *pn
, int status
)
206 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
207 N_("Usage: %s [options] [file]\n"
209 " a url string to connect to (%s, see below)\n"
210 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
211 " --connect-timeout <seconds>\n"
212 " seconds before connecting to a remote host fails (0=disabled, 120)\n"
213 " --socket-timeout <seconds>\n"
214 " seconds before a remote command fails (0=disabled, 300)\n"
217 " --ca-cert <filename>\n"
218 " certificate authority (CA) used to sign the server cert\n"
219 " --client-cert <filename>\n"
220 " client certificate to use for authentication\n"
221 " --client-key <filename>\n"
222 " key file used to protect the client certificate\n"
223 " --tls-priority <string>\n"
224 " compression, cipher and hash algorithm string\n"
225 " (SECURE256:SECURE192:SECURE128:-VERS-SSL3.0:-VERS-TLS1.0)\n"
227 " disable verifying the hostname against the server certificate\n"
228 " --tls-fingerprint <string>\n"
229 " a SHA-256 hash of the server fingerprint to verify against\n"
233 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
234 " --identity, -i <filename>\n"
235 " the ssh identity file to use for authentication\n"
236 " --knownhosts, -k <filename>\n"
237 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
238 " --ssh-needs-passphrase\n"
239 " prompt for a passphrase for the SSH identity file\n"
240 " --ssh-passphrase-file <filename>\n"
241 " read the SSH private key passphrase from filename\n"
244 " do not lock the data file upon opening it\n"
245 " --lock-timeout <N>\n"
246 " time in tenths of a second to wait for a locked data file (50)\n"
247 " --name, -n <string>\n"
248 " set the client name\n"
249 " --pinentry <path>\n"
250 " the full path to the pinentry binary\n"
251 " --local-pinentry\n"
252 " force using a local pinentry\n"
254 " disable pinentry both remotely and locally\n"
255 " --ttyname, -y <path>\n"
256 " tty that pinentry will use\n"
257 " --ttytype, -t <string>\n"
258 " pinentry terminal type (default is $TERM)\n"
260 " pinentry display (default is $DISPLAY)\n"
261 " --lc-ctype <string>\n"
262 " locale setting for pinentry\n"
263 " --lc-messages <string>\n"
264 " locale setting for pinentry\n"
266 " number of pinentry tries before failing (3)\n"
267 " --timeout <seconds>\n"
268 " pinentry timeout\n"
269 " --inquire <COMMAND>\n"
270 " the specified command (with any options) uses a server inquire while\n"
271 " command data is read via the inquire file descriptor (stdin)\n"
272 " --inquire-line, -L <STRING>\n"
273 " the initial line to send (i.e., element path) before the inquire data\n"
274 " --inquire-fd <FD>\n"
275 " read inquire data from the specified file descriptor (stdin)\n"
276 " --inquire-file <filename>\n"
277 " read inquire data from the specified filename\n"
278 " --output-fd <FD>\n"
279 " redirect command output to the specified file descriptor\n"
281 " send the SAVE command before exiting\n"
282 " --passphrase-file <filename>\n"
283 " obtain the passphrase from the specified filename\n"
284 " --new-passphrase-file <filename>\n"
285 " obtain the passphrase to save with from the specified filename\n"
286 " --sign-passphrase-file <filename>\n"
287 " obtain the passphrase to sign with from the specified filename\n"
288 " --key-params <filename>\n"
289 " key parameters to use for key generation (pwmd default)\n"
290 " --keyid <recipient>[,<recipient>]\n"
291 " the public key ID to u\n"
292 " --sign-keyid <string>\n"
293 " the key ID to sign the data file with\n"
295 " use conventional encryption with optional signer(s) for new files\n"
297 " disable showing of status messages from the server\n"
299 " enable receiving of client STATE status messages\n"
300 " --status-fd <FD>\n"
301 " redirect status messages to the specified file descriptor\n"
302 " --status-ignore <string[,...]>\n"
303 " prevent parsing of the specified status message keywords\n"
305 " disable showing of extra messages (implies --no-status)\n"
306 #ifdef HAVE_LIBREADLINE
307 " --no-interactive\n"
308 " disable interactive mode\n"
313 #ifdef DEFAULT_PWMD_SOCKET
319 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
321 "An optional url may be in the form of:\n"
322 " --url /path/to/socket\n"
323 " --url file://[/path/to/socket]\n"
326 " --url ssh[46]://[username@]hostname[:port] (uses ssh-agent)\n"
327 " -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
331 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
332 " --client-key filename\n"
334 #ifdef HAVE_LIBREADLINE
336 "Interactive mode is used when input is from a terminal.\n"
343 inquire_cb (void *user
, const char *keyword
, gpg_error_t rc
,
344 char **data
, size_t * size
)
346 struct inquire_s
*inq
= user
;
348 int is_newpassword
= 0;
358 if (!strcmp (keyword
, "PASSPHRASE"))
360 else if (!strcmp (keyword
, "SIGN_PASSPHRASE"))
362 else if (!strcmp (keyword
, "NEW_PASSPHRASE"))
364 #ifdef HAVE_LIBREADLINE
365 else if (!strcmp (keyword
, "KEYPARAM") && !interactive
)
368 else if (!strcmp (keyword
, "KEYPARAM"))
372 if (!keyparams
|| !*keyparams
)
373 return gpg_error (GPG_ERR_INV_PARAMETER
);
375 fd
= open (keyparams
, O_RDONLY
);
378 fprintf (stderr
, "%s: %s\n", keyparams
, strerror (errno
));
379 return gpg_error_from_syserror ();
382 rc
= set_inquire (fd
, NULL
, &inq
);
390 fprintf (stderr
, N_("Using file '%s' as %s.\n"), keyparams
, keyword
);
395 if ((is_password
&& !keyfile
) || (is_newpassword
&& !new_keyfile
)
396 || (sign
&& !sign_keyfile
))
401 /* Try to use the local pinentry between inquires (new/sign/passphrase).
402 * If --no-pinentry was specified then the passphrase is read from the
403 * terminal as usual. */
404 pwmd_getopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, &local
);
405 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, 1);
406 rc
= pwmd_password (pwm
, keyword
, &tmp
, &inq
->len
);
407 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local
);
408 if (rc
&& gpg_err_code (rc
) != GPG_ERR_EOF
)
411 pwmd_free (inq
->line
);
415 return gpg_error (GPG_ERR_EOF
);
417 else if ((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
)
418 || (sign
&& sign_keyfile
))
423 fd
= open (sign_keyfile
, O_RDONLY
);
425 fd
= open (is_password
|| sign
? keyfile
: new_keyfile
, O_RDONLY
);
430 fprintf (stderr
, "%s: %s\n", sign_keyfile
, strerror (errno
));
432 fprintf (stderr
, "%s: %s\n", is_newpassword
? new_keyfile
433 : keyfile
, strerror (errno
));
434 return gpg_error_from_syserror ();
437 rc
= set_inquire (fd
, NULL
, &inq
);
445 fprintf (stderr
, N_("Using keyfile '%s' as %s.\n"),
446 sign
? sign_keyfile
: is_newpassword
? new_keyfile
449 #ifdef HAVE_LIBREADLINE
450 else if ((!inq
->last_keyword
|| strcmp (keyword
, inq
->last_keyword
))
451 && interactive
&& inq
->fd
== STDIN_FILENO
)
455 ("%sPress CTRL-D to send the current line. Press twice to end. %s:\n"),
456 inq
->last_keyword
? "\n" : "", keyword
);
457 pwmd_free (inq
->last_keyword
);
458 inq
->last_keyword
= pwmd_strdup (keyword
);
462 /* The first part of the command data. */
468 return inq
->fd
== -1 ? gpg_error (GPG_ERR_EOF
) : 0;
471 *size
= read (inq
->fd
, inq
->line
, ASSUAN_LINELENGTH
);
475 return gpg_error (gpg_error_from_syserror ());
479 else if (inq
->fd
!= STDIN_FILENO
&&
480 (is_newpassword
|| is_password
|| sign
|| is_keyparam
))
488 if (((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
)
489 || (sign
&& sign_keyfile
) || (keyparams
&& is_keyparam
))
490 && *size
== inq
->size
)
491 return gpg_error (GPG_ERR_EOF
);
493 return *size
? 0 : gpg_error (GPG_ERR_EOF
);
497 status_msg_cb (void *data
, const char *line
)
499 char *p
= strchr (line
, ' ');
504 /* Ignore status messages specified by the client via --status-ignore. */
505 for (s
= status_ignore
; s
&& *s
; s
++)
507 char *tmp
= strchr (line
, ' ');
508 size_t len
= tmp
? strlen (line
) - strlen (tmp
) : strlen (line
);
510 if (!strncmp (line
, *s
, len
) && len
== strlen (*s
))
514 #ifdef HAVE_LIBREADLINE
515 if (interactive
&& !strncmp (line
, "XFER ", 5)
517 if (!strncmp (line
, "XFER ", 5)
519 && *line
!= '#' && p
&& strchr (p
, ' ') && *++p
)
521 char *p1
= strchr (p
, ' ');
522 int a
= strtol (p
, NULL
, 10);
524 if (isdigit (*p
) && p1
)
526 int b
= strtol (p1
, NULL
, 10);
528 int t
= a
&& b
? a
* 100 / b
: 0;
530 strncpy (l
, line
, strlen (line
) - strlen (p
) - 1);
531 fprintf (statusfp
, "\rS:%s %i/%i %i%%%s", l
, a
, b
, t
,
538 fprintf (statusfp
, "S:%s\n", line
);
540 #ifdef HAVE_LIBREADLINE
549 return pwmd_process (pwm
);
552 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
554 is_remote_url (const char *str
)
557 return PWMD_SOCKET_LOCAL
;
560 if (strstr (str
, "ssh://") || strstr (str
, "ssh4://")
561 || strstr (str
, "ssh6://"))
562 return PWMD_SOCKET_SSH
;
566 if (strstr (str
, "tls://") || strstr (str
, "tls4://")
567 || strstr (str
, "tls6://"))
568 return PWMD_SOCKET_TLS
;
571 return PWMD_SOCKET_LOCAL
;
576 escape (const char *str
)
579 char *buf
= pwmd_malloc (ASSUAN_LINELENGTH
+ 1), *b
= buf
;
582 for (p
= str
; *p
; p
++, len
++)
584 if (len
== ASSUAN_LINELENGTH
)
628 free_inquire (struct inquire_s
*inq
)
633 pwmd_free (inq
->line
);
635 if (inq
->fd
!= -1 && inq
->fd
!= STDIN_FILENO
)
638 pwmd_free (inq
->last_keyword
);
642 /* When *result is not NULL it is updated to the new values and not
645 set_inquire (int fd
, const char *line
, struct inquire_s
**result
)
647 struct inquire_s inq
= { 0 };
648 struct stat st
= { 0 };
653 if (fstat (fd
, &st
) == -1)
654 return gpg_error_from_syserror ();
656 inq
.size
= st
.st_size
;
660 inq
.line
= pwmd_calloc (1, ASSUAN_LINELENGTH
);
662 return GPG_ERR_ENOMEM
;
666 char *s
= escape (line
);
670 pwmd_free (inq
.line
);
671 return GPG_ERR_ENOMEM
;
674 if (strlen (s
) >= ASSUAN_LINELENGTH
)
676 pwmd_free (inq
.line
);
678 return GPG_ERR_LINE_TOO_LONG
;
681 strncpy (inq
.line
, s
, ASSUAN_LINELENGTH
- 1);
682 inq
.len
= strlen (s
);
686 rc
= pwmd_setopt (pwm
, PWMD_OPTION_INQUIRE_TOTAL
,
687 st
.st_size
? st
.st_size
+ strlen (inq
.line
) : 0);
690 pwmd_free (inq
.line
);
695 *result
= pwmd_malloc (sizeof (struct inquire_s
));
698 if ((*result
)->fd
!= -1 && (*result
)->fd
!= STDIN_FILENO
)
699 close ((*result
)->fd
);
701 pwmd_free ((*result
)->line
);
702 (*result
)->line
= NULL
;
707 memcpy (*result
, &inq
, sizeof (struct inquire_s
));
708 memset (&inq
, 0, sizeof (struct inquire_s
));
712 #ifdef HAVE_LIBREADLINE
714 interactive_hook (void)
716 interactive_error
= process_cmd ();
718 if (interactive_error
)
719 rl_event_hook
= NULL
;
725 get_readline_char (FILE *fp
)
728 && (!strncmp (rl_line_buffer
, ".set passphrase-file ", 16)
729 || !strncmp (rl_line_buffer
, ".set new-passphrase-file ", 20)
730 || !strncmp (rl_line_buffer
, ".set sign-passphrase-file ", 21)))
731 rl_inhibit_completion
= 0;
732 else if (rl_line_buffer
733 && !strncmp (rl_line_buffer
, ".redir ", 7))
735 char *p
= strchr (rl_line_buffer
, ' ');
737 if (p
&& strchr (++p
, ' '))
738 rl_inhibit_completion
= 1;
740 rl_inhibit_completion
= 0;
742 else if (rl_line_buffer
743 && !strncmp (rl_line_buffer
, ".read ", 6))
745 char *p
= rl_line_buffer
+ 6;
747 if (strstr (p
, "--prefix "))
749 p
= strstr (p
, "--prefix ");
756 if (!p
|| strchr (p
, ' '))
757 rl_inhibit_completion
= 1;
759 rl_inhibit_completion
= 0;
762 rl_inhibit_completion
= 1;
772 ("------------------------------------------------------------\n"
773 "Elements are TAB delimited. Type HELP for protocol commands.\n"
774 "Type .help for pwmc commands. Press CTRL-D to quit.\n"
775 "------------------------------------------------------------\n"));
780 parse_arg (const char *src
, char *dst
, size_t len
)
786 for (; s
&& *s
&& *s
!= ' ' && n
< len
; s
++, n
++)
794 parse_opt (char **line
, const char *opt
, gpg_error_t
* rc
)
796 static char result
[ASSUAN_LINELENGTH
] = { 0 }, *r
= result
;
797 char *s
= strstr (*line
, opt
);
807 size_t rlen
= strlen (opt
);
811 while (*p
&& *p
== ' ')
817 for (; *p
&& len
< sizeof (result
) - 1; p
++, rlen
++)
819 if (isspace (*p
) && !quote
)
822 if (*p
== '\"' && lastc
!= '\\')
835 if (len
>= sizeof (result
) - 1)
836 *rc
= GPG_ERR_LINE_TOO_LONG
;
841 while (*p
&& *p
== ' ')
852 read_command (const char *line
, char **result
, size_t * len
)
857 struct inquire_s
*inq
= NULL
;
858 char *p
= (char *) line
;
859 const char *prefix
= parse_opt (&p
, "--prefix", &rc
);
860 char filebuf
[ASSUAN_LINELENGTH
];
869 while (*p
&& isspace (*p
))
872 file
= parse_arg (p
, filebuf
, sizeof (filebuf
));
875 p
+= strlen (file
) + 1;
877 while (*p
&& isspace (*p
))
889 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
892 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\\ = \\)\n"));
896 fd
= open (file
, O_RDONLY
);
898 return gpg_error_from_syserror ();
900 rc
= set_inquire (fd
, prefix
&& *prefix
? prefix
: NULL
, &inq
);
907 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, "%s", p
);
913 redir_command (const char *line
)
915 const char *p
= line
;
917 gpg_error_t rc
= GPG_ERR_SYNTAX
;
919 struct inquire_s
*inq
= NULL
;
922 char filebuf
[ASSUAN_LINELENGTH
];
926 file
= parse_arg (p
, filebuf
, sizeof (filebuf
));
929 p
+= strlen (file
) + 1;
931 while (*p
&& isspace (*p
))
941 fprintf (stderr
, N_("Usage: .redir <filename> <command> [args]\n"));
945 fd
= open (file
, 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
)
978 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
979 " .redir <filename> <command>\n"
980 " redirect the output of a command to the specified file\n"
982 " .open <filename>\n"
983 " open the specified filename losing any changes to the current one\n"
985 " .read [--prefix <string>] <filename> <command> [args]\n"
986 " obtain data from the specified filename for an inquire command\n"
988 " .set help | <name> [<value>]\n"
989 " set option <name> to <value>\n"
992 " generate a new key\n"
995 " write changes of the file to disk\n"
998 " change the passphrase of a data file\n"
1000 " .listkeys [--options] [pattern[,..]]\n"
1001 " show human readable output of the LISTKEYS command\n"
1004 " this help text\n"));
1009 open_command (char *line
)
1011 struct inquire_s
*inq
= NULL
;
1012 char *file
= line
, *tmp
= NULL
;
1016 while (file
&& isspace (*file
))
1021 char *p
= strrchr (file
, ' ');
1025 while (isspace (*p
))
1030 file
= tmp
= pwmd_strdup (file
+ (strlen (file
)-strlen (p
)));
1031 if (!file
|| !*file
)
1042 if (!file
|| !*file
)
1044 fprintf (stderr
, N_("Usage: .open [--options] <filename>\n"));
1045 return GPG_ERR_SYNTAX
;
1048 #ifdef HAVE_LIBREADLINE
1049 if (interactive
|| !quiet
)
1053 fprintf (stderr
, N_("Opening data file \"%s\" ...\n"), file
);
1055 #ifdef HAVE_LIBREADLINE
1056 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1058 rc
= set_inquire (-1, NULL
, &inq
);
1067 pwmd_getopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, &local
);
1071 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1073 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, 1);
1076 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1079 rc
= pwmd_open (pwm
, file
, inquire_cb
, inq
);
1081 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local
);
1083 #ifdef HAVE_LIBREADLINE
1093 pwmd_free (filename
);
1098 char *p
= pwmd_strdup (file
);
1100 pwmd_free (filename
);
1103 rc
= GPG_ERR_ENOMEM
;
1109 pwmd_free (filename
);
1117 set_command (const char *line
)
1120 char name
[256] = { 0 };
1121 char value
[512] = { 0 };
1124 const char *p
= line
;
1126 while (p
&& *p
&& isspace (*p
))
1129 namep
= parse_arg (p
, name
, sizeof (name
));
1130 if (!namep
|| !*namep
)
1132 fprintf (stderr
, N_("Usage: .set help | <name> [<value>]\n"));
1133 return GPG_ERR_SYNTAX
;
1136 p
+= strlen (namep
);
1137 while (p
&& *p
&& isspace (*p
))
1140 valuep
= parse_arg (p
, value
, sizeof (value
));
1142 if (!strcmp (name
, "passphrase-file") || !strcmp (name
, "new-passphrase-file")
1143 || !strcmp (name
, "sign-passphrase-file"))
1145 int is_newkeyfile
= 1;
1146 int sign
= !strcmp (name
, "sign-passphrase-file");
1148 if (!strcmp (name
, "passphrase-file") || sign
)
1153 pwmd_free (new_keyfile
);
1158 pwmd_free (sign_keyfile
);
1159 sign_keyfile
= NULL
;
1163 pwmd_free (keyfile
);
1170 new_keyfile
= pwmd_strdup (value
);
1172 sign_keyfile
= pwmd_strdup (value
);
1174 keyfile
= pwmd_strdup (value
);
1176 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1178 else if (!local_pin
&& !no_pinentry
)
1182 pwmd_socket_type (pwm
, &t
);
1183 if (t
== PWMD_SOCKET_LOCAL
)
1184 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1187 else if (!strcmp(name
, "pinentry-timeout"))
1190 int n
= strtol(valuep
, &e
, 10);
1193 return gpg_error (GPG_ERR_INV_VALUE
);
1196 n
= DEFAULT_PIN_TIMEOUT
;
1198 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, n
);
1200 else if (!strcmp (name
, "help"))
1204 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1205 "delimited. When no value is specified the option is unset.\n\n"
1206 "passphrase-file [<filename>]\n"
1207 " set or unset the file to be used when a passphrase is required (*)\n"
1209 "new-passphrase-file [<filename>]\n"
1210 " set or unset the file to be used when a new passphrase is required (*)\n"
1212 "sign-passphrase-file [<filename>]\n"
1213 " set or unset the file to be used when a passphrase is required for\n"
1214 " signing (symmetric) (*)\n"
1216 "pinentry-timeout <seconds>\n"
1217 " the amount of seconds before pinentry gives up waiting for input\n"
1219 "* = the next protocol command will unset this value\n"
1223 rc
= GPG_ERR_UNKNOWN_OPTION
;
1229 do_save_passwd_command (const char *line
, int which
)
1231 struct inquire_s
*inq
= NULL
;
1235 #ifdef HAVE_LIBREADLINE
1236 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1238 rc
= set_inquire (-1, NULL
, &inq
);
1243 pwmd_getopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, &local
);
1245 if (new_keyfile
|| keyfile
|| sign_keyfile
)
1247 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1249 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, 1);
1252 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1256 if (which
== SAVE_WHICH_SAVE
)
1257 rc
= pwmd_save (pwm
, line
, inquire_cb
, inq
);
1258 else if (which
== SAVE_WHICH_PASSWD
)
1259 rc
= pwmd_passwd (pwm
, line
, inquire_cb
, inq
);
1261 rc
= pwmd_genkey (pwm
, line
, inquire_cb
, inq
);
1264 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local
);
1266 #ifdef HAVE_LIBREADLINE
1276 save_command (const char *line
)
1278 return do_save_passwd_command (line
, SAVE_WHICH_SAVE
);
1282 search_and_replace (char *str
, const char *s
, const char r
)
1286 p
= strstr (str
, s
);
1292 search_and_replace (str
, s
, r
);
1298 openpgp_unescape (char *str
)
1300 search_and_replace (str
, "\\x3a", ':');
1301 search_and_replace (str
, "\\x5c", '\\');
1306 free_listkeys (struct slist_s
*keys
)
1310 t
= slist_length (keys
);
1311 for (i
= 0; i
< t
; i
++)
1313 struct keyid_s
*key
= slist_nth_data (keys
, i
);
1316 nt
= slist_length (key
->userids
);
1317 for (n
= 0; n
< nt
; n
++)
1319 struct userid_s
*userid
= slist_nth_data (key
->userids
, n
);
1321 pwmd_free (userid
->userid
);
1322 pwmd_free (userid
->name
);
1323 pwmd_free (userid
->email
);
1324 pwmd_free (userid
->comment
);
1328 slist_free (key
->userids
);
1329 nt
= slist_length (key
->subkeys
);
1330 for (n
= 0; n
< nt
; n
++)
1332 struct keyid_s
*sub
= slist_nth_data (key
->subkeys
, n
);
1334 pwmd_free (sub
->keyid
);
1335 pwmd_free (sub
->fpr
);
1336 pwmd_free (sub
->grip
);
1337 pwmd_free (sub
->card
);
1338 pwmd_free (sub
->curve
);
1342 slist_free (key
->subkeys
);
1350 openpgp_algorithm (struct keyid_s
*key
)
1371 return N_("Unknown");
1375 display_listkeys (struct slist_s
*keys
)
1379 t
= slist_length (keys
);
1380 for (i
= 0; i
< t
; i
++)
1382 struct keyid_s
*key
= slist_nth_data (keys
, i
);
1383 unsigned st
= slist_length (key
->subkeys
);
1385 unsigned ut
= slist_length (key
->userids
);
1388 for (u
= 0; u
< ut
; u
++)
1390 struct userid_s
*userid
= slist_nth_data (key
->userids
, u
);
1392 fprintf(stdout
, N_("User ID: %s\n"), userid
->userid
);
1395 for (s
= 0; s
< st
; s
++)
1397 struct keyid_s
*sub
= slist_nth_data (key
->subkeys
, s
);
1399 const char *caps
= NULL
;
1400 char expires
[11] = { 0 };
1401 char created
[11] = { 0 };
1405 tmp
= localtime (&sub
->expires
);
1406 strftime (expires
, sizeof (expires
), "%F", tmp
);
1409 tmp
= localtime (&sub
->created
);
1410 strftime (created
, sizeof (created
), "%F", tmp
);
1412 if (sub
->can_encrypt
)
1414 else if (sub
->can_sign
)
1416 else if (sub
->can_auth
)
1418 else if (sub
->can_certify
)
1422 " Subkey %u: %s [%s]%s%s %s-%u%s%s\n"
1423 " Created: %s %s%s\n"
1424 " Fingerprint: %s\n"
1430 sub
->secret
|| sub
->card
? "[P]" : "",
1431 sub
->revoked
? "[R]" : "",
1432 openpgp_algorithm (sub
),
1434 sub
->curve
? "-" : "",
1435 sub
->curve
? sub
->curve
: "",
1437 sub
->expired
? N_("Expired: ") : expires
[0] ? N_("Expires: ") : "",
1438 sub
->expired
|| expires
[0] ? expires
: "",
1441 sub
->card
? N_(" Card: ") : "",
1442 sub
->card
? sub
->card
: "",
1443 sub
->card
? "\n" : "");
1447 fprintf (stdout
, "\n");
1452 listkeys_command (const char *pattern
)
1456 char **lines
= NULL
, **p
;
1457 struct slist_s
*keys
= NULL
;
1459 rc
= pwmd_command (pwm
, &result
, NULL
, NULL
, NULL
, "LISTKEYS %s", pattern
);
1463 lines
= str_split (result
, "\n", 0);
1466 return GPG_ERR_ENOMEM
;
1468 for (p
= lines
; *p
; p
++)
1470 struct keyid_s
*key
;
1471 char **fields
= str_split (*p
, ":", 0);
1474 unsigned n_subkeys
= 0;
1475 struct slist_s
*tlist
;
1479 rc
= GPG_ERR_ENOMEM
;
1483 key
= pwmd_calloc (1, sizeof (struct keyid_s
));
1487 rc
= GPG_ERR_ENOMEM
;
1491 for (f
= i
= 0; i
< 17; i
++, f
++)
1496 b
= atoi (fields
[f
]) != 0;
1500 case 0: key
->revoked
= b
; break;
1501 case 1: key
->expired
= b
; break;
1502 case 4: key
->can_encrypt
= b
; break;
1503 case 5: key
->can_sign
= b
; break;
1504 case 7: key
->secret
= b
; break;
1505 case 16: n_subkeys
= strtoul (fields
[f
], NULL
, 10); break;
1511 for (s
= 0; s
< n_subkeys
; s
++)
1513 struct keyid_s
*sub
;
1516 sub
= pwmd_calloc (1, sizeof (struct keyid_s
));
1520 rc
= GPG_ERR_ENOMEM
;
1524 for (i
= 0; i
< 20; i
++, f
++)
1527 b
= atoi (fields
[f
]) != 0;
1531 case 0: sub
->revoked
= b
; break;
1532 case 1: sub
->expired
= b
; break;
1533 case 4: sub
->can_encrypt
= b
; break;
1534 case 5: sub
->can_sign
= b
; break;
1535 case 6: sub
->can_certify
= b
; break;
1536 case 7: sub
->secret
= b
; break;
1537 case 8: sub
->can_auth
= b
; break;
1538 case 11: sub
->algo
= atoi (fields
[f
]); break;
1539 case 12: sub
->bits
= atoi (fields
[f
]); break;
1540 case 13: sub
->keyid
= pwmd_strdup (fields
[f
]); break;
1541 case 14: sub
->fpr
= pwmd_strdup (fields
[f
]); break;
1542 case 15: sub
->grip
= pwmd_strdup (fields
[f
]); break;
1543 case 16: sub
->created
= strtoul (fields
[f
], NULL
, 10); break;
1544 case 17: sub
->expires
= strtoul (fields
[f
], NULL
, 10); break;
1545 case 18: sub
->card
= fields
[f
] && strlen(fields
[f
]) > 1
1546 ? pwmd_strdup (fields
[f
]) : NULL
; break;
1547 case 19: sub
->curve
= strlen (fields
[f
]) > 1 ? pwmd_strdup (openpgp_unescape(fields
[f
])) : NULL
; break;
1553 tlist
= slist_append (key
->subkeys
, sub
);
1556 rc
= GPG_ERR_ENOMEM
;
1560 key
->subkeys
= tlist
;
1569 // Re-create a line containing the userIds.
1570 for (; f
< strv_length (fields
); f
++)
1572 struct userid_s
*userid
;
1574 userid
= pwmd_calloc (1, sizeof (struct userid_s
));
1577 rc
= GPG_ERR_ENOMEM
;
1588 userid
->userid
= pwmd_strdup (openpgp_unescape (fields
[f
++]));
1589 userid
->name
= pwmd_strdup (openpgp_unescape (fields
[f
++]));
1590 userid
->email
= pwmd_strdup (openpgp_unescape (fields
[f
++]));
1591 userid
->comment
= pwmd_strdup (openpgp_unescape (fields
[f
]));
1593 tlist
= slist_append (key
->userids
, userid
);
1596 rc
= GPG_ERR_ENOMEM
;
1600 key
->userids
= tlist
;
1607 tlist
= slist_append (keys
, key
);
1610 rc
= GPG_ERR_ENOMEM
;
1620 display_listkeys (keys
);
1622 free_listkeys (keys
);
1627 parse_dotcommand (const char *line
, char **result
,
1628 size_t * len
, struct inquire_s
*inq
)
1630 const char *p
= line
;
1633 if (!strncmp (p
, ".read", 5))
1634 rc
= read_command (p
+ 5, result
, len
);
1635 else if (!strncmp (p
, ".redir", 6))
1636 rc
= redir_command (p
+ 6);
1637 else if (!strncmp (p
, ".help", 5))
1638 rc
= help_command (p
+ 5);
1639 else if (!strncmp (p
, ".open", 5))
1640 rc
= open_command ((char *)p
+ 5);
1641 else if (!strncmp (p
, ".set", 4))
1642 rc
= set_command (p
+ 4);
1643 else if (!strncmp (p
, ".save", 5))
1644 rc
= do_save_passwd_command (p
+ 5, SAVE_WHICH_SAVE
);
1645 else if (!strncmp (p
, ".passwd", 7))
1646 rc
= do_save_passwd_command (p
+ 7, SAVE_WHICH_PASSWD
);
1647 else if (!strncmp (p
, ".genkey", 7))
1648 rc
= do_save_passwd_command (p
+ 7, SAVE_WHICH_GENKEY
);
1649 else if (!strncmp (p
, ".listkeys", 9))
1650 rc
= listkeys_command (p
+9);
1653 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, "%s", line
);
1654 #ifdef HAVE_LIBREADLINE
1659 #ifdef HAVE_LIBREADLINE
1663 if (!rc
&& !strncasecmp (line
, "RESET", 5))
1665 pwmd_free (filename
);
1673 #ifdef HAVE_LIBREADLINE
1674 #ifdef HAVE_READLINE_HISTORY
1676 add_history_item (const char *line
)
1678 HIST_ENTRY
**list
, *p
= NULL
;
1681 list
= history_list ();
1682 for (i
= 0; list
&& list
[i
]; i
++)
1684 if (!strcmp (list
[i
]->line
, line
))
1695 p
= remove_history (i
);
1696 #ifdef HAVE_FREE_HISTORY_ENTRY
1697 s
= free_history_entry (p
);
1710 struct inquire_s
*inq
= NULL
;
1713 rc
= process_cmd ();
1717 rc
= set_inquire (STDIN_FILENO
, NULL
, &inq
);
1722 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1724 rl_event_hook
= &interactive_hook
;
1725 rl_getc_function
= get_readline_char
;
1726 rl_set_keyboard_input_timeout (100000);
1731 char *result
= NULL
;
1735 snprintf (buf
, sizeof (buf
), "pwmc%s%s> ",
1736 filename
? ":" : "", filename
? filename
: "");
1737 line
= readline (buf
);
1738 if (interactive_error
)
1741 rc
= interactive_error
;
1751 if (gpg_err_code (rc
) != GPG_ERR_CANCELED
&&
1752 gpg_err_code (rc
) != GPG_ERR_EOF
)
1753 fprintf (stderr
, "ERR %i: %s\n", rc
, gpg_strerror (rc
));
1763 #ifdef HAVE_READLINE_HISTORY
1764 add_history_item (line
);
1766 rc
= parse_dotcommand (line
, &result
, &len
, inq
);
1772 if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
1773 (void) pwmd_command (pwm
, &tmp
, NULL
, NULL
, NULL
,
1774 "GETINFO last_error");
1776 show_error (pwm
, rc
, tmp
);
1779 else if (result
&& len
)
1780 printf ("%s%s", result
, result
[len
- 1] != '\n' ? "\n" : "");
1794 #ifdef HAVE_LIBREADLINE
1801 fprintf (stderr
, "\n");
1809 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1810 p
= fgets (buf
, sizeof (buf
), stdin
);
1824 return GPG_ERR_CANCELED
;
1828 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1829 "CLEARCACHE %s", filename
);
1833 interactive_hook ();
1849 if (save
&& !filename
)
1853 ("No filename was specified on the command line. Aborting.\n"));
1854 return GPG_ERR_CANCELED
;
1857 if (save
&& filename
)
1860 pwmd_strdup_printf ("%s %s%s %s%s %s",
1861 symmetric
? "--symmetric" : "",
1862 keyid
? "--keyid=" : "",
1864 sign_keyid
? "--sign-keyid=" : "",
1865 sign_keyid
? sign_keyid
: "",
1866 keyparams
? "--inquire-keyparam" : "");
1868 #ifdef HAVE_LIBREADLINE
1869 if (!quiet
|| interactive
)
1875 fprintf (stderr
, "\n");
1876 fprintf (stderr
, N_("Saving changes ...\n"));
1879 rc
= save_command (args
);
1883 #ifdef HAVE_LIBREADLINE
1885 return rc
? rc
: quit
? 0 : GPG_ERR_CANCELED
;
1892 parse_status_ignore (char *str
)
1896 strv_free (status_ignore
);
1897 status_ignore
= NULL
;
1901 while ((s
= strsep (&str
, ",")))
1903 char **p
= strv_cat (status_ignore
, pwmd_strdup (s
));
1907 strv_free (status_ignore
);
1908 status_ignore
= NULL
;
1916 main (int argc
, char *argv
[])
1919 int status_state
= 0;
1922 char command
[ASSUAN_LINELENGTH
], *p
= NULL
;
1923 char *result
= NULL
;
1925 char *pinentry_path
= NULL
;
1926 char *display
= NULL
, *tty
= NULL
, *ttytype
= NULL
;
1927 char *lcctype
= NULL
, *lcmessages
= NULL
;
1928 int outfd
= STDOUT_FILENO
;
1929 FILE *outfp
= stdout
;
1930 int show_status
= 1;
1931 const char *clientname
= "pwmc";
1932 char *inquire
= NULL
;
1933 char *inquire_line
= NULL
;
1936 int use_ssh_agent
= -1;
1937 char *knownhosts
= NULL
;
1938 char *identity
= NULL
;
1939 int needs_passphrase
= 0;
1940 char *ssh_passphrase_file
= NULL
;
1943 char *cacert
= NULL
;
1944 char *clientcert
= NULL
;
1945 char *clientkey
= NULL
;
1947 int tls_verify
= -1;
1948 char *tls_fingerprint
= NULL
;
1950 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1951 pwmd_socket_t socktype
;
1952 long socket_timeout
= 300;
1953 int connect_timeout
= 120;
1955 #ifdef HAVE_LIBREADLINE
1956 int no_interactive
= 0;
1958 int lock_on_open
= -1;
1959 long lock_timeout
= 50;
1962 /* The order is important. */
1965 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1966 OPT_SOCKET_TIMEOUT
, OPT_CONNECT_TIMEOUT
,
1969 OPT_USE_SSH_AGENT
, OPT_IDENTITY
, OPT_KNOWNHOSTS
, OPT_SSH_NEEDS_PASSPHRASE
,
1970 OPT_SSH_PASSPHRASE_FILE
,
1973 OPT_CACERT
, OPT_CLIENTCERT
, OPT_CLIENTKEY
, OPT_PRIORITY
, OPT_VERIFY
,
1976 OPT_URL
, OPT_LOCAL
, OPT_TTYNAME
, OPT_TTYTYPE
, OPT_DISPLAY
, OPT_LC_CTYPE
,
1977 OPT_LC_MESSAGES
, OPT_TIMEOUT
, OPT_TRIES
, OPT_PINENTRY
, OPT_KEYFILE
,
1978 OPT_PASSPHRASE_FILE
, OPT_NEW_KEYFILE
, OPT_NEW_PASSPHRASE_FILE
,
1979 OPT_SIGN_KEYFILE
, OPT_SIGN_PASSPHRASE_FILE
, OPT_NOLOCK
, OPT_LOCK_TIMEOUT
,
1980 OPT_SAVE
, OPT_OUTPUT_FD
, OPT_INQUIRE
, OPT_INQUIRE_FD
, OPT_INQUIRE_FILE
,
1981 OPT_INQUIRE_LINE
, OPT_NO_STATUS
, OPT_STATUS_IGNORE
, OPT_STATUSFD
, OPT_NAME
,
1982 OPT_VERSION
, OPT_HELP
, OPT_KEYID
, OPT_SIGN_KEYID
, OPT_SYMMETRIC
,
1983 OPT_KEYPARAMS
, OPT_NO_PINENTRY
, OPT_QUIET
, OPT_STATUS_STATE
,
1984 #ifdef HAVE_LIBREADLINE
1988 const struct option long_opts
[] = {
1989 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1990 {"socket-timeout", 1, 0, 0},
1991 {"connect-timeout", 1, 0, 0},
1995 {"no-ssh-agent", 0, 0, 0},
1996 {"identity", 1, 0, 'i'},
1997 {"knownhosts", 1, 0, 'k'},
1998 {"ssh-needs-passphrase", 0, 0, 0},
1999 {"ssh-passphrase-file", 1, 0, 0},
2002 {"ca-cert", 1, 0, 0},
2003 {"client-cert", 1, 0, 0},
2004 {"client-key", 1, 0, 0},
2005 {"tls-priority", 1, 0, 0},
2006 {"no-tls-verify", 0, 0, 0},
2007 {"tls-fingerprint", 1, 0, 0},
2010 {"local-pinentry", 0, 0},
2011 {"ttyname", 1, 0, 'y'},
2012 {"ttytype", 1, 0, 't'},
2013 {"display", 1, 0, 'd'},
2014 {"lc-ctype", 1, 0, 0},
2015 {"lc-messages", 1, 0, 0},
2016 {"timeout", 1, 0, 0},
2018 {"pinentry", 1, 0, 0},
2019 {"key-file", 1, 0, 0},
2020 {"passphrase-file", 1, 0, 0},
2021 {"new-key-file", 1, 0, 0},
2022 {"new-passphrase-file", 1, 0, 0},
2023 {"sign-key-file", 1, 0, 0},
2024 {"sign-passphrase-file", 1, 0, 0},
2025 {"no-lock", 0, 0, 0},
2026 {"lock-timeout", 1, 0, 0},
2027 {"save", 0, 0, 'S'},
2028 {"output-fd", 1, 0, 0},
2029 {"inquire", 1, 0, 0},
2030 {"inquire-fd", 1, 0, 0},
2031 {"inquire-file", 1, 0, 0},
2032 {"inquire-line", 1, 0, 'L'},
2033 {"no-status", 0, 0, 0},
2034 {"status-ignore", 1, 0, 0},
2035 {"status-fd", 1, 0, 0},
2036 {"name", 1, 0, 'n'},
2037 {"version", 0, 0, 0},
2040 {"sign-keyid", 1, 0, 0},
2041 {"symmetric", 0, 0, 0},
2042 {"key-params", 1, 0, 0},
2043 {"no-pinentry", 0, 0, 0},
2045 {"status-state", 0, 0, 0},
2046 #ifdef HAVE_LIBREADLINE
2047 {"no-interactive", 0, 0},
2052 const char *optstring
= "L:y:t:d:P:I:Sn:i:k:s";
2054 const char *optstring
= "L:y:t:d:P:I:Sn:s";
2059 setlocale (LC_ALL
, "");
2060 bindtextdomain ("libpwmd", LOCALEDIR
);
2063 tries
= DEFAULT_PIN_TRIES
;
2064 inquirefd
= STDIN_FILENO
;
2065 statusfd
= STDERR_FILENO
;
2067 tmp
= pwmd_strdup (DEFAULT_STATUS_IGNORE
);
2068 parse_status_ignore (tmp
);
2074 getopt_long (argc
, argv
, optstring
, long_opts
, &opt_index
)) != -1)
2078 /* Handle long options without a short option part. */
2082 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2083 case OPT_SOCKET_TIMEOUT
:
2084 socket_timeout
= strtol (optarg
, &p
, 10);
2086 case OPT_CONNECT_TIMEOUT
:
2087 connect_timeout
= strtol (optarg
, &p
, 10);
2091 case OPT_USE_SSH_AGENT
:
2094 case OPT_SSH_NEEDS_PASSPHRASE
:
2095 needs_passphrase
= 1;
2097 case OPT_SSH_PASSPHRASE_FILE
:
2098 ssh_passphrase_file
= optarg
;
2105 case OPT_CLIENTCERT
:
2106 clientcert
= optarg
;
2118 tls_fingerprint
= optarg
;
2128 case OPT_PASSPHRASE_FILE
:
2129 keyfile
= pwmd_strdup (optarg
);
2131 case OPT_NEW_KEYFILE
:
2132 case OPT_NEW_PASSPHRASE_FILE
:
2133 new_keyfile
= pwmd_strdup (optarg
);
2135 case OPT_SIGN_KEYFILE
:
2136 case OPT_SIGN_PASSPHRASE_FILE
:
2137 sign_keyfile
= pwmd_strdup (optarg
);
2142 case OPT_LOCK_TIMEOUT
:
2143 lock_timeout
= strtol (optarg
, &p
, 10);
2152 lcctype
= pwmd_strdup (optarg
);
2154 case OPT_LC_MESSAGES
:
2155 lcmessages
= pwmd_strdup (optarg
);
2158 timeout
= strtol (optarg
, &p
, 10);
2161 tries
= strtol (optarg
, &p
, 10);
2164 inquire
= escape (optarg
);
2166 case OPT_INQUIRE_FD
:
2167 inquirefd
= strtol (optarg
, &p
, 10);
2169 case OPT_INQUIRE_FILE
:
2170 inquirefd
= open (optarg
, O_RDONLY
);
2171 if (inquirefd
== -1)
2172 err (EXIT_FAILURE
, "%s", optarg
);
2175 outfd
= strtol (optarg
, &p
, 10);
2178 outfp
= fdopen (outfd
, "w");
2180 err (EXIT_FAILURE
, "%i", outfd
);
2187 statusfd
= strtol (optarg
, &p
, 10);
2190 statusfp
= fdopen (statusfd
, "w");
2192 err (EXIT_FAILURE
, "%i", statusfd
);
2195 case OPT_STATUS_IGNORE
:
2196 parse_status_ignore (optarg
);
2199 printf ("%s (pwmc)\n\n"
2200 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017\n"
2202 "Released under the terms of the LGPL v2.1. Use at your own risk.\n\n"
2203 "Compile-time features:\n"
2204 #ifdef HAVE_LIBREADLINE
2219 #ifdef WITH_PINENTRY
2234 "\n", PACKAGE_STRING
, PACKAGE_BUGREPORT
);
2235 exit (EXIT_SUCCESS
);
2237 pinentry_path
= optarg
;
2240 usage (argv
[0], EXIT_SUCCESS
);
2244 case OPT_SIGN_KEYID
:
2245 sign_keyid
= optarg
;
2251 case OPT_STATUS_STATE
:
2254 case OPT_NO_PINENTRY
:
2257 #ifdef HAVE_LIBREADLINE
2258 case OPT_NO_INTERACTIVE
:
2263 usage (argv
[0], EXIT_FAILURE
);
2268 fprintf (stderr
, N_("%s: invalid argument for option '--%s'\n"),
2269 argv
[0], long_opts
[opt_index
].name
);
2270 usage (argv
[0], EXIT_FAILURE
);
2279 knownhosts
= optarg
;
2283 inquire_line
= optarg
;
2298 clientname
= optarg
;
2301 usage (argv
[0], EXIT_FAILURE
);
2305 #ifdef HAVE_LIBREADLINE
2306 if (isatty (STDIN_FILENO
) && !inquire
&& !inquire_line
&& !no_interactive
)
2311 rc
= pwmd_new (clientname
, &pwm
);
2315 filename
= argv
[optind
] ? pwmd_strdup (argv
[optind
]) : NULL
;
2316 if (no_pinentry
!= -1)
2317 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
2319 rc
= pwmd_getopt (pwm
, PWMD_OPTION_NO_PINENTRY
, &no_pinentry
);
2323 if (local_pin
!= -1)
2324 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local_pin
);
2326 rc
= pwmd_getopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, &local_pin
);
2330 pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TRIES
, tries
);
2332 fprintf (stderr
, N_("Connecting ...\n"));
2334 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
2335 socktype
= is_remote_url (url
);
2336 if (socktype
!= PWMD_SOCKET_LOCAL
)
2339 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2340 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, connect_timeout
);
2345 if (socktype
== PWMD_SOCKET_SSH
)
2348 if (use_ssh_agent
== -1)
2349 rc
= pwmd_getopt (pwm
, PWMD_OPTION_SSH_AGENT
, &use_ssh_agent
);
2353 if (!getenv ("SSH_AUTH_SOCK") || identity
)
2356 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_AGENT
, use_ssh_agent
);
2363 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_NEEDS_PASSPHRASE
,
2368 if (ssh_passphrase_file
)
2373 if (stat (ssh_passphrase_file
, &st
) == -1)
2375 rc
= gpg_error_from_syserror ();
2376 fprintf(stderr
, "%s: %s\n", ssh_passphrase_file
,
2381 result
= pwmd_calloc (1, st
.st_size
+1);
2384 rc
= GPG_ERR_ENOMEM
;
2388 fd
= open (ssh_passphrase_file
, O_RDONLY
);
2391 len
= read (fd
, result
, st
.st_size
);
2392 if (len
== st
.st_size
)
2393 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_PASSPHRASE
, result
);
2395 rc
= gpg_error_from_syserror ();
2400 rc
= gpg_error_from_syserror ();
2408 fprintf(stderr
, "%s: %s\n", ssh_passphrase_file
,
2414 rc
= pwmd_connect (pwm
, url
, identity
, knownhosts
);
2420 if (tls_verify
!= -1)
2422 rc
= pwmd_setopt (pwm
, PWMD_OPTION_TLS_VERIFY
, tls_verify
);
2428 rc
= pwmd_setopt (pwm
, PWMD_OPTION_TLS_PRIORITY
, prio
);
2431 rc
= pwmd_connect (pwm
, url
, clientcert
, clientkey
, cacert
,
2437 rc
= pwmd_connect (pwm
, url
);
2439 rc
= pwmd_connect (pwm
, url
);
2445 fprintf (stderr
, N_("Connected.\n"));
2448 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2449 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, socket_timeout
);
2456 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
2457 "OPTION LOCK-TIMEOUT=%li", lock_timeout
);
2464 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
, "OPTION CLIENT-STATE=1");
2469 if (lock_on_open
!= -1)
2471 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCK_ON_OPEN
, lock_on_open
);
2476 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, NULL
, NULL
);
2482 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, timeout
);
2489 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_PATH
, pinentry_path
);
2496 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DISPLAY
, display
);
2503 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TTY
, tty
);
2510 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TERM
, ttytype
);
2517 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_CTYPE
, lcctype
);
2524 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_MESSAGES
, lcmessages
);
2531 rc
= pwmd_setopt (pwm
, PWMD_OPTION_STATUS_CB
, status_msg_cb
);
2538 rc
= open_command (filename
);
2543 #ifdef HAVE_LIBREADLINE
2546 rc
= do_interactive ();
2554 struct inquire_s
*inq
= NULL
;
2556 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2558 rc
= pwmd_command (pwm
, &result
, &len
, inquire_cb
, inq
, "%s", inquire
);
2565 if (fcntl (STDIN_FILENO
, F_SETFL
, O_NONBLOCK
, 1) == -1)
2567 rc
= gpg_error_from_errno (errno
);
2576 rc
= process_cmd ();
2581 n
= read (STDIN_FILENO
, command
, sizeof (command
)-1);
2584 if (errno
== EAGAIN
)
2594 rc
= gpg_error_from_errno (errno
);
2605 if (!p
|| !*p
|| !strcasecmp (p
, "BYE"))
2609 struct inquire_s
*inq
= NULL
;
2610 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2613 rc
= parse_dotcommand (command
, &result
, &len
, inq
);
2623 fwrite (result
, 1, result
[len
- 1] == 0 ? len
- 1 : len
, outfp
);
2631 else if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
2632 (void) pwmd_command (pwm
, &result
, NULL
, NULL
, NULL
,
2633 "GETINFO last_error");
2635 #ifdef HAVE_LIBREADLINE
2638 wipememory (command
, 0, sizeof (command
));
2641 show_error (pwm
, rc
, result
);
2647 pwmd_free (filename
);
2648 pwmd_free (inquire
);
2649 strv_free (status_ignore
);
2650 if (connected
&& !quiet
)
2651 fprintf (stderr
, N_("Connection closed.\n"));
2653 exit (rc
? EXIT_FAILURE
: EXIT_SUCCESS
);