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/select.h>
36 #include <sys/types.h>
44 #include "util-string.h"
45 #include "util-slist.h"
48 #include <gnutls/gnutls.h>
55 #ifdef HAVE_GETOPT_LONG
60 #include "getopt_long.h"
63 #ifdef HAVE_LIBREADLINE
64 #if defined(HAVE_READLINE_READLINE_H)
65 #include <readline/readline.h>
66 #elif defined(HAVE_READLINE_H)
68 #endif /* !defined(HAVE_READLINE_H) */
69 static int interactive_error
;
70 static int interactive
;
71 #endif /* HAVE_LIBREADLINE */
73 #ifdef HAVE_READLINE_HISTORY
74 #if defined(HAVE_READLINE_HISTORY_H)
75 #include <readline/history.h>
76 #elif defined(HAVE_HISTORY_H)
79 #endif /* HAVE_READLINE_HISTORY */
86 #define N_(msgid) gettext(msgid)
91 #define DEFAULT_STATUS_IGNORE "KEEPALIVE,GPGME,PASSPHRASE_INFO,PASSPHRASE_HINT"
92 #define DEFAULT_PIN_TIMEOUT 30
93 #define DEFAULT_PIN_TRIES 3
95 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
105 static int no_pinentry
;
107 static char *filename
;
110 static char *sign_keyid
;
111 static int symmetric
;
112 static char *keyparams
;
113 static char *keyfile
;
114 static char *new_keyfile
;
115 static char *sign_keyfile
;
117 static int local_pin
;
118 static int inquirefd
;
122 static char **status_ignore
;
129 size_t size
; // from stat(2).
157 struct slist_s
*userids
;
158 struct slist_s
*subkeys
;
161 static gpg_error_t
finalize ();
162 static gpg_error_t
set_inquire (int fd
, const char *line
,
163 struct inquire_s
**result
);
164 static gpg_error_t
parse_dotcommand (const char *line
, char **result
,
165 size_t * len
, struct inquire_s
*inq
);
166 static gpg_error_t
open_command (char *line
);
169 show_error (pwm_t
*h
, gpg_error_t rc
, const char *str
)
173 int e
= pwmd_gnutls_error (h
, &tlsstr
);
176 fprintf(stderr
, "TLS: %s\n", tlsstr
);
180 fprintf (stderr
, "ERR %i: %s%s%s%s", rc
, gpg_strerror (rc
),
181 str
? ": " : "", str
? str
: "", str
? "" : "\n");
188 pwmd_free (new_keyfile
);
189 pwmd_free (sign_keyfile
);
190 keyfile
= new_keyfile
= sign_keyfile
= NULL
;
194 usage (const char *pn
, int status
)
196 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
197 N_("Usage: %s [options] [file]\n"
199 " a url string to connect to (%s, see below)\n"
200 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
201 " --connect-timeout <seconds>\n"
202 " seconds before connecting to a remote host fails (0=disabled, 120)\n"
203 " --socket-timeout <seconds>\n"
204 " seconds before a remote command fails (0=disabled, 300)\n"
207 " --ca-cert <filename>\n"
208 " certificate authority (CA) used to sign the server cert\n"
209 " --client-cert <filename>\n"
210 " client certificate to use for authentication\n"
211 " --client-key <filename>\n"
212 " key file used to protect the client certificate\n"
213 " --tls-priority <string>\n"
214 " compression, cipher and hash algorithm string\n"
215 " (SECURE256:SECURE192:SECURE128:-VERS-SSL3.0:-VERS-TLS1.0)\n"
217 " disable verifying the hostname against the server certificate\n"
218 " --tls-fingerprint <string>\n"
219 " a SHA-256 hash of the server fingerprint to verify against\n"
223 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
224 " --identity, -i <filename>\n"
225 " the ssh identity file to use for authentication\n"
226 " --knownhosts, -k <filename>\n"
227 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
228 " --ssh-needs-passphrase\n"
229 " prompt for a passphrase for the SSH identity file\n"
230 " --ssh-passphrase-file <filename>\n"
231 " read the SSH private key passphrase from filename\n"
234 " do not lock the data file upon opening it\n"
235 " --lock-timeout <N>\n"
236 " time in tenths of a second to wait for a locked data file (50)\n"
237 " --name, -n <string>\n"
238 " set the client name\n"
239 " --pinentry <path>\n"
240 " the full path to the pinentry binary\n"
241 " --local-pinentry\n"
242 " force using a local pinentry\n"
244 " disable pinentry both remotely and locally\n"
245 " --ttyname, -y <path>\n"
246 " tty that pinentry will use\n"
247 " --ttytype, -t <string>\n"
248 " pinentry terminal type (default is $TERM)\n"
250 " pinentry display (default is $DISPLAY)\n"
251 " --lc-ctype <string>\n"
252 " locale setting for pinentry\n"
253 " --lc-messages <string>\n"
254 " locale setting for pinentry\n"
256 " number of pinentry tries before failing (3)\n"
257 " --timeout <seconds>\n"
258 " pinentry timeout\n"
259 " --inquire <COMMAND>\n"
260 " the specified command (with any options) uses a server inquire while\n"
261 " command data is read via the inquire file descriptor (stdin)\n"
262 " --inquire-line, -L <STRING>\n"
263 " the initial line to send (i.e., element path) before the inquire data\n"
264 " --inquire-fd <FD>\n"
265 " read inquire data from the specified file descriptor (stdin)\n"
266 " --inquire-file <filename>\n"
267 " read inquire data from the specified filename\n"
268 " --output-fd <FD>\n"
269 " redirect command output to the specified file descriptor\n"
271 " send the SAVE command before exiting\n"
272 " --passphrase-file <filename>\n"
273 " obtain the passphrase from the specified filename\n"
274 " --new-passphrase-file <filename>\n"
275 " obtain the passphrase to save with from the specified filename\n"
276 " --sign-passphrase-file <filename>\n"
277 " obtain the passphrase to sign with from the specified filename\n"
278 " --key-params <filename>\n"
279 " key parameters to use for key generation (pwmd default)\n"
280 " --keyid <recipient>[,<recipient>]\n"
281 " the public key ID to u\n"
282 " --sign-keyid <string>\n"
283 " the key ID to sign the data file with\n"
285 " use conventional encryption with optional signer(s) for new files\n"
287 " disable showing of status messages from the server\n"
289 " enable receiving of client STATE status messages\n"
290 " --status-fd <FD>\n"
291 " redirect status messages to the specified file descriptor\n"
292 " --status-ignore <string[,...]>\n"
293 " prevent parsing of the specified status message keywords\n"
295 " disable showing of extra messages (implies --no-status)\n"
296 #ifdef HAVE_LIBREADLINE
297 " --no-interactive\n"
298 " disable interactive mode\n"
303 #ifdef DEFAULT_PWMD_SOCKET
309 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
311 "An optional url may be in the form of:\n"
312 " --url /path/to/socket\n"
313 " --url file://[/path/to/socket]\n"
316 " --url ssh[46]://[username@]hostname[:port] (uses ssh-agent)\n"
317 " -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
321 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
322 " --client-key filename\n"
324 #ifdef HAVE_LIBREADLINE
326 "Interactive mode is used when input is from a terminal.\n"
333 inquire_cb (void *user
, const char *keyword
, gpg_error_t rc
,
334 char **data
, size_t * size
)
336 struct inquire_s
*inq
= user
;
338 int is_newpassword
= 0;
348 if (!strcmp (keyword
, "PASSPHRASE"))
350 else if (!strcmp (keyword
, "SIGN_PASSPHRASE"))
352 else if (!strcmp (keyword
, "NEW_PASSPHRASE"))
354 #ifdef HAVE_LIBREADLINE
355 else if (!strcmp (keyword
, "KEYPARAM") && !interactive
)
358 else if (!strcmp (keyword
, "KEYPARAM"))
362 if (!keyparams
|| !*keyparams
)
363 return gpg_error (GPG_ERR_INV_PARAMETER
);
365 fd
= open (keyparams
, O_RDONLY
);
368 fprintf (stderr
, "%s: %s\n", keyparams
, strerror (errno
));
369 return gpg_error_from_syserror ();
372 rc
= set_inquire (fd
, NULL
, &inq
);
380 fprintf (stderr
, N_("Using file '%s' as %s.\n"), keyparams
, keyword
);
385 if ((is_password
&& !keyfile
) || (is_newpassword
&& !new_keyfile
)
386 || (sign
&& !sign_keyfile
))
391 /* Try to use the local pinentry between inquires (new/sign/passphrase).
392 * If --no-pinentry was specified then the passphrase is read from the
393 * terminal as usual. */
394 pwmd_getopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, &local
);
395 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, 1);
396 rc
= pwmd_password (pwm
, keyword
, &tmp
, &inq
->len
);
397 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local
);
398 if (rc
&& gpg_err_code (rc
) != GPG_ERR_EOF
)
401 pwmd_free (inq
->line
);
405 return gpg_error (GPG_ERR_EOF
);
407 else if ((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
)
408 || (sign
&& sign_keyfile
))
413 fd
= open (sign_keyfile
, O_RDONLY
);
415 fd
= open (is_password
|| sign
? keyfile
: new_keyfile
, O_RDONLY
);
420 fprintf (stderr
, "%s: %s\n", sign_keyfile
, strerror (errno
));
422 fprintf (stderr
, "%s: %s\n", is_newpassword
? new_keyfile
423 : keyfile
, strerror (errno
));
424 return gpg_error_from_syserror ();
427 rc
= set_inquire (fd
, NULL
, &inq
);
435 fprintf (stderr
, N_("Using keyfile '%s' as %s.\n"),
436 sign
? sign_keyfile
: is_newpassword
? new_keyfile
439 #ifdef HAVE_LIBREADLINE
440 else if ((!inq
->last_keyword
|| strcmp (keyword
, inq
->last_keyword
))
441 && interactive
&& inq
->fd
== STDIN_FILENO
)
445 ("%sPress CTRL-D to send the current line. Press twice to end. %s:\n"),
446 inq
->last_keyword
? "\n" : "", keyword
);
447 pwmd_free (inq
->last_keyword
);
448 inq
->last_keyword
= pwmd_strdup (keyword
);
452 /* The first part of the command data. */
458 return inq
->fd
== -1 ? gpg_error (GPG_ERR_EOF
) : 0;
461 *size
= read (inq
->fd
, inq
->line
, ASSUAN_LINELENGTH
);
465 return gpg_error (gpg_error_from_syserror ());
469 else if (inq
->fd
!= STDIN_FILENO
&&
470 (is_newpassword
|| is_password
|| sign
|| is_keyparam
))
478 if (((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
)
479 || (sign
&& sign_keyfile
) || (keyparams
&& is_keyparam
))
480 && *size
== inq
->size
)
481 return gpg_error (GPG_ERR_EOF
);
483 return *size
? 0 : gpg_error (GPG_ERR_EOF
);
487 status_msg_cb (void *data
, const char *line
)
489 char *p
= strchr (line
, ' ');
494 /* Ignore status messages specified by the client via --status-ignore. */
495 for (s
= status_ignore
; s
&& *s
; s
++)
497 char *tmp
= strchr (line
, ' ');
498 size_t len
= tmp
? strlen (line
) - strlen (tmp
) : strlen (line
);
500 if (!strncmp (line
, *s
, len
) && len
== strlen (*s
))
504 #ifdef HAVE_LIBREADLINE
505 if (interactive
&& !strncmp (line
, "XFER ", 5)
507 if (!strncmp (line
, "XFER ", 5)
509 && *line
!= '#' && p
&& strchr (p
, ' ') && *++p
)
511 char *p1
= strchr (p
, ' ');
512 int a
= strtol (p
, NULL
, 10);
514 if (isdigit (*p
) && p1
)
516 int b
= strtol (p1
, NULL
, 10);
518 int t
= a
&& b
? a
* 100 / b
: 0;
520 strncpy (l
, line
, strlen (line
) - strlen (p
) - 1);
521 fprintf (statusfp
, "\rS:%s %i/%i %i%%%s", l
, a
, b
, t
,
528 fprintf (statusfp
, "S:%s\n", line
);
530 #ifdef HAVE_LIBREADLINE
539 return pwmd_process (pwm
);
542 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
544 is_remote_url (const char *str
)
547 return PWMD_SOCKET_LOCAL
;
550 if (strstr (str
, "ssh://") || strstr (str
, "ssh4://")
551 || strstr (str
, "ssh6://"))
552 return PWMD_SOCKET_SSH
;
556 if (strstr (str
, "tls://") || strstr (str
, "tls4://")
557 || strstr (str
, "tls6://"))
558 return PWMD_SOCKET_TLS
;
561 return PWMD_SOCKET_LOCAL
;
566 escape (const char *str
)
569 char *buf
= pwmd_malloc (ASSUAN_LINELENGTH
+ 1), *b
= buf
;
572 for (p
= str
; *p
; p
++, len
++)
574 if (len
== ASSUAN_LINELENGTH
)
618 free_inquire (struct inquire_s
*inq
)
623 pwmd_free (inq
->line
);
625 if (inq
->fd
!= -1 && inq
->fd
!= STDIN_FILENO
)
628 pwmd_free (inq
->last_keyword
);
632 /* When *result is not NULL it is updated to the new values and not
635 set_inquire (int fd
, const char *line
, struct inquire_s
**result
)
637 struct inquire_s inq
= { 0 };
638 struct stat st
= { 0 };
643 if (fstat (fd
, &st
) == -1)
644 return gpg_error_from_syserror ();
646 inq
.size
= st
.st_size
;
650 inq
.line
= pwmd_calloc (1, ASSUAN_LINELENGTH
);
652 return GPG_ERR_ENOMEM
;
656 char *s
= escape (line
);
660 pwmd_free (inq
.line
);
661 return GPG_ERR_ENOMEM
;
664 if (strlen (s
) >= ASSUAN_LINELENGTH
)
666 pwmd_free (inq
.line
);
668 return GPG_ERR_LINE_TOO_LONG
;
671 strncpy (inq
.line
, s
, ASSUAN_LINELENGTH
- 1);
672 inq
.len
= strlen (s
);
676 rc
= pwmd_setopt (pwm
, PWMD_OPTION_INQUIRE_TOTAL
,
677 st
.st_size
? st
.st_size
+ strlen (inq
.line
) : 0);
680 pwmd_free (inq
.line
);
685 *result
= pwmd_malloc (sizeof (struct inquire_s
));
688 if ((*result
)->fd
!= -1 && (*result
)->fd
!= STDIN_FILENO
)
689 close ((*result
)->fd
);
691 pwmd_free ((*result
)->line
);
692 (*result
)->line
= NULL
;
697 memcpy (*result
, &inq
, sizeof (struct inquire_s
));
698 memset (&inq
, 0, sizeof (struct inquire_s
));
702 #ifdef HAVE_LIBREADLINE
704 interactive_hook (void)
706 interactive_error
= process_cmd ();
708 if (interactive_error
)
709 rl_event_hook
= NULL
;
715 get_readline_char (FILE *fp
)
718 && (!strncmp (rl_line_buffer
, ".set passphrase-file ", 16)
719 || !strncmp (rl_line_buffer
, ".set new-passphrase-file ", 20)
720 || !strncmp (rl_line_buffer
, ".set sign-passphrase-file ", 21)))
721 rl_inhibit_completion
= 0;
722 else if (rl_line_buffer
723 && !strncmp (rl_line_buffer
, ".redir ", 7))
725 char *p
= strchr (rl_line_buffer
, ' ');
727 if (p
&& strchr (++p
, ' '))
728 rl_inhibit_completion
= 1;
730 rl_inhibit_completion
= 0;
732 else if (rl_line_buffer
733 && !strncmp (rl_line_buffer
, ".read ", 6))
735 char *p
= rl_line_buffer
+ 6;
737 if (strstr (p
, "--prefix "))
739 p
= strstr (p
, "--prefix ");
746 if (!p
|| strchr (p
, ' '))
747 rl_inhibit_completion
= 1;
749 rl_inhibit_completion
= 0;
752 rl_inhibit_completion
= 1;
762 ("------------------------------------------------------------\n"
763 "Elements are TAB delimited. Type HELP for protocol commands.\n"
764 "Type .help for pwmc commands. Press CTRL-D to quit.\n"
765 "------------------------------------------------------------\n"));
770 parse_arg (const char *src
, char *dst
, size_t len
)
776 for (; s
&& *s
&& *s
!= ' ' && n
< len
; s
++, n
++)
784 parse_opt (char **line
, const char *opt
, gpg_error_t
* rc
)
786 static char result
[ASSUAN_LINELENGTH
] = { 0 }, *r
= result
;
787 char *s
= strstr (*line
, opt
);
797 size_t rlen
= strlen (opt
);
801 while (*p
&& *p
== ' ')
807 for (; *p
&& len
< sizeof (result
) - 1; p
++, rlen
++)
809 if (isspace (*p
) && !quote
)
812 if (*p
== '\"' && lastc
!= '\\')
825 if (len
>= sizeof (result
) - 1)
826 *rc
= GPG_ERR_LINE_TOO_LONG
;
831 while (*p
&& *p
== ' ')
842 read_command (const char *line
, char **result
, size_t * len
)
847 struct inquire_s
*inq
= NULL
;
848 char *p
= (char *) line
;
849 const char *prefix
= parse_opt (&p
, "--prefix", &rc
);
850 char filebuf
[ASSUAN_LINELENGTH
];
859 while (*p
&& isspace (*p
))
862 file
= parse_arg (p
, filebuf
, sizeof (filebuf
));
865 p
+= strlen (file
) + 1;
867 while (*p
&& isspace (*p
))
879 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
882 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\\ = \\)\n"));
886 fd
= open (file
, O_RDONLY
);
888 return gpg_error_from_syserror ();
890 rc
= set_inquire (fd
, prefix
&& *prefix
? prefix
: NULL
, &inq
);
897 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, "%s", p
);
903 redir_command (const char *line
)
905 const char *p
= line
;
907 gpg_error_t rc
= GPG_ERR_SYNTAX
;
909 struct inquire_s
*inq
= NULL
;
912 char filebuf
[ASSUAN_LINELENGTH
];
916 file
= parse_arg (p
, filebuf
, sizeof (filebuf
));
919 p
+= strlen (file
) + 1;
921 while (*p
&& isspace (*p
))
931 fprintf (stderr
, N_("Usage: .redir <filename> <command> [args]\n"));
935 fd
= open (file
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600);
937 return gpg_error_from_syserror ();
939 #ifdef HAVE_LIBREADLINE
940 rc
= set_inquire (interactive
? STDIN_FILENO
: inquirefd
, NULL
, &inq
);
942 rc
= set_inquire (inquirefd
, NULL
, &inq
);
950 rc
= parse_dotcommand (p
, &result
, &len
, inq
);
951 if (!rc
&& result
&& len
--)
952 { // null byte which is always appended
953 if (write (fd
, result
, len
) != len
)
954 rc
= GPG_ERR_TOO_SHORT
;
964 help_command (const char *line
)
968 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
969 " .redir <filename> <command>\n"
970 " redirect the output of a command to the specified file\n"
972 " .open <filename>\n"
973 " open the specified filename losing any changes to the current one\n"
975 " .read [--prefix <string>] <filename> <command> [args]\n"
976 " obtain data from the specified filename for an inquire command\n"
978 " .set help | <name> [<value>]\n"
979 " set option <name> to <value>\n"
982 " generate a new key\n"
985 " write changes of the file to disk\n"
988 " change the passphrase of a data file\n"
990 " .listkeys [--options] [pattern[,..]]\n"
991 " show human readable output of the LISTKEYS command\n"
994 " this help text\n"));
999 open_command (char *line
)
1001 struct inquire_s
*inq
= NULL
;
1002 char *file
= line
, *tmp
= NULL
;
1006 while (file
&& isspace (*file
))
1011 char *p
= strrchr (file
, ' ');
1015 while (isspace (*p
))
1020 file
= tmp
= pwmd_strdup (file
+ (strlen (file
)-strlen (p
)));
1021 if (!file
|| !*file
)
1032 if (!file
|| !*file
)
1034 fprintf (stderr
, N_("Usage: .open [--options] <filename>\n"));
1035 return GPG_ERR_SYNTAX
;
1038 #ifdef HAVE_LIBREADLINE
1039 if (interactive
|| !quiet
)
1043 fprintf (stderr
, N_("Opening data file \"%s\" ...\n"), file
);
1045 #ifdef HAVE_LIBREADLINE
1046 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1048 rc
= set_inquire (-1, NULL
, &inq
);
1057 pwmd_getopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, &local
);
1061 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1063 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, 1);
1066 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1069 rc
= pwmd_open (pwm
, file
, inquire_cb
, inq
);
1071 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local
);
1073 #ifdef HAVE_LIBREADLINE
1083 pwmd_free (filename
);
1088 char *p
= pwmd_strdup (file
);
1090 pwmd_free (filename
);
1093 rc
= GPG_ERR_ENOMEM
;
1099 pwmd_free (filename
);
1107 set_command (const char *line
)
1110 char name
[256] = { 0 };
1111 char value
[512] = { 0 };
1114 const char *p
= line
;
1116 while (p
&& *p
&& isspace (*p
))
1119 namep
= parse_arg (p
, name
, sizeof (name
));
1120 if (!namep
|| !*namep
)
1122 fprintf (stderr
, N_("Usage: .set help | <name> [<value>]\n"));
1123 return GPG_ERR_SYNTAX
;
1126 p
+= strlen (namep
);
1127 while (p
&& *p
&& isspace (*p
))
1130 valuep
= parse_arg (p
, value
, sizeof (value
));
1132 if (!strcmp (name
, "passphrase-file") || !strcmp (name
, "new-passphrase-file")
1133 || !strcmp (name
, "sign-passphrase-file"))
1135 int is_newkeyfile
= 1;
1136 int sign
= !strcmp (name
, "sign-passphrase-file");
1138 if (!strcmp (name
, "passphrase-file") || sign
)
1143 pwmd_free (new_keyfile
);
1148 pwmd_free (sign_keyfile
);
1149 sign_keyfile
= NULL
;
1153 pwmd_free (keyfile
);
1160 new_keyfile
= pwmd_strdup (value
);
1162 sign_keyfile
= pwmd_strdup (value
);
1164 keyfile
= pwmd_strdup (value
);
1166 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1168 else if (!local_pin
&& !no_pinentry
)
1172 pwmd_socket_type (pwm
, &t
);
1173 if (t
== PWMD_SOCKET_LOCAL
)
1174 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1177 else if (!strcmp(name
, "pinentry-timeout"))
1180 int n
= strtol(valuep
, &e
, 10);
1183 return gpg_error (GPG_ERR_INV_VALUE
);
1186 n
= DEFAULT_PIN_TIMEOUT
;
1188 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, n
);
1190 else if (!strcmp (name
, "help"))
1194 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1195 "delimited. When no value is specified the option is unset.\n\n"
1196 "passphrase-file [<filename>]\n"
1197 " set or unset the file to be used when a passphrase is required (*)\n"
1199 "new-passphrase-file [<filename>]\n"
1200 " set or unset the file to be used when a new passphrase is required (*)\n"
1202 "sign-passphrase-file [<filename>]\n"
1203 " set or unset the file to be used when a passphrase is required for\n"
1204 " signing (symmetric) (*)\n"
1206 "pinentry-timeout <seconds>\n"
1207 " the amount of seconds before pinentry gives up waiting for input\n"
1209 "* = the next protocol command will unset this value\n"
1213 rc
= GPG_ERR_UNKNOWN_OPTION
;
1219 do_save_passwd_command (const char *line
, int which
)
1221 struct inquire_s
*inq
= NULL
;
1225 #ifdef HAVE_LIBREADLINE
1226 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1228 rc
= set_inquire (-1, NULL
, &inq
);
1233 pwmd_getopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, &local
);
1235 if (new_keyfile
|| keyfile
|| sign_keyfile
)
1237 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1239 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, 1);
1242 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1246 if (which
== SAVE_WHICH_SAVE
)
1247 rc
= pwmd_save (pwm
, line
, inquire_cb
, inq
);
1248 else if (which
== SAVE_WHICH_PASSWD
)
1249 rc
= pwmd_passwd (pwm
, line
, inquire_cb
, inq
);
1251 rc
= pwmd_genkey (pwm
, line
, inquire_cb
, inq
);
1254 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local
);
1256 #ifdef HAVE_LIBREADLINE
1266 save_command (const char *line
)
1268 return do_save_passwd_command (line
, SAVE_WHICH_SAVE
);
1272 search_and_replace (char *str
, const char *s
, const char r
)
1276 p
= strstr (str
, s
);
1282 search_and_replace (str
, s
, r
);
1288 openpgp_unescape (char *str
)
1290 search_and_replace (str
, "\\x3a", ':');
1291 search_and_replace (str
, "\\x5c", '\\');
1296 free_listkeys (struct slist_s
*keys
)
1300 t
= slist_length (keys
);
1301 for (i
= 0; i
< t
; i
++)
1303 struct keyid_s
*key
= slist_nth_data (keys
, i
);
1306 nt
= slist_length (key
->userids
);
1307 for (n
= 0; n
< nt
; n
++)
1309 struct userid_s
*userid
= slist_nth_data (key
->userids
, n
);
1311 pwmd_free (userid
->userid
);
1312 pwmd_free (userid
->name
);
1313 pwmd_free (userid
->email
);
1314 pwmd_free (userid
->comment
);
1318 slist_free (key
->userids
);
1319 nt
= slist_length (key
->subkeys
);
1320 for (n
= 0; n
< nt
; n
++)
1322 struct keyid_s
*sub
= slist_nth_data (key
->subkeys
, n
);
1324 pwmd_free (sub
->keyid
);
1325 pwmd_free (sub
->fpr
);
1326 pwmd_free (sub
->grip
);
1327 pwmd_free (sub
->card
);
1328 pwmd_free (sub
->curve
);
1332 slist_free (key
->subkeys
);
1340 openpgp_algorithm (struct keyid_s
*key
)
1361 return N_("Unknown");
1365 display_listkeys (struct slist_s
*keys
)
1369 t
= slist_length (keys
);
1370 for (i
= 0; i
< t
; i
++)
1372 struct keyid_s
*key
= slist_nth_data (keys
, i
);
1373 unsigned st
= slist_length (key
->subkeys
);
1375 unsigned ut
= slist_length (key
->userids
);
1378 for (u
= 0; u
< ut
; u
++)
1380 struct userid_s
*userid
= slist_nth_data (key
->userids
, u
);
1382 fprintf(stdout
, N_("User ID: %s\n"), userid
->userid
);
1385 for (s
= 0; s
< st
; s
++)
1387 struct keyid_s
*sub
= slist_nth_data (key
->subkeys
, s
);
1389 const char *caps
= NULL
;
1390 char expires
[11] = { 0 };
1391 char created
[11] = { 0 };
1395 tmp
= localtime (&sub
->expires
);
1396 strftime (expires
, sizeof (expires
), "%F", tmp
);
1399 tmp
= localtime (&sub
->created
);
1400 strftime (created
, sizeof (created
), "%F", tmp
);
1402 if (sub
->can_encrypt
)
1404 else if (sub
->can_sign
)
1406 else if (sub
->can_auth
)
1408 else if (sub
->can_certify
)
1412 " Subkey %u: %s [%s]%s%s %s-%u%s%s\n"
1413 " Created: %s %s%s\n"
1414 " Fingerprint: %s\n"
1420 sub
->secret
|| sub
->card
? "[P]" : "",
1421 sub
->revoked
? "[R]" : "",
1422 openpgp_algorithm (sub
),
1424 sub
->curve
? "-" : "",
1425 sub
->curve
? sub
->curve
: "",
1427 sub
->expired
? N_("Expired: ") : expires
[0] ? N_("Expires: ") : "",
1428 sub
->expired
|| expires
[0] ? expires
: "",
1431 sub
->card
? N_(" Card: ") : "",
1432 sub
->card
? sub
->card
: "",
1433 sub
->card
? "\n" : "");
1437 fprintf (stdout
, "\n");
1442 listkeys_command (const char *pattern
)
1446 char **lines
= NULL
, **p
;
1447 struct slist_s
*keys
= NULL
;
1449 rc
= pwmd_command (pwm
, &result
, NULL
, NULL
, NULL
, "LISTKEYS %s", pattern
);
1453 lines
= str_split (result
, "\n", 0);
1456 return GPG_ERR_ENOMEM
;
1458 for (p
= lines
; *p
; p
++)
1460 struct keyid_s
*key
;
1461 char **fields
= str_split (*p
, ":", 0);
1464 unsigned n_subkeys
= 0;
1465 struct slist_s
*tlist
;
1469 rc
= GPG_ERR_ENOMEM
;
1473 key
= pwmd_calloc (1, sizeof (struct keyid_s
));
1477 rc
= GPG_ERR_ENOMEM
;
1481 for (f
= i
= 0; i
< 17; i
++, f
++)
1486 b
= atoi (fields
[f
]) != 0;
1490 case 0: key
->revoked
= b
; break;
1491 case 1: key
->expired
= b
; break;
1492 case 4: key
->can_encrypt
= b
; break;
1493 case 5: key
->can_sign
= b
; break;
1494 case 7: key
->secret
= b
; break;
1495 case 16: n_subkeys
= strtoul (fields
[f
], NULL
, 10); break;
1501 for (s
= 0; s
< n_subkeys
; s
++)
1503 struct keyid_s
*sub
;
1506 sub
= pwmd_calloc (1, sizeof (struct keyid_s
));
1510 rc
= GPG_ERR_ENOMEM
;
1514 for (i
= 0; i
< 20; i
++, f
++)
1517 b
= atoi (fields
[f
]) != 0;
1521 case 0: sub
->revoked
= b
; break;
1522 case 1: sub
->expired
= b
; break;
1523 case 4: sub
->can_encrypt
= b
; break;
1524 case 5: sub
->can_sign
= b
; break;
1525 case 6: sub
->can_certify
= b
; break;
1526 case 7: sub
->secret
= b
; break;
1527 case 8: sub
->can_auth
= b
; break;
1528 case 11: sub
->algo
= atoi (fields
[f
]); break;
1529 case 12: sub
->bits
= atoi (fields
[f
]); break;
1530 case 13: sub
->keyid
= pwmd_strdup (fields
[f
]); break;
1531 case 14: sub
->fpr
= pwmd_strdup (fields
[f
]); break;
1532 case 15: sub
->grip
= pwmd_strdup (fields
[f
]); break;
1533 case 16: sub
->created
= strtoul (fields
[f
], NULL
, 10); break;
1534 case 17: sub
->expires
= strtoul (fields
[f
], NULL
, 10); break;
1535 case 18: sub
->card
= fields
[f
] && strlen(fields
[f
]) > 1
1536 ? pwmd_strdup (fields
[f
]) : NULL
; break;
1537 case 19: sub
->curve
= strlen (fields
[f
]) > 1 ? pwmd_strdup (openpgp_unescape(fields
[f
])) : NULL
; break;
1543 tlist
= slist_append (key
->subkeys
, sub
);
1546 rc
= GPG_ERR_ENOMEM
;
1550 key
->subkeys
= tlist
;
1559 // Re-create a line containing the userIds.
1560 for (; f
< strv_length (fields
); f
++)
1562 struct userid_s
*userid
;
1564 userid
= pwmd_calloc (1, sizeof (struct userid_s
));
1567 rc
= GPG_ERR_ENOMEM
;
1578 userid
->userid
= pwmd_strdup (openpgp_unescape (fields
[f
++]));
1579 userid
->name
= pwmd_strdup (openpgp_unescape (fields
[f
++]));
1580 userid
->email
= pwmd_strdup (openpgp_unescape (fields
[f
++]));
1581 userid
->comment
= pwmd_strdup (openpgp_unescape (fields
[f
]));
1583 tlist
= slist_append (key
->userids
, userid
);
1586 rc
= GPG_ERR_ENOMEM
;
1590 key
->userids
= tlist
;
1597 tlist
= slist_append (keys
, key
);
1600 rc
= GPG_ERR_ENOMEM
;
1610 display_listkeys (keys
);
1612 free_listkeys (keys
);
1617 parse_dotcommand (const char *line
, char **result
,
1618 size_t * len
, struct inquire_s
*inq
)
1620 const char *p
= line
;
1623 if (!strncmp (p
, ".read", 5))
1624 rc
= read_command (p
+ 5, result
, len
);
1625 else if (!strncmp (p
, ".redir", 6))
1626 rc
= redir_command (p
+ 6);
1627 else if (!strncmp (p
, ".help", 5))
1628 rc
= help_command (p
+ 5);
1629 else if (!strncmp (p
, ".open", 5))
1630 rc
= open_command ((char *)p
+ 5);
1631 else if (!strncmp (p
, ".set", 4))
1632 rc
= set_command (p
+ 4);
1633 else if (!strncmp (p
, ".save", 5))
1634 rc
= do_save_passwd_command (p
+ 5, SAVE_WHICH_SAVE
);
1635 else if (!strncmp (p
, ".passwd", 7))
1636 rc
= do_save_passwd_command (p
+ 7, SAVE_WHICH_PASSWD
);
1637 else if (!strncmp (p
, ".genkey", 7))
1638 rc
= do_save_passwd_command (p
+ 7, SAVE_WHICH_GENKEY
);
1639 else if (!strncmp (p
, ".listkeys", 9))
1640 rc
= listkeys_command (p
+9);
1643 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, "%s", line
);
1644 #ifdef HAVE_LIBREADLINE
1649 #ifdef HAVE_LIBREADLINE
1653 if (!rc
&& !strncasecmp (line
, "RESET", 5))
1655 pwmd_free (filename
);
1663 #ifdef HAVE_LIBREADLINE
1664 #ifdef HAVE_READLINE_HISTORY
1666 add_history_item (const char *line
)
1668 HIST_ENTRY
**list
, *p
= NULL
;
1671 list
= history_list ();
1672 for (i
= 0; list
&& list
[i
]; i
++)
1674 if (!strcmp (list
[i
]->line
, line
))
1685 p
= remove_history (i
);
1686 #ifdef HAVE_FREE_HISTORY_ENTRY
1687 s
= free_history_entry (p
);
1700 struct inquire_s
*inq
= NULL
;
1703 rc
= process_cmd ();
1707 rc
= set_inquire (STDIN_FILENO
, NULL
, &inq
);
1712 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1714 rl_event_hook
= &interactive_hook
;
1715 rl_getc_function
= get_readline_char
;
1716 rl_set_keyboard_input_timeout (100000);
1721 char *result
= NULL
;
1725 snprintf (buf
, sizeof (buf
), "pwmc%s%s> ",
1726 filename
? ":" : "", filename
? filename
: "");
1727 line
= readline (buf
);
1728 if (interactive_error
)
1731 rc
= interactive_error
;
1741 if (gpg_err_code (rc
) != GPG_ERR_CANCELED
&&
1742 gpg_err_code (rc
) != GPG_ERR_EOF
)
1743 fprintf (stderr
, "ERR %i: %s\n", rc
, gpg_strerror (rc
));
1753 #ifdef HAVE_READLINE_HISTORY
1754 add_history_item (line
);
1756 rc
= parse_dotcommand (line
, &result
, &len
, inq
);
1762 if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
1763 (void) pwmd_command (pwm
, &tmp
, NULL
, NULL
, NULL
,
1764 "GETINFO last_error");
1766 show_error (pwm
, rc
, tmp
);
1769 else if (result
&& len
)
1770 printf ("%s%s", result
, result
[len
- 1] != '\n' ? "\n" : "");
1784 #ifdef HAVE_LIBREADLINE
1791 fprintf (stderr
, "\n");
1799 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1800 p
= fgets (buf
, sizeof (buf
), stdin
);
1814 return GPG_ERR_CANCELED
;
1818 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1819 "CLEARCACHE %s", filename
);
1823 interactive_hook ();
1839 if (save
&& !filename
)
1843 ("No filename was specified on the command line. Aborting.\n"));
1844 return GPG_ERR_CANCELED
;
1847 if (save
&& filename
)
1850 pwmd_strdup_printf ("%s %s%s %s%s %s",
1851 symmetric
? "--symmetric" : "",
1852 keyid
? "--keyid=" : "",
1854 sign_keyid
? "--sign-keyid=" : "",
1855 sign_keyid
? sign_keyid
: "",
1856 keyparams
? "--inquire-keyparam" : "");
1858 #ifdef HAVE_LIBREADLINE
1859 if (!quiet
|| interactive
)
1865 fprintf (stderr
, "\n");
1866 fprintf (stderr
, N_("Saving changes ...\n"));
1869 rc
= save_command (args
);
1873 #ifdef HAVE_LIBREADLINE
1875 return rc
? rc
: quit
? 0 : GPG_ERR_CANCELED
;
1882 parse_status_ignore (char *str
)
1886 strv_free (status_ignore
);
1887 status_ignore
= NULL
;
1891 while ((s
= strsep (&str
, ",")))
1893 char **p
= strv_cat (status_ignore
, pwmd_strdup (s
));
1897 strv_free (status_ignore
);
1898 status_ignore
= NULL
;
1906 main (int argc
, char *argv
[])
1909 int status_state
= 0;
1912 char command
[ASSUAN_LINELENGTH
], *p
= NULL
;
1913 char *result
= NULL
;
1915 char *pinentry_path
= NULL
;
1916 char *display
= NULL
, *tty
= NULL
, *ttytype
= NULL
;
1917 char *lcctype
= NULL
, *lcmessages
= NULL
;
1918 int outfd
= STDOUT_FILENO
;
1919 FILE *outfp
= stdout
;
1920 int show_status
= 1;
1921 const char *clientname
= "pwmc";
1922 char *inquire
= NULL
;
1923 char *inquire_line
= NULL
;
1926 int use_ssh_agent
= -1;
1927 char *knownhosts
= NULL
;
1928 char *identity
= NULL
;
1929 int needs_passphrase
= 0;
1930 char *ssh_passphrase_file
= NULL
;
1933 char *cacert
= NULL
;
1934 char *clientcert
= NULL
;
1935 char *clientkey
= NULL
;
1937 int tls_verify
= -1;
1938 char *tls_fingerprint
= NULL
;
1940 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1941 pwmd_socket_t socktype
;
1942 long socket_timeout
= 300;
1943 int connect_timeout
= 120;
1945 #ifdef HAVE_LIBREADLINE
1946 int no_interactive
= 0;
1948 int lock_on_open
= -1;
1949 long lock_timeout
= 50;
1952 /* The order is important. */
1955 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1956 OPT_SOCKET_TIMEOUT
, OPT_CONNECT_TIMEOUT
,
1959 OPT_USE_SSH_AGENT
, OPT_IDENTITY
, OPT_KNOWNHOSTS
, OPT_SSH_NEEDS_PASSPHRASE
,
1960 OPT_SSH_PASSPHRASE_FILE
,
1963 OPT_CACERT
, OPT_CLIENTCERT
, OPT_CLIENTKEY
, OPT_PRIORITY
, OPT_VERIFY
,
1966 OPT_URL
, OPT_LOCAL
, OPT_TTYNAME
, OPT_TTYTYPE
, OPT_DISPLAY
, OPT_LC_CTYPE
,
1967 OPT_LC_MESSAGES
, OPT_TIMEOUT
, OPT_TRIES
, OPT_PINENTRY
, OPT_KEYFILE
,
1968 OPT_PASSPHRASE_FILE
, OPT_NEW_KEYFILE
, OPT_NEW_PASSPHRASE_FILE
,
1969 OPT_SIGN_KEYFILE
, OPT_SIGN_PASSPHRASE_FILE
, OPT_NOLOCK
, OPT_LOCK_TIMEOUT
,
1970 OPT_SAVE
, OPT_OUTPUT_FD
, OPT_INQUIRE
, OPT_INQUIRE_FD
, OPT_INQUIRE_FILE
,
1971 OPT_INQUIRE_LINE
, OPT_NO_STATUS
, OPT_STATUS_IGNORE
, OPT_STATUSFD
, OPT_NAME
,
1972 OPT_VERSION
, OPT_HELP
, OPT_KEYID
, OPT_SIGN_KEYID
, OPT_SYMMETRIC
,
1973 OPT_KEYPARAMS
, OPT_NO_PINENTRY
, OPT_QUIET
, OPT_STATUS_STATE
,
1974 #ifdef HAVE_LIBREADLINE
1978 const struct option long_opts
[] = {
1979 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1980 {"socket-timeout", 1, 0, 0},
1981 {"connect-timeout", 1, 0, 0},
1985 {"no-ssh-agent", 0, 0, 0},
1986 {"identity", 1, 0, 'i'},
1987 {"knownhosts", 1, 0, 'k'},
1988 {"ssh-needs-passphrase", 0, 0, 0},
1989 {"ssh-passphrase-file", 1, 0, 0},
1992 {"ca-cert", 1, 0, 0},
1993 {"client-cert", 1, 0, 0},
1994 {"client-key", 1, 0, 0},
1995 {"tls-priority", 1, 0, 0},
1996 {"no-tls-verify", 0, 0, 0},
1997 {"tls-fingerprint", 1, 0, 0},
2000 {"local-pinentry", 0, 0},
2001 {"ttyname", 1, 0, 'y'},
2002 {"ttytype", 1, 0, 't'},
2003 {"display", 1, 0, 'd'},
2004 {"lc-ctype", 1, 0, 0},
2005 {"lc-messages", 1, 0, 0},
2006 {"timeout", 1, 0, 0},
2008 {"pinentry", 1, 0, 0},
2009 {"key-file", 1, 0, 0},
2010 {"passphrase-file", 1, 0, 0},
2011 {"new-key-file", 1, 0, 0},
2012 {"new-passphrase-file", 1, 0, 0},
2013 {"sign-key-file", 1, 0, 0},
2014 {"sign-passphrase-file", 1, 0, 0},
2015 {"no-lock", 0, 0, 0},
2016 {"lock-timeout", 1, 0, 0},
2017 {"save", 0, 0, 'S'},
2018 {"output-fd", 1, 0, 0},
2019 {"inquire", 1, 0, 0},
2020 {"inquire-fd", 1, 0, 0},
2021 {"inquire-file", 1, 0, 0},
2022 {"inquire-line", 1, 0, 'L'},
2023 {"no-status", 0, 0, 0},
2024 {"status-ignore", 1, 0, 0},
2025 {"status-fd", 1, 0, 0},
2026 {"name", 1, 0, 'n'},
2027 {"version", 0, 0, 0},
2030 {"sign-keyid", 1, 0, 0},
2031 {"symmetric", 0, 0, 0},
2032 {"key-params", 1, 0, 0},
2033 {"no-pinentry", 0, 0, 0},
2035 {"status-state", 0, 0, 0},
2036 #ifdef HAVE_LIBREADLINE
2037 {"no-interactive", 0, 0},
2042 const char *optstring
= "L:y:t:d:P:I:Sn:i:k:s";
2044 const char *optstring
= "L:y:t:d:P:I:Sn:s";
2049 setlocale (LC_ALL
, "");
2050 bindtextdomain ("libpwmd", LOCALEDIR
);
2053 tries
= DEFAULT_PIN_TRIES
;
2054 inquirefd
= STDIN_FILENO
;
2055 statusfd
= STDERR_FILENO
;
2057 tmp
= pwmd_strdup (DEFAULT_STATUS_IGNORE
);
2058 parse_status_ignore (tmp
);
2064 getopt_long (argc
, argv
, optstring
, long_opts
, &opt_index
)) != -1)
2068 /* Handle long options without a short option part. */
2072 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2073 case OPT_SOCKET_TIMEOUT
:
2074 socket_timeout
= strtol (optarg
, &p
, 10);
2076 case OPT_CONNECT_TIMEOUT
:
2077 connect_timeout
= strtol (optarg
, &p
, 10);
2081 case OPT_USE_SSH_AGENT
:
2084 case OPT_SSH_NEEDS_PASSPHRASE
:
2085 needs_passphrase
= 1;
2087 case OPT_SSH_PASSPHRASE_FILE
:
2088 ssh_passphrase_file
= optarg
;
2095 case OPT_CLIENTCERT
:
2096 clientcert
= optarg
;
2108 tls_fingerprint
= optarg
;
2118 case OPT_PASSPHRASE_FILE
:
2119 keyfile
= pwmd_strdup (optarg
);
2121 case OPT_NEW_KEYFILE
:
2122 case OPT_NEW_PASSPHRASE_FILE
:
2123 new_keyfile
= pwmd_strdup (optarg
);
2125 case OPT_SIGN_KEYFILE
:
2126 case OPT_SIGN_PASSPHRASE_FILE
:
2127 sign_keyfile
= pwmd_strdup (optarg
);
2132 case OPT_LOCK_TIMEOUT
:
2133 lock_timeout
= strtol (optarg
, &p
, 10);
2142 lcctype
= pwmd_strdup (optarg
);
2144 case OPT_LC_MESSAGES
:
2145 lcmessages
= pwmd_strdup (optarg
);
2148 timeout
= strtol (optarg
, &p
, 10);
2151 tries
= strtol (optarg
, &p
, 10);
2154 inquire
= escape (optarg
);
2156 case OPT_INQUIRE_FD
:
2157 inquirefd
= strtol (optarg
, &p
, 10);
2159 case OPT_INQUIRE_FILE
:
2160 inquirefd
= open (optarg
, O_RDONLY
);
2161 if (inquirefd
== -1)
2162 err (EXIT_FAILURE
, "%s", optarg
);
2165 outfd
= strtol (optarg
, &p
, 10);
2168 outfp
= fdopen (outfd
, "w");
2170 err (EXIT_FAILURE
, "%i", outfd
);
2177 statusfd
= strtol (optarg
, &p
, 10);
2180 statusfp
= fdopen (statusfd
, "w");
2182 err (EXIT_FAILURE
, "%i", statusfd
);
2185 case OPT_STATUS_IGNORE
:
2186 parse_status_ignore (optarg
);
2189 printf ("%s (pwmc)\n\n"
2190 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017\n"
2192 "Released under the terms of the LGPL v2.1. Use at your own risk.\n\n"
2193 "Compile-time features:\n"
2194 #ifdef HAVE_LIBREADLINE
2209 #ifdef WITH_PINENTRY
2224 "\n", PACKAGE_STRING
, PACKAGE_BUGREPORT
);
2225 exit (EXIT_SUCCESS
);
2227 pinentry_path
= optarg
;
2230 usage (argv
[0], EXIT_SUCCESS
);
2234 case OPT_SIGN_KEYID
:
2235 sign_keyid
= optarg
;
2241 case OPT_STATUS_STATE
:
2244 case OPT_NO_PINENTRY
:
2247 #ifdef HAVE_LIBREADLINE
2248 case OPT_NO_INTERACTIVE
:
2253 usage (argv
[0], EXIT_FAILURE
);
2258 fprintf (stderr
, N_("%s: invalid argument for option '--%s'\n"),
2259 argv
[0], long_opts
[opt_index
].name
);
2260 usage (argv
[0], EXIT_FAILURE
);
2269 knownhosts
= optarg
;
2273 inquire_line
= optarg
;
2288 clientname
= optarg
;
2291 usage (argv
[0], EXIT_FAILURE
);
2295 #ifdef HAVE_LIBREADLINE
2296 if (isatty (STDIN_FILENO
) && !inquire
&& !inquire_line
&& !no_interactive
)
2301 rc
= pwmd_new (clientname
, &pwm
);
2305 filename
= argv
[optind
] ? pwmd_strdup (argv
[optind
]) : NULL
;
2306 if (no_pinentry
!= -1)
2307 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
2309 rc
= pwmd_getopt (pwm
, PWMD_OPTION_NO_PINENTRY
, &no_pinentry
);
2313 if (local_pin
!= -1)
2314 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local_pin
);
2316 rc
= pwmd_getopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, &local_pin
);
2320 pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TRIES
, tries
);
2322 fprintf (stderr
, N_("Connecting ...\n"));
2324 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
2325 socktype
= is_remote_url (url
);
2326 if (socktype
!= PWMD_SOCKET_LOCAL
)
2329 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2330 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, connect_timeout
);
2335 if (socktype
== PWMD_SOCKET_SSH
)
2338 if (use_ssh_agent
== -1)
2339 rc
= pwmd_getopt (pwm
, PWMD_OPTION_SSH_AGENT
, &use_ssh_agent
);
2343 if (!getenv ("SSH_AUTH_SOCK") || identity
)
2346 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_AGENT
, use_ssh_agent
);
2353 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_NEEDS_PASSPHRASE
,
2358 if (ssh_passphrase_file
)
2363 if (stat (ssh_passphrase_file
, &st
) == -1)
2365 rc
= gpg_error_from_syserror ();
2366 fprintf(stderr
, "%s: %s\n", ssh_passphrase_file
,
2371 result
= pwmd_calloc (1, st
.st_size
+1);
2374 rc
= GPG_ERR_ENOMEM
;
2378 fd
= open (ssh_passphrase_file
, O_RDONLY
);
2381 len
= read (fd
, result
, st
.st_size
);
2382 if (len
== st
.st_size
)
2383 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_PASSPHRASE
, result
);
2385 rc
= gpg_error_from_syserror ();
2390 rc
= gpg_error_from_syserror ();
2398 fprintf(stderr
, "%s: %s\n", ssh_passphrase_file
,
2404 rc
= pwmd_connect (pwm
, url
, identity
, knownhosts
);
2410 if (tls_verify
!= -1)
2412 rc
= pwmd_setopt (pwm
, PWMD_OPTION_TLS_VERIFY
, tls_verify
);
2418 rc
= pwmd_setopt (pwm
, PWMD_OPTION_TLS_PRIORITY
, prio
);
2421 rc
= pwmd_connect (pwm
, url
, clientcert
, clientkey
, cacert
,
2427 rc
= pwmd_connect (pwm
, url
);
2429 rc
= pwmd_connect (pwm
, url
);
2435 fprintf (stderr
, N_("Connected.\n"));
2438 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2439 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, socket_timeout
);
2446 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
2447 "OPTION LOCK-TIMEOUT=%li", lock_timeout
);
2454 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
, "OPTION CLIENT-STATE=1");
2459 if (lock_on_open
!= -1)
2461 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCK_ON_OPEN
, lock_on_open
);
2466 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, NULL
, NULL
);
2472 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, timeout
);
2479 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_PATH
, pinentry_path
);
2486 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DISPLAY
, display
);
2493 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TTY
, tty
);
2500 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TERM
, ttytype
);
2507 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_CTYPE
, lcctype
);
2514 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_MESSAGES
, lcmessages
);
2521 rc
= pwmd_setopt (pwm
, PWMD_OPTION_STATUS_CB
, status_msg_cb
);
2528 rc
= open_command (filename
);
2533 #ifdef HAVE_LIBREADLINE
2536 rc
= do_interactive ();
2544 struct inquire_s
*inq
= NULL
;
2546 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2548 rc
= pwmd_command (pwm
, &result
, &len
, inquire_cb
, inq
, "%s", inquire
);
2554 if (fcntl (STDIN_FILENO
, F_SETFL
, O_NONBLOCK
) == -1)
2556 rc
= gpg_error_from_errno (errno
);
2564 rc
= process_cmd ();
2569 n
= read (STDIN_FILENO
, command
, sizeof (command
)-1);
2572 if (errno
== EAGAIN
)
2578 rc
= gpg_error_from_errno (errno
);
2589 if (!p
|| !*p
|| !strcasecmp (p
, "BYE"))
2593 struct inquire_s
*inq
= NULL
;
2594 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2597 rc
= parse_dotcommand (command
, &result
, &len
, inq
);
2607 fwrite (result
, 1, result
[len
- 1] == 0 ? len
- 1 : len
, outfp
);
2615 else if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
2616 (void) pwmd_command (pwm
, &result
, NULL
, NULL
, NULL
,
2617 "GETINFO last_error");
2619 #ifdef HAVE_LIBREADLINE
2622 wipememory (command
, 0, sizeof (command
));
2625 show_error (pwm
, rc
, result
);
2631 pwmd_free (filename
);
2632 pwmd_free (inquire
);
2633 strv_free (status_ignore
);
2634 if (connected
&& !quiet
)
2635 fprintf (stderr
, N_("Connection closed.\n"));
2637 exit (rc
? EXIT_FAILURE
: EXIT_SUCCESS
);