2 Copyright (C) 2006-2023 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 version 2.1 as published by the Free Software Foundation.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
30 #include <sys/types.h>
62 #include <sys/select.h>
65 #include "util-string.h"
66 #include "util-slist.h"
69 #include <gnutls/gnutls.h>
76 #ifdef HAVE_GETOPT_LONG
81 # include "getopt_long.h"
84 #ifdef HAVE_LIBREADLINE
85 #if defined(HAVE_READLINE_READLINE_H)
86 # include <readline/readline.h>
87 #elif defined(HAVE_READLINE_H)
88 # include <readline.h>
89 #endif /* !defined(HAVE_READLINE_H) */
90 static int interactive_error
;
91 static int interactive
;
92 #endif /* HAVE_LIBREADLINE */
94 #ifdef HAVE_READLINE_HISTORY
95 # if defined(HAVE_READLINE_HISTORY_H)
96 # include <readline/history.h>
97 #elif defined(HAVE_HISTORY_H)
100 #endif /* HAVE_READLINE_HISTORY */
103 #define LINE_MAX 2048
107 #define N_(msgid) gettext(msgid)
112 #define DEFAULT_STATUS_IGNORE "KEEPALIVE,GPGME,PASSPHRASE_INFO,PASSPHRASE_HINT"
113 #define DEFAULT_PIN_TIMEOUT 30
114 #define DEFAULT_PIN_TRIES 3
116 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
126 static int no_pinentry
;
128 static char *filename
;
131 static char *sign_keyid
;
132 static int symmetric
;
133 static char *keyparams
;
134 static char *keyfile
;
135 static char *new_keyfile
;
136 static char *sign_keyfile
;
138 static int local_pin
;
139 static int inquirefd
;
143 static char **status_ignore
;
144 static int skip_pinentry_status
;
151 size_t size
; // from stat(2).
179 struct slist_s
*userids
;
180 struct slist_s
*subkeys
;
183 static gpg_error_t
finalize ();
184 static gpg_error_t
set_inquire (int fd
, const char *line
,
185 struct inquire_s
**result
);
186 static gpg_error_t
parse_dotcommand (const char *line
, char **result
,
187 size_t * len
, struct inquire_s
*inq
);
188 static gpg_error_t
open_command (char *line
);
190 char *strsep (char **, const char *);
192 #if !defined (HAVE_ERR) && !defined (HAVE_ERR_H)
193 int err (int, const char *, ...);
197 show_error (pwm_t
*h
, gpg_error_t rc
, const char *str
)
201 int e
= pwmd_gnutls_error (h
, &tlsstr
);
204 fprintf(stderr
, "TLS: %s\n", tlsstr
);
208 fprintf (stderr
, "ERR %i: %s%s%s%s", rc
, gpg_strerror (rc
),
209 str
? ": " : "", str
? str
: "", str
? "" : "\n");
216 pwmd_free (new_keyfile
);
217 pwmd_free (sign_keyfile
);
218 keyfile
= new_keyfile
= sign_keyfile
= NULL
;
222 usage (const char *pn
, int status
)
224 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
225 N_("Usage: %s [options] [file]\n"
226 " --socket <string>\n"
227 " a url string to connect to (%s, see below)\n"
228 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
229 " --connect-timeout <seconds>\n"
230 " seconds before connecting to a remote host fails (0=disabled, 120)\n"
231 " --socket-timeout <seconds>\n"
232 " seconds before a remote command fails (0=disabled, 300)\n"
235 " --ca-cert <filename>\n"
236 " certificate authority (CA) used to sign the server cert\n"
237 " --client-cert <filename>\n"
238 " client certificate to use for authentication\n"
239 " --client-key <filename>\n"
240 " key file used to protect the client certificate\n"
241 " --tls-priority <string>\n"
242 " compression, cipher and hash algorithm string\n"
243 " (SECURE256:SECURE192:SECURE128:-VERS-SSL3.0:-VERS-TLS1.0)\n"
245 " disable verifying the hostname against the server certificate\n"
246 " --tls-fingerprint <string>\n"
247 " a SHA-256 hash of the server fingerprint to verify against\n"
251 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
252 " --identity, -i <filename>\n"
253 " the ssh identity file to use for authentication\n"
254 " --knownhosts, -k <filename>\n"
255 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
256 " --ssh-passphrase-file <filename>\n"
257 " read the SSH private key passphrase from filename\n"
260 " do not lock the data file upon opening it\n"
261 " --lock-timeout <N>\n"
262 " time in tenths of a second to wait for a locked data file (50)\n"
263 " --name, -n <string>\n"
264 " set the client name\n"
265 " --local-pinentry\n"
266 " force using a local pinentry\n"
268 " disable pinentry both remotely and locally\n"
269 " --ttyname, -y <path>\n"
270 " tty that pinentry will use\n"
271 " --ttytype, -t <string>\n"
272 " pinentry terminal type (default is $TERM)\n"
274 " pinentry display (default is $DISPLAY)\n"
275 " --lc-ctype <string>\n"
276 " locale setting for pinentry\n"
277 " --lc-messages <string>\n"
278 " locale setting for pinentry\n"
280 " number of pinentry tries before failing (3)\n"
281 " --timeout <seconds>\n"
282 " pinentry timeout\n"
283 " --inquire <COMMAND>\n"
284 " the specified command (with any options) uses a server inquire while\n"
285 " command data is read via the inquire file descriptor (stdin)\n"
286 " --inquire-line, -L <STRING>\n"
287 " the initial line to send (i.e., element path) before the inquire data\n"
288 " --inquire-fd <FD>\n"
289 " read inquire data from the specified file descriptor (stdin)\n"
290 " --inquire-file <filename>\n"
291 " read inquire data from the specified filename\n"
292 " --output-fd <FD>\n"
293 " redirect command output to the specified file descriptor\n"
295 " send the SAVE command before exiting\n"
296 " --passphrase-file <filename>\n"
297 " obtain the passphrase from the specified filename\n"
298 " --new-passphrase-file <filename>\n"
299 " obtain the passphrase to save with from the specified filename\n"
300 " --sign-passphrase-file <filename>\n"
301 " obtain the passphrase to sign with from the specified filename\n"
302 " --key-params <filename>\n"
303 " key parameters to use for key generation (pwmd default)\n"
304 " --keyid <recipient>[,<recipient>]\n"
305 " the public key ID to u\n"
306 " --sign-keyid <string>\n"
307 " the key ID to sign the data file with\n"
309 " use conventional encryption with optional signer(s) for new files\n"
311 " disable showing of status messages from the server\n"
313 " enable receiving of client STATE status messages\n"
314 " --status-fd <FD>\n"
315 " redirect status messages to the specified file descriptor\n"
316 " --status-ignore <string[,...]>\n"
317 " prevent parsing of the specified status message keywords\n"
319 " disable showing of extra messages (implies --no-status)\n"
320 #ifdef HAVE_LIBREADLINE
321 " --no-interactive\n"
322 " disable interactive mode\n"
327 #ifdef DEFAULT_PWMD_SOCKET
333 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
335 "An optional url may be in the form of:\n"
336 " --socket /path/to/socket\n"
337 " --socket file://[/path/to/socket]\n"
340 " --socket ssh[46]://[username@]hostname[:port] (uses ssh-agent)\n"
341 " -i identity_file --socket ssh[46]://[username@]hostname[:port]\n"
345 " --socket tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
346 " --client-key filename\n"
348 #ifdef HAVE_LIBREADLINE
350 "Interactive mode is used when input is from a terminal.\n"
357 inquire_cb (void *user
, const char *keyword
, gpg_error_t rc
,
358 char **data
, size_t * size
)
360 struct inquire_s
*inq
= user
;
362 int is_newpassword
= 0;
372 if (!strcmp (keyword
, "PASSPHRASE"))
374 else if (!strcmp (keyword
, "SIGN_PASSPHRASE"))
376 else if (!strcmp (keyword
, "NEW_PASSPHRASE"))
378 #ifdef HAVE_LIBREADLINE
379 else if (!strcmp (keyword
, "KEYPARAM") && !interactive
)
382 else if (!strcmp (keyword
, "KEYPARAM"))
386 if (!keyparams
|| !*keyparams
)
387 return gpg_error (GPG_ERR_INV_PARAMETER
);
389 fd
= open (keyparams
, O_RDONLY
);
392 fprintf (stderr
, "%s: %s\n", keyparams
, strerror (errno
));
393 return gpg_error_from_syserror ();
396 rc
= set_inquire (fd
, NULL
, &inq
);
404 fprintf (stderr
, N_("Using file '%s' as %s.\n"), keyparams
, keyword
);
409 if ((is_password
&& !keyfile
) || (is_newpassword
&& !new_keyfile
)
410 || (sign
&& !sign_keyfile
))
415 /* Try to use the local pinentry between inquires (new/sign/passphrase).
416 * If --no-pinentry was specified then the passphrase is read from the
417 * terminal as usual. */
418 pwmd_getopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, &local
);
419 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, 1);
420 rc
= pwmd_password (pwm
, keyword
, &tmp
, &inq
->len
);
421 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local
);
422 if (rc
&& gpg_err_code (rc
) != GPG_ERR_EOF
)
425 pwmd_free (inq
->line
);
429 rc
= gpg_error (GPG_ERR_EOF
);
432 else if ((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
)
433 || (sign
&& sign_keyfile
))
438 fd
= open (sign_keyfile
, O_RDONLY
);
440 fd
= open (is_password
|| sign
? keyfile
: new_keyfile
, O_RDONLY
);
445 fprintf (stderr
, "%s: %s\n", sign_keyfile
, strerror (errno
));
447 fprintf (stderr
, "%s: %s\n", is_newpassword
? new_keyfile
448 : keyfile
, strerror (errno
));
449 return gpg_error_from_syserror ();
452 rc
= set_inquire (fd
, NULL
, &inq
);
460 fprintf (stderr
, N_("Using keyfile '%s' as %s.\n"),
461 sign
? sign_keyfile
: is_newpassword
? new_keyfile
464 #ifdef HAVE_LIBREADLINE
465 else if ((!inq
->last_keyword
|| strcmp (keyword
, inq
->last_keyword
))
466 && interactive
&& inq
->fd
== STDIN_FILENO
)
470 ("%sPress CTRL-D to send the current line. Press twice to end. %s:\n"),
471 inq
->last_keyword
? "\n" : "", keyword
);
472 pwmd_free (inq
->last_keyword
);
473 inq
->last_keyword
= pwmd_strdup (keyword
);
477 /* The first part of the command data. */
483 rc
= inq
->fd
== -1 ? gpg_error (GPG_ERR_EOF
) : 0;
487 *size
= read (inq
->fd
, inq
->line
, ASSUAN_LINELENGTH
);
491 return gpg_error (gpg_error_from_syserror ());
495 else if (inq
->fd
!= STDIN_FILENO
&&
496 (is_newpassword
|| is_password
|| sign
|| is_keyparam
))
504 if (((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
)
505 || (sign
&& sign_keyfile
) || (keyparams
&& is_keyparam
))
506 && *size
== inq
->size
)
507 rc
= gpg_error (GPG_ERR_EOF
);
510 rc
= *size
? 0 : gpg_error (GPG_ERR_EOF
);
513 if (gpg_err_code (rc
) == GPG_ERR_EOF
)
515 pwmd_free (inq
->last_keyword
);
516 inq
->last_keyword
= NULL
;
523 status_msg_cb (void *data
, const char *line
)
525 char *p
= strchr (line
, ' ');
530 /* Ignore status messages specified by the client via --status-ignore. */
531 for (s
= status_ignore
; s
&& *s
; s
++)
533 char *tmp
= strchr (line
, ' ');
534 size_t len
= tmp
? strlen (line
) - strlen (tmp
) : strlen (line
);
536 if (!strncmp (line
, *s
, len
) && len
== strlen (*s
))
540 #ifdef HAVE_LIBREADLINE
541 if (interactive
&& !strncmp (line
, "XFER ", 5)
543 if (!strncmp (line
, "XFER ", 5)
545 && *line
!= '#' && p
&& strchr (p
, ' ') && *++p
)
547 char *p1
= strchr (p
, ' ');
548 int a
= strtol (p
, NULL
, 10);
550 if (isdigit (*p
) && p1
)
552 int b
= strtol (p1
, NULL
, 10);
553 int t
= a
&& b
? a
* 100 / b
: 0;
555 fprintf (statusfp
, "\rS:XFER %i/%i %i%%%s", a
, b
, t
,
561 #ifdef HAVE_LIBREADLINE
562 else if (interactive
&& (!strncmp (line
, "DECRYPT", 7)
563 || !strncmp (line
, "ENCRYPT", 7)
564 || !strncmp (line
, "GENKEY", 6)))
566 else if (!strncmp (line
, "DECRYPT", 7) || !strncmp (line
, "ENCRYPT", 7)
567 || !strncmp (line
, "GENKEY", 6))
570 if (skip_pinentry_status
)
574 fprintf (statusfp
, "S:%s\n", line
);
577 #ifdef HAVE_LIBREADLINE
586 return pwmd_process (pwm
);
589 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
591 is_remote_url (const char *str
)
594 return PWMD_SOCKET_LOCAL
;
597 if (strstr (str
, "ssh://") || strstr (str
, "ssh4://")
598 || strstr (str
, "ssh6://"))
599 return PWMD_SOCKET_SSH
;
603 if (strstr (str
, "tls://") || strstr (str
, "tls4://")
604 || strstr (str
, "tls6://"))
605 return PWMD_SOCKET_TLS
;
608 return PWMD_SOCKET_LOCAL
;
613 escape (const char *str
)
616 char *buf
= pwmd_malloc (ASSUAN_LINELENGTH
+ 1), *b
= buf
;
619 for (p
= str
; *p
; p
++, len
++)
621 if (len
== ASSUAN_LINELENGTH
)
665 free_inquire (struct inquire_s
*inq
)
670 pwmd_free (inq
->line
);
672 if (inq
->fd
!= -1 && inq
->fd
!= STDIN_FILENO
)
675 pwmd_free (inq
->last_keyword
);
679 /* When *result is not NULL it is updated to the new values and not
682 set_inquire (int fd
, const char *line
, struct inquire_s
**result
)
684 struct inquire_s inq
= { 0 };
685 struct stat st
= { 0 };
690 if (fstat (fd
, &st
) == -1)
691 return gpg_error_from_syserror ();
693 inq
.size
= st
.st_size
;
697 inq
.line
= pwmd_calloc (1, ASSUAN_LINELENGTH
);
699 return GPG_ERR_ENOMEM
;
703 char *s
= escape (line
);
707 pwmd_free (inq
.line
);
708 return GPG_ERR_ENOMEM
;
711 if (strlen (s
) >= ASSUAN_LINELENGTH
)
713 pwmd_free (inq
.line
);
715 return gpg_error (GPG_ERR_LINE_TOO_LONG
);
718 strncpy (inq
.line
, s
, ASSUAN_LINELENGTH
- 1);
719 inq
.len
= strlen (s
);
723 rc
= pwmd_setopt (pwm
, PWMD_OPTION_INQUIRE_TOTAL
,
724 st
.st_size
? st
.st_size
+ strlen (inq
.line
) : 0);
727 pwmd_free (inq
.line
);
732 *result
= pwmd_malloc (sizeof (struct inquire_s
));
735 if ((*result
)->fd
!= -1 && (*result
)->fd
!= STDIN_FILENO
)
736 close ((*result
)->fd
);
738 pwmd_free ((*result
)->line
);
739 (*result
)->line
= NULL
;
744 memcpy (*result
, &inq
, sizeof (struct inquire_s
));
745 memset (&inq
, 0, sizeof (struct inquire_s
));
749 #ifdef HAVE_LIBREADLINE
751 interactive_hook (void)
753 interactive_error
= process_cmd ();
755 if (interactive_error
)
756 rl_event_hook
= NULL
;
762 get_readline_char (FILE *fp
)
765 && (!strncmp (rl_line_buffer
, ".set passphrase-file ", 16)
766 || !strncmp (rl_line_buffer
, ".set new-passphrase-file ", 20)
767 || !strncmp (rl_line_buffer
, ".set sign-passphrase-file ", 21)))
768 rl_inhibit_completion
= 0;
769 else if (rl_line_buffer
770 && !strncmp (rl_line_buffer
, ".redir ", 7))
772 char *p
= strchr (rl_line_buffer
, ' ');
774 if (p
&& strchr (++p
, ' '))
775 rl_inhibit_completion
= 1;
777 rl_inhibit_completion
= 0;
779 else if (rl_line_buffer
780 && !strncmp (rl_line_buffer
, ".read ", 6))
782 char *p
= rl_line_buffer
+ 6;
784 if (strstr (p
, "--prefix "))
786 p
= strstr (p
, "--prefix ");
793 if (!p
|| strchr (p
, ' '))
794 rl_inhibit_completion
= 1;
796 rl_inhibit_completion
= 0;
799 rl_inhibit_completion
= 1;
809 ("------------------------------------------------------------\n"
810 "Elements are TAB delimited. Type HELP for protocol commands.\n"
811 "Type .help for pwmc commands. Press CTRL-D to quit.\n"
812 "------------------------------------------------------------\n"));
817 parse_arg (const char *src
, char *dst
, size_t len
)
823 for (; s
&& *s
&& *s
!= ' ' && n
< len
; s
++, n
++)
831 parse_opt (char **line
, const char *opt
, gpg_error_t
* rc
)
833 static char result
[ASSUAN_LINELENGTH
] = { 0 }, *r
= result
;
834 char *s
= strstr (*line
, opt
);
844 size_t rlen
= strlen (opt
);
848 while (*p
&& *p
== ' ')
854 for (; *p
&& len
< sizeof (result
) - 1; p
++, rlen
++)
856 if (isspace (*p
) && !quote
)
859 if (*p
== '\"' && lastc
!= '\\')
872 if (len
>= sizeof (result
) - 1)
873 *rc
= GPG_ERR_LINE_TOO_LONG
;
878 while (*p
&& *p
== ' ')
889 read_command (const char *line
, char **result
, size_t * len
)
894 struct inquire_s
*inq
= NULL
;
895 char *p
= (char *) line
;
896 const char *prefix
= parse_opt (&p
, "--prefix", &rc
);
897 char filebuf
[ASSUAN_LINELENGTH
];
906 while (*p
&& isspace (*p
))
909 file
= parse_arg (p
, filebuf
, sizeof (filebuf
));
912 p
+= strlen (file
) + 1;
914 while (*p
&& isspace (*p
))
926 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
929 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\\ = \\)\n"));
933 fd
= open (file
, O_RDONLY
);
935 return gpg_error_from_syserror ();
937 rc
= set_inquire (fd
, prefix
&& *prefix
? prefix
: NULL
, &inq
);
944 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, "%s", p
);
950 redir_command (const char *line
)
952 const char *p
= line
;
954 gpg_error_t rc
= GPG_ERR_SYNTAX
;
956 struct inquire_s
*inq
= NULL
;
959 char filebuf
[ASSUAN_LINELENGTH
];
963 file
= parse_arg (p
, filebuf
, sizeof (filebuf
));
966 p
+= strlen (file
) + 1;
968 while (*p
&& isspace (*p
))
978 fprintf (stderr
, N_("Usage: .redir <filename> <command> [args]\n"));
983 fd
= open (file
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_BINARY
, 0600);
985 fd
= open (file
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600);
988 return gpg_error_from_syserror ();
990 #ifdef HAVE_LIBREADLINE
991 rc
= set_inquire (interactive
? STDIN_FILENO
: inquirefd
, NULL
, &inq
);
993 rc
= set_inquire (inquirefd
, NULL
, &inq
);
1001 rc
= parse_dotcommand (p
, &result
, &len
, inq
);
1002 if (!rc
&& result
&& len
--)
1003 { // null byte which is always appended
1004 if (write (fd
, result
, len
) != len
)
1005 rc
= GPG_ERR_TOO_SHORT
;
1015 help_command (const char *line
)
1019 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
1020 " .redir <filename> <command>\n"
1021 " redirect the output of a command to the specified file\n"
1023 " .open <filename>\n"
1024 " open the specified filename losing any changes to the current one\n"
1026 " .read [--prefix <string>] <filename> <command> [args]\n"
1027 " obtain data from the specified filename for an inquire command\n"
1029 " .set help | <name> [<value>]\n"
1030 " set option <name> to <value>\n"
1033 " generate a new key\n"
1036 " write changes of the file to disk\n"
1039 " change the passphrase of a data file\n"
1041 " .listkeys [--options] [pattern[,..]]\n"
1042 " show human readable output of the LISTKEYS command\n"
1045 " this help text\n"));
1050 open_command (char *line
)
1052 struct inquire_s
*inq
= NULL
;
1053 char *file
= line
, *tmp
= NULL
;
1057 while (file
&& isspace (*file
))
1062 char *p
= strrchr (file
, ' ');
1066 while (isspace (*p
))
1071 file
= tmp
= pwmd_strdup (file
+ (strlen (file
)-strlen (p
)));
1072 if (!file
|| !*file
)
1083 if (!file
|| !*file
)
1085 fprintf (stderr
, N_("Usage: .open [--options] <filename>\n"));
1086 return GPG_ERR_SYNTAX
;
1089 #ifdef HAVE_LIBREADLINE
1090 if (interactive
|| !quiet
)
1094 fprintf (stderr
, N_("Opening data file \"%s\" ...\n"), file
);
1096 #ifdef HAVE_LIBREADLINE
1097 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1099 rc
= set_inquire (-1, NULL
, &inq
);
1108 pwmd_getopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, &local
);
1112 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1114 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, 1);
1117 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1120 rc
= pwmd_open (pwm
, file
, inquire_cb
, inq
);
1122 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local
);
1124 #ifdef HAVE_LIBREADLINE
1134 pwmd_free (filename
);
1139 char *p
= pwmd_strdup (file
);
1141 pwmd_free (filename
);
1144 rc
= GPG_ERR_ENOMEM
;
1150 pwmd_free (filename
);
1158 set_command (const char *line
)
1161 char name
[256] = { 0 };
1162 char value
[512] = { 0 };
1165 const char *p
= line
;
1167 while (p
&& *p
&& isspace (*p
))
1170 namep
= parse_arg (p
, name
, sizeof (name
));
1171 if (!namep
|| !*namep
)
1173 fprintf (stderr
, N_("Usage: .set help | <name> [<value>]\n"));
1174 return GPG_ERR_SYNTAX
;
1177 p
+= strlen (namep
);
1178 while (p
&& *p
&& isspace (*p
))
1181 valuep
= parse_arg (p
, value
, sizeof (value
));
1183 if (!strcmp (name
, "passphrase-file") || !strcmp (name
, "new-passphrase-file")
1184 || !strcmp (name
, "sign-passphrase-file"))
1186 int is_newkeyfile
= 1;
1187 int sign
= !strcmp (name
, "sign-passphrase-file");
1189 if (!strcmp (name
, "passphrase-file") || sign
)
1194 pwmd_free (new_keyfile
);
1199 pwmd_free (sign_keyfile
);
1200 sign_keyfile
= NULL
;
1204 pwmd_free (keyfile
);
1211 new_keyfile
= pwmd_strdup (value
);
1213 sign_keyfile
= pwmd_strdup (value
);
1215 keyfile
= pwmd_strdup (value
);
1217 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1219 else if (!local_pin
&& !no_pinentry
)
1223 pwmd_socket_type (pwm
, &t
);
1224 if (t
== PWMD_SOCKET_LOCAL
)
1225 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1228 else if (!strcmp(name
, "pinentry-timeout"))
1231 int n
= strtol(valuep
, &e
, 10);
1234 return gpg_error (GPG_ERR_INV_VALUE
);
1237 n
= DEFAULT_PIN_TIMEOUT
;
1239 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, n
);
1241 else if (!strcmp (name
, "help"))
1245 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1246 "delimited. When no value is specified the option is unset.\n\n"
1247 "passphrase-file [<filename>]\n"
1248 " set or unset the file to be used when a passphrase is required (*)\n"
1250 "new-passphrase-file [<filename>]\n"
1251 " set or unset the file to be used when a new passphrase is required (*)\n"
1253 "sign-passphrase-file [<filename>]\n"
1254 " set or unset the file to be used when a passphrase is required for\n"
1255 " signing (symmetric) (*)\n"
1257 "pinentry-timeout <seconds>\n"
1258 " the amount of seconds before pinentry gives up waiting for input\n"
1260 "* = the next protocol command will unset this value\n"
1264 rc
= GPG_ERR_UNKNOWN_OPTION
;
1270 do_save_passwd_command (const char *line
, int which
)
1272 struct inquire_s
*inq
= NULL
;
1276 #ifdef HAVE_LIBREADLINE
1277 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1279 rc
= set_inquire (-1, NULL
, &inq
);
1284 pwmd_getopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, &local
);
1286 if (new_keyfile
|| keyfile
|| sign_keyfile
)
1288 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1290 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, 1);
1293 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1297 skip_pinentry_status
= 1;
1299 if (which
== SAVE_WHICH_SAVE
)
1300 rc
= pwmd_save (pwm
, line
, inquire_cb
, inq
);
1301 else if (which
== SAVE_WHICH_PASSWD
)
1302 rc
= pwmd_passwd (pwm
, line
, inquire_cb
, inq
);
1304 rc
= pwmd_genkey (pwm
, line
, inquire_cb
, inq
);
1306 skip_pinentry_status
= 0;
1309 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local
);
1311 #ifdef HAVE_LIBREADLINE
1321 save_command (const char *line
)
1323 return do_save_passwd_command (line
, SAVE_WHICH_SAVE
);
1327 search_and_replace (char *str
, const char *s
, const char r
)
1331 p
= strstr (str
, s
);
1337 search_and_replace (str
, s
, r
);
1343 openpgp_unescape (char *str
)
1345 search_and_replace (str
, "\\x3a", ':');
1346 search_and_replace (str
, "\\x5c", '\\');
1351 free_listkeys (struct slist_s
*keys
)
1355 t
= slist_length (keys
);
1356 for (i
= 0; i
< t
; i
++)
1358 struct keyid_s
*key
= slist_nth_data (keys
, i
);
1361 nt
= slist_length (key
->userids
);
1362 for (n
= 0; n
< nt
; n
++)
1364 struct userid_s
*userid
= slist_nth_data (key
->userids
, n
);
1366 pwmd_free (userid
->userid
);
1367 pwmd_free (userid
->name
);
1368 pwmd_free (userid
->email
);
1369 pwmd_free (userid
->comment
);
1373 slist_free (key
->userids
);
1374 nt
= slist_length (key
->subkeys
);
1375 for (n
= 0; n
< nt
; n
++)
1377 struct keyid_s
*sub
= slist_nth_data (key
->subkeys
, n
);
1379 pwmd_free (sub
->keyid
);
1380 pwmd_free (sub
->fpr
);
1381 pwmd_free (sub
->grip
);
1382 pwmd_free (sub
->card
);
1383 pwmd_free (sub
->curve
);
1387 slist_free (key
->subkeys
);
1395 openpgp_algorithm (struct keyid_s
*key
)
1418 return N_("Unknown");
1422 display_listkeys (struct slist_s
*keys
)
1426 t
= slist_length (keys
);
1427 for (i
= 0; i
< t
; i
++)
1429 struct keyid_s
*key
= slist_nth_data (keys
, i
);
1430 unsigned st
= slist_length (key
->subkeys
);
1432 unsigned ut
= slist_length (key
->userids
);
1435 for (u
= 0; u
< ut
; u
++)
1437 struct userid_s
*userid
= slist_nth_data (key
->userids
, u
);
1439 fprintf(stdout
, N_("User ID: %s\n"), userid
->userid
);
1442 for (s
= 0; s
< st
; s
++)
1444 struct keyid_s
*sub
= slist_nth_data (key
->subkeys
, s
);
1446 const char *caps
= NULL
;
1447 char expires
[11] = { 0 };
1448 char created
[11] = { 0 };
1452 tmp
= localtime (&sub
->expires
);
1453 strftime (expires
, sizeof (expires
), "%Y-%m-%d", tmp
);
1456 tmp
= localtime (&sub
->created
);
1457 strftime (created
, sizeof (created
), "%Y-%m-%d", tmp
);
1459 if (sub
->can_encrypt
)
1461 else if (sub
->can_sign
)
1463 else if (sub
->can_auth
)
1465 else if (sub
->can_certify
)
1469 " Subkey %u: %s [%s]%s%s %s-%u%s%s\n"
1470 " Created: %s %s%s\n"
1471 " Fingerprint: %s\n"
1477 sub
->secret
|| sub
->card
? "[P]" : "",
1478 sub
->revoked
? "[R]" : "",
1479 openpgp_algorithm (sub
),
1481 sub
->curve
? "-" : "",
1482 sub
->curve
? sub
->curve
: "",
1484 sub
->expired
? N_("Expired: ") : expires
[0] ? N_("Expires: ") : "",
1485 sub
->expired
|| expires
[0] ? expires
: "",
1488 sub
->card
? N_(" Card: ") : "",
1489 sub
->card
? sub
->card
: "",
1490 sub
->card
? "\n" : "");
1494 fprintf (stdout
, "\n");
1499 listkeys_command (const char *pattern
)
1503 char **lines
= NULL
, **p
;
1504 struct slist_s
*keys
= NULL
;
1506 rc
= pwmd_command (pwm
, &result
, NULL
, NULL
, NULL
, "LISTKEYS %s", pattern
);
1510 lines
= str_split (result
, "\n", 0);
1513 return GPG_ERR_ENOMEM
;
1515 for (p
= lines
; *p
; p
++)
1517 struct keyid_s
*key
;
1518 char **fields
= str_split (*p
, ":", 0);
1521 unsigned n_subkeys
= 0;
1522 struct slist_s
*tlist
;
1526 rc
= GPG_ERR_ENOMEM
;
1530 key
= pwmd_calloc (1, sizeof (struct keyid_s
));
1534 rc
= GPG_ERR_ENOMEM
;
1538 for (f
= i
= 0; i
< 17; i
++, f
++)
1543 b
= atoi (fields
[f
]) != 0;
1547 case 0: key
->revoked
= b
; break;
1548 case 1: key
->expired
= b
; break;
1549 case 4: key
->can_encrypt
= b
; break;
1550 case 5: key
->can_sign
= b
; break;
1551 case 7: key
->secret
= b
; break;
1552 case 16: n_subkeys
= strtoul (fields
[f
], NULL
, 10); break;
1558 for (s
= 0; s
< n_subkeys
; s
++)
1560 struct keyid_s
*sub
;
1563 sub
= pwmd_calloc (1, sizeof (struct keyid_s
));
1567 rc
= GPG_ERR_ENOMEM
;
1571 for (i
= 0; i
< 20; i
++, f
++)
1574 b
= atoi (fields
[f
]) != 0;
1578 case 0: sub
->revoked
= b
; break;
1579 case 1: sub
->expired
= b
; break;
1580 case 4: sub
->can_encrypt
= b
; break;
1581 case 5: sub
->can_sign
= b
; break;
1582 case 6: sub
->can_certify
= b
; break;
1583 case 7: sub
->secret
= b
; break;
1584 case 8: sub
->can_auth
= b
; break;
1585 case 11: sub
->algo
= atoi (fields
[f
]); break;
1586 case 12: sub
->bits
= atoi (fields
[f
]); break;
1587 case 13: sub
->keyid
= pwmd_strdup (fields
[f
]); break;
1588 case 14: sub
->fpr
= pwmd_strdup (fields
[f
]); break;
1589 case 15: sub
->grip
= pwmd_strdup (fields
[f
]); break;
1590 case 16: sub
->created
= strtoul (fields
[f
], NULL
, 10); break;
1591 case 17: sub
->expires
= strtoul (fields
[f
], NULL
, 10); break;
1592 case 18: sub
->card
= fields
[f
] && strlen(fields
[f
]) > 1
1593 ? pwmd_strdup (fields
[f
]) : NULL
; break;
1594 case 19: sub
->curve
= strlen (fields
[f
]) > 1 ? pwmd_strdup (openpgp_unescape(fields
[f
])) : NULL
; break;
1600 tlist
= slist_append (key
->subkeys
, sub
);
1603 rc
= GPG_ERR_ENOMEM
;
1607 key
->subkeys
= tlist
;
1616 // Re-create a line containing the userIds.
1617 for (; f
< strv_length (fields
); f
++)
1619 struct userid_s
*userid
;
1621 userid
= pwmd_calloc (1, sizeof (struct userid_s
));
1624 rc
= GPG_ERR_ENOMEM
;
1635 userid
->userid
= pwmd_strdup (openpgp_unescape (fields
[f
++]));
1636 userid
->name
= pwmd_strdup (openpgp_unescape (fields
[f
++]));
1637 userid
->email
= pwmd_strdup (openpgp_unescape (fields
[f
++]));
1638 userid
->comment
= pwmd_strdup (openpgp_unescape (fields
[f
]));
1640 tlist
= slist_append (key
->userids
, userid
);
1643 rc
= GPG_ERR_ENOMEM
;
1647 key
->userids
= tlist
;
1654 tlist
= slist_append (keys
, key
);
1657 rc
= GPG_ERR_ENOMEM
;
1667 display_listkeys (keys
);
1669 free_listkeys (keys
);
1674 parse_dotcommand (const char *line
, char **result
,
1675 size_t * len
, struct inquire_s
*inq
)
1677 const char *p
= line
;
1680 if (!strncmp (p
, ".read", 5) && (p
[5] == ' ' || p
[5] == 0))
1681 rc
= read_command (p
+ 5, result
, len
);
1682 else if (!strncmp (p
, ".redir", 6) && (p
[6] == ' ' || p
[6] == 0))
1683 rc
= redir_command (p
+ 6);
1684 else if (!strncmp (p
, ".help", 5) && (p
[5] == ' ' || p
[5] == 0))
1685 rc
= help_command (p
+ 5);
1686 else if (!strncmp (p
, ".open", 5) && (p
[5] == ' ' || p
[5] == 0))
1687 rc
= open_command ((char *)p
+ 5);
1688 else if (!strncmp (p
, ".set", 4) && (p
[4] == ' ' || p
[4] == 0))
1689 rc
= set_command (p
+ 4);
1690 else if (!strncmp (p
, ".save", 5) && (p
[5] == ' ' || p
[5] == 0))
1691 rc
= do_save_passwd_command (p
+ 5, SAVE_WHICH_SAVE
);
1692 else if (!strncmp (p
, ".passwd", 7) && (p
[7] == ' ' || p
[7] == 0))
1693 rc
= do_save_passwd_command (p
+ 7, SAVE_WHICH_PASSWD
);
1694 else if (!strncmp (p
, ".genkey", 7) && (p
[7] == ' ' || p
[7] == 0))
1695 rc
= do_save_passwd_command (p
+ 7, SAVE_WHICH_GENKEY
);
1696 else if (!strncmp (p
, ".listkeys", 9) && (p
[9] == ' ' || p
[9] == 0))
1697 rc
= listkeys_command (p
+9);
1700 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, "%s", line
);
1701 #ifdef HAVE_LIBREADLINE
1708 if (!rc
&& !strncasecmp (line
, "RESET", 5) && (p
[5] == ' ' || p
[5] == 0))
1710 pwmd_free (filename
);
1718 #ifdef HAVE_LIBREADLINE
1719 #ifdef HAVE_READLINE_HISTORY
1721 add_history_item (const char *line
)
1724 HIST_ENTRY
*h
= NULL
;
1726 for (i
= 0; i
< history_length
; i
++)
1728 h
= history_get (i
+ history_base
);
1729 if (h
&& !strcmp (h
->line
, line
))
1737 h
= remove_history (i
);
1738 #ifdef HAVE_FREE_HISTORY_ENTRY
1739 s
= free_history_entry (h
);
1742 wipememory (s
, 0, strlen (s
));
1754 struct inquire_s
*inq
= NULL
;
1757 rc
= process_cmd ();
1761 rc
= set_inquire (STDIN_FILENO
, NULL
, &inq
);
1766 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1768 rl_event_hook
= &interactive_hook
;
1769 rl_getc_function
= get_readline_char
;
1770 rl_set_keyboard_input_timeout (100000);
1775 char *result
= NULL
;
1779 snprintf (buf
, sizeof (buf
), "pwmc%s%s> ",
1780 filename
? ":" : "", filename
? filename
: "");
1781 line
= readline (buf
);
1782 if (interactive_error
)
1785 wipememory (line
, 0, strlen (line
));
1788 rc
= interactive_error
;
1798 if (gpg_err_code (rc
) != GPG_ERR_CANCELED
&&
1799 gpg_err_code (rc
) != GPG_ERR_EOF
)
1800 fprintf (stderr
, "ERR %i: %s\n", rc
, gpg_strerror (rc
));
1810 #ifdef HAVE_READLINE_HISTORY
1811 add_history_item (line
);
1813 rc
= parse_dotcommand (line
, &result
, &len
, inq
);
1814 wipememory (line
, 0, strlen (line
));
1820 if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
1821 (void) pwmd_command (pwm
, &tmp
, NULL
, NULL
, NULL
,
1822 "GETINFO last_error");
1824 show_error (pwm
, rc
, tmp
);
1827 else if (result
&& len
)
1828 printf ("%s%s", result
, result
[len
- 1] != '\n' ? "\n" : "");
1842 #ifdef HAVE_LIBREADLINE
1849 fprintf (stderr
, "\n");
1857 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1858 p
= fgets (buf
, sizeof (buf
), stdin
);
1872 return GPG_ERR_CANCELED
;
1876 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1877 "CLEARCACHE %s", filename
);
1881 interactive_hook ();
1897 if (save
&& !filename
)
1901 ("No filename was specified on the command line. Aborting.\n"));
1902 return GPG_ERR_CANCELED
;
1905 if (save
&& filename
)
1908 pwmd_strdup_printf ("%s %s%s %s%s %s",
1909 symmetric
? "--symmetric" : "",
1910 keyid
? "--keyid=" : "",
1912 sign_keyid
? "--sign-keyid=" : "",
1913 sign_keyid
? sign_keyid
: "",
1914 keyparams
? "--inquire-keyparam" : "");
1916 #ifdef HAVE_LIBREADLINE
1917 if (!quiet
|| interactive
)
1923 fprintf (stderr
, "\n");
1924 fprintf (stderr
, N_("Saving changes ...\n"));
1927 rc
= save_command (args
);
1931 #ifdef HAVE_LIBREADLINE
1933 return rc
? rc
: quit
? 0 : GPG_ERR_CANCELED
;
1940 parse_status_ignore (char *str
)
1944 strv_free (status_ignore
);
1945 status_ignore
= NULL
;
1949 while ((s
= strsep (&str
, ",")))
1951 char **p
= strv_cat (status_ignore
, pwmd_strdup (s
));
1955 strv_free (status_ignore
);
1956 status_ignore
= NULL
;
1964 main (int argc
, char *argv
[])
1967 int status_state
= 0;
1970 char command
[ASSUAN_LINELENGTH
], *p
= NULL
;
1971 char *result
= NULL
;
1973 char *display
= NULL
, *tty
= NULL
, *ttytype
= NULL
;
1974 char *lcctype
= NULL
, *lcmessages
= NULL
;
1975 int outfd
= STDOUT_FILENO
;
1976 FILE *outfp
= stdout
;
1977 int show_status
= 1;
1978 const char *clientname
= "pwmc";
1979 char *inquire
= NULL
;
1980 char *inquire_line
= NULL
;
1983 int use_ssh_agent
= -1;
1984 char *knownhosts
= NULL
;
1985 char *identity
= NULL
;
1986 int needs_passphrase
= 0;
1987 char *ssh_passphrase_file
= NULL
;
1990 char *cacert
= NULL
;
1991 char *clientcert
= NULL
;
1992 char *clientkey
= NULL
;
1994 int tls_verify
= -1;
1995 char *tls_fingerprint
= NULL
;
1997 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1998 pwmd_socket_t socktype
;
1999 long socket_timeout
= 300;
2000 int connect_timeout
= 120;
2002 #ifdef HAVE_LIBREADLINE
2003 int no_interactive
= 0;
2005 int lock_on_open
= -1;
2006 long lock_timeout
= -2;
2009 /* The order is important. */
2012 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2013 OPT_SOCKET_TIMEOUT
, OPT_CONNECT_TIMEOUT
,
2016 OPT_USE_SSH_AGENT
, OPT_IDENTITY
, OPT_KNOWNHOSTS
, OPT_SSH_NEEDS_PASSPHRASE
,
2017 OPT_SSH_PASSPHRASE_FILE
,
2020 OPT_CACERT
, OPT_CLIENTCERT
, OPT_CLIENTKEY
, OPT_PRIORITY
, OPT_VERIFY
,
2023 OPT_URL
, OPT_SOCKET
, OPT_LOCAL
, OPT_TTYNAME
, OPT_TTYTYPE
, OPT_DISPLAY
,
2024 OPT_LC_CTYPE
, OPT_LC_MESSAGES
, OPT_TIMEOUT
, OPT_TRIES
, OPT_PINENTRY
,
2025 OPT_KEYFILE
, OPT_PASSPHRASE_FILE
, OPT_NEW_KEYFILE
, OPT_NEW_PASSPHRASE_FILE
,
2026 OPT_SIGN_KEYFILE
, OPT_SIGN_PASSPHRASE_FILE
, OPT_NOLOCK
, OPT_LOCK_TIMEOUT
,
2027 OPT_SAVE
, OPT_OUTPUT_FD
, OPT_INQUIRE
, OPT_INQUIRE_FD
, OPT_INQUIRE_FILE
,
2028 OPT_INQUIRE_LINE
, OPT_NO_STATUS
, OPT_STATUS_IGNORE
, OPT_STATUSFD
, OPT_NAME
,
2029 OPT_VERSION
, OPT_HELP
, OPT_KEYID
, OPT_SIGN_KEYID
, OPT_SYMMETRIC
,
2030 OPT_KEYPARAMS
, OPT_NO_PINENTRY
, OPT_QUIET
, OPT_STATUS_STATE
,
2031 #ifdef HAVE_LIBREADLINE
2035 const struct option long_opts
[] = {
2036 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2037 {"socket-timeout", 1, 0, 0},
2038 {"connect-timeout", 1, 0, 0},
2042 {"no-ssh-agent", 0, 0, 0},
2043 {"identity", 1, 0, 'i'},
2044 {"knownhosts", 1, 0, 'k'},
2045 {"ssh-needs-passphrase", 0, 0, 0},
2046 {"ssh-passphrase-file", 1, 0, 0},
2049 {"ca-cert", 1, 0, 0},
2050 {"client-cert", 1, 0, 0},
2051 {"client-key", 1, 0, 0},
2052 {"tls-priority", 1, 0, 0},
2053 {"no-tls-verify", 0, 0, 0},
2054 {"tls-fingerprint", 1, 0, 0},
2056 {"socket", 1, 0, 0},
2058 {"local-pinentry", 0, 0},
2059 {"ttyname", 1, 0, 'y'},
2060 {"ttytype", 1, 0, 't'},
2061 {"display", 1, 0, 'd'},
2062 {"lc-ctype", 1, 0, 0},
2063 {"lc-messages", 1, 0, 0},
2064 {"timeout", 1, 0, 0},
2066 {"pinentry", 1, 0, 0},
2067 {"key-file", 1, 0, 0},
2068 {"passphrase-file", 1, 0, 0},
2069 {"new-key-file", 1, 0, 0},
2070 {"new-passphrase-file", 1, 0, 0},
2071 {"sign-key-file", 1, 0, 0},
2072 {"sign-passphrase-file", 1, 0, 0},
2073 {"no-lock", 0, 0, 0},
2074 {"lock-timeout", 1, 0, 0},
2075 {"save", 0, 0, 'S'},
2076 {"output-fd", 1, 0, 0},
2077 {"inquire", 1, 0, 0},
2078 {"inquire-fd", 1, 0, 0},
2079 {"inquire-file", 1, 0, 0},
2080 {"inquire-line", 1, 0, 'L'},
2081 {"no-status", 0, 0, 0},
2082 {"status-ignore", 1, 0, 0},
2083 {"status-fd", 1, 0, 0},
2084 {"name", 1, 0, 'n'},
2085 {"version", 0, 0, 0},
2088 {"sign-keyid", 1, 0, 0},
2089 {"symmetric", 0, 0, 0},
2090 {"key-params", 1, 0, 0},
2091 {"no-pinentry", 0, 0, 0},
2093 {"status-state", 0, 0, 0},
2094 #ifdef HAVE_LIBREADLINE
2095 {"no-interactive", 0, 0},
2100 const char *optstring
= "L:y:t:d:P:I:Sn:i:k:s";
2102 const char *optstring
= "L:y:t:d:P:I:Sn:s";
2107 setlocale (LC_ALL
, "");
2108 bindtextdomain ("libpwmd", LOCALEDIR
);
2111 tries
= DEFAULT_PIN_TRIES
;
2112 inquirefd
= STDIN_FILENO
;
2113 statusfd
= STDERR_FILENO
;
2115 tmp
= pwmd_strdup (DEFAULT_STATUS_IGNORE
);
2116 parse_status_ignore (tmp
);
2122 getopt_long (argc
, argv
, optstring
, long_opts
, &opt_index
)) != -1)
2126 /* Handle long options without a short option part. */
2130 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2131 case OPT_SOCKET_TIMEOUT
:
2132 socket_timeout
= strtol (optarg
, &p
, 10);
2134 case OPT_CONNECT_TIMEOUT
:
2135 connect_timeout
= strtol (optarg
, &p
, 10);
2139 case OPT_USE_SSH_AGENT
:
2142 case OPT_SSH_NEEDS_PASSPHRASE
:
2143 needs_passphrase
= 1;
2145 case OPT_SSH_PASSPHRASE_FILE
:
2146 ssh_passphrase_file
= optarg
;
2153 case OPT_CLIENTCERT
:
2154 clientcert
= optarg
;
2166 tls_fingerprint
= optarg
;
2176 case OPT_PASSPHRASE_FILE
:
2177 keyfile
= pwmd_strdup (optarg
);
2179 case OPT_NEW_KEYFILE
:
2180 case OPT_NEW_PASSPHRASE_FILE
:
2181 new_keyfile
= pwmd_strdup (optarg
);
2183 case OPT_SIGN_KEYFILE
:
2184 case OPT_SIGN_PASSPHRASE_FILE
:
2185 sign_keyfile
= pwmd_strdup (optarg
);
2190 case OPT_LOCK_TIMEOUT
:
2191 lock_timeout
= strtol (optarg
, &p
, 10);
2201 lcctype
= pwmd_strdup (optarg
);
2203 case OPT_LC_MESSAGES
:
2204 lcmessages
= pwmd_strdup (optarg
);
2207 timeout
= strtol (optarg
, &p
, 10);
2210 tries
= strtol (optarg
, &p
, 10);
2213 inquire
= escape (optarg
);
2215 case OPT_INQUIRE_FD
:
2216 inquirefd
= strtol (optarg
, &p
, 10);
2218 case OPT_INQUIRE_FILE
:
2219 inquirefd
= open (optarg
, O_RDONLY
);
2220 if (inquirefd
== -1)
2221 err (EXIT_FAILURE
, "%s", optarg
);
2224 outfd
= strtol (optarg
, &p
, 10);
2227 outfp
= fdopen (outfd
, "wb");
2229 err (EXIT_FAILURE
, "%i", outfd
);
2236 statusfd
= strtol (optarg
, &p
, 10);
2239 statusfp
= fdopen (statusfd
, "wb");
2241 err (EXIT_FAILURE
, "%i", statusfd
);
2244 case OPT_STATUS_IGNORE
:
2245 parse_status_ignore (optarg
);
2248 printf ("%s (pwmc)\n\n"
2249 "Copyright (C) 2006-2023\n"
2251 "Released under the terms of the LGPL v2.1.\n\n"
2252 "Compile-time features:\n"
2253 #ifdef HAVE_LIBREADLINE
2268 #ifdef WITH_PINENTRY
2283 "\n", PACKAGE_STRING LIBPWMD_GIT_HASH
, PACKAGE_BUGREPORT
);
2284 exit (EXIT_SUCCESS
);
2288 usage (argv
[0], EXIT_SUCCESS
);
2292 case OPT_SIGN_KEYID
:
2293 sign_keyid
= optarg
;
2299 case OPT_STATUS_STATE
:
2302 case OPT_NO_PINENTRY
:
2305 #ifdef HAVE_LIBREADLINE
2306 case OPT_NO_INTERACTIVE
:
2311 usage (argv
[0], EXIT_FAILURE
);
2316 fprintf (stderr
, N_("%s: invalid argument for option '--%s'\n"),
2317 argv
[0], long_opts
[opt_index
].name
);
2318 usage (argv
[0], EXIT_FAILURE
);
2327 knownhosts
= optarg
;
2331 inquire_line
= optarg
;
2346 clientname
= optarg
;
2349 usage (argv
[0], EXIT_FAILURE
);
2353 #ifdef HAVE_LIBREADLINE
2354 if (isatty (STDIN_FILENO
) && !inquire
&& !inquire_line
&& !no_interactive
)
2359 rc
= pwmd_new (clientname
, &pwm
);
2363 filename
= argv
[optind
] ? pwmd_strdup (argv
[optind
]) : NULL
;
2364 if (no_pinentry
!= -1)
2365 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
2367 rc
= pwmd_getopt (pwm
, PWMD_OPTION_NO_PINENTRY
, &no_pinentry
);
2371 if (local_pin
!= -1)
2372 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local_pin
);
2374 rc
= pwmd_getopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, &local_pin
);
2378 pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TRIES
, tries
);
2380 fprintf (stderr
, N_("Connecting ...\n"));
2384 rc
= pwmd_setopt (pwm
, PWMD_OPTION_STATE_STATUS
, 1);
2389 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
2390 socktype
= is_remote_url (url
);
2391 if (socktype
!= PWMD_SOCKET_LOCAL
)
2394 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2395 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, connect_timeout
);
2400 if (socktype
== PWMD_SOCKET_SSH
)
2403 if (use_ssh_agent
== -1)
2404 rc
= pwmd_getopt (pwm
, PWMD_OPTION_SSH_AGENT
, &use_ssh_agent
);
2408 if (use_ssh_agent
!= 0)
2410 char *t
= getenv ("SSH_AUTH_SOCK");
2412 use_ssh_agent
= t
&& *t
? 1 : 0;
2418 if (!identity
&& !use_ssh_agent
)
2421 fprintf (stderr
, N_("No identity specified and no SSH_AUTH_SOCK environment variable.\n"));
2422 usage (argv
[0], EXIT_FAILURE
);
2425 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_AGENT
, use_ssh_agent
);
2432 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_NEEDS_PASSPHRASE
,
2437 if (ssh_passphrase_file
)
2442 if (stat (ssh_passphrase_file
, &st
) == -1)
2444 rc
= gpg_error_from_syserror ();
2445 fprintf(stderr
, "%s: %s\n", ssh_passphrase_file
,
2450 result
= pwmd_calloc (1, st
.st_size
+1);
2453 rc
= GPG_ERR_ENOMEM
;
2457 fd
= open (ssh_passphrase_file
, O_RDONLY
);
2460 len
= read (fd
, result
, st
.st_size
);
2461 if (len
== st
.st_size
)
2462 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_PASSPHRASE
, result
);
2464 rc
= gpg_error_from_syserror ();
2469 rc
= gpg_error_from_syserror ();
2477 fprintf(stderr
, "%s: %s\n", ssh_passphrase_file
,
2483 rc
= pwmd_connect (pwm
, url
, identity
, knownhosts
);
2489 if (tls_verify
!= -1)
2491 rc
= pwmd_setopt (pwm
, PWMD_OPTION_TLS_VERIFY
, tls_verify
);
2497 rc
= pwmd_setopt (pwm
, PWMD_OPTION_TLS_PRIORITY
, prio
);
2500 rc
= pwmd_connect (pwm
, url
, clientcert
, clientkey
, cacert
,
2506 rc
= pwmd_connect (pwm
, url
);
2508 rc
= pwmd_connect (pwm
, url
);
2514 fprintf (stderr
, N_("Connected.\n"));
2517 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2518 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, socket_timeout
);
2523 if (lock_on_open
!= -1)
2525 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCK_ON_OPEN
, lock_on_open
);
2530 if (lock_timeout
!= -2)
2532 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCK_TIMEOUT
, lock_timeout
);
2537 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, NULL
, NULL
);
2543 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, timeout
);
2550 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DISPLAY
, display
);
2557 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TTY
, tty
);
2564 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TERM
, ttytype
);
2571 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_CTYPE
, lcctype
);
2578 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_MESSAGES
, lcmessages
);
2585 rc
= pwmd_setopt (pwm
, PWMD_OPTION_STATUS_CB
, status_msg_cb
);
2592 rc
= open_command (filename
);
2597 #ifdef HAVE_LIBREADLINE
2600 rc
= do_interactive ();
2602 while (history_length
)
2605 HIST_ENTRY
*h
= remove_history (0);
2606 #ifdef HAVE_FREE_HISTORY_ENTRY
2607 s
= free_history_entry (h
);
2612 wipememory (s
, 0, strlen (s
));
2621 struct inquire_s
*inq
= NULL
;
2623 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2625 rc
= pwmd_command (pwm
, &result
, &len
, inquire_cb
, inq
, "%s", inquire
);
2632 if (fcntl (STDIN_FILENO
, F_SETFL
, O_NONBLOCK
, 1) == -1)
2634 rc
= gpg_error_from_errno (errno
);
2643 rc
= process_cmd ();
2648 n
= read (STDIN_FILENO
, command
, sizeof (command
)-1);
2651 if (errno
== EAGAIN
)
2661 rc
= gpg_error_from_errno (errno
);
2672 if (!p
|| !*p
|| !strcasecmp (p
, "BYE"))
2676 struct inquire_s
*inq
= NULL
;
2677 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2680 rc
= parse_dotcommand (command
, &result
, &len
, inq
);
2690 fwrite (result
, 1, result
[len
- 1] == 0 ? len
- 1 : len
, outfp
);
2698 else if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
2699 (void) pwmd_command (pwm
, &result
, NULL
, NULL
, NULL
,
2700 "GETINFO last_error");
2702 #ifdef HAVE_LIBREADLINE
2705 wipememory (command
, 0, sizeof (command
));
2708 show_error (pwm
, rc
, result
);
2714 pwmd_free (filename
);
2715 pwmd_free (inquire
);
2716 strv_free (status_ignore
);
2717 if (connected
&& !quiet
)
2718 fprintf (stderr
, N_("Connection closed.\n"));
2720 exit (rc
? EXIT_FAILURE
: EXIT_SUCCESS
);