2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015,
4 Ben Kibbey <bjk@luxsci.net>
6 This file is part of libpwmd.
8 Libpwmd is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
13 Libpwmd is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Libpwmd. If not, see <http://www.gnu.org/licenses/>.
34 #include <sys/select.h>
36 #include <sys/types.h>
44 #include <gnutls/gnutls.h>
51 #ifdef HAVE_GETOPT_LONG
56 #include "getopt_long.h"
59 #ifdef HAVE_LIBREADLINE
60 #if defined(HAVE_READLINE_READLINE_H)
61 #include <readline/readline.h>
62 #elif defined(HAVE_READLINE_H)
64 #endif /* !defined(HAVE_READLINE_H) */
65 static int interactive_error
;
66 static int interactive
;
67 #endif /* HAVE_LIBREADLINE */
69 #ifdef HAVE_READLINE_HISTORY
70 #if defined(HAVE_READLINE_HISTORY_H)
71 #include <readline/history.h>
72 #elif defined(HAVE_HISTORY_H)
75 #endif /* HAVE_READLINE_HISTORY */
82 #define N_(msgid) gettext(msgid)
87 #define DEFAULT_STATUS_IGNORE "KEEPALIVE,STATE,GPGME,PASSPHRASE_INFO,PASSPHRASE_HINT"
88 #define DEFAULT_PIN_TIMEOUT 30
89 #define DEFAULT_PIN_TRIES 3
90 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
93 static int no_pinentry
;
95 static char *filename
;
98 static char *sign_keyid
;
100 static char *keyparams
;
101 static char *keyfile
;
102 static char *new_keyfile
;
103 static char *sign_keyfile
;
105 static int local_pin
;
106 static int inquirefd
;
110 static char **status_ignore
;
117 size_t size
; // from stat(2).
121 static gpg_error_t
finalize ();
122 static gpg_error_t
set_inquire (int fd
, const char *line
,
123 struct inquire_s
**result
);
124 static gpg_error_t
parse_dotcommand (const char *line
, char **result
,
125 size_t * len
, struct inquire_s
*inq
);
126 static gpg_error_t
open_command (char *line
);
129 show_error (pwm_t
*pwm
, gpg_error_t rc
, const char *str
)
133 int e
= pwmd_gnutls_error (pwm
, &tlsstr
);
136 fprintf(stderr
, "TLS: %s\n", tlsstr
);
138 fprintf (stderr
, "ERR %i: %s%s%s%s", rc
, gpg_strerror (rc
),
139 str
? ": " : "", str
? str
: "", str
? "" : "\n");
146 pwmd_free (new_keyfile
);
147 pwmd_free (sign_keyfile
);
148 keyfile
= new_keyfile
= sign_keyfile
= NULL
;
152 usage (const char *pn
, int status
)
154 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
155 N_("Usage: pwmc [options] [file]\n"
157 " a url string to connect to (%s, see below)\n"
158 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
159 " --connect-timeout <seconds>\n"
160 " seconds before connecting to a remote host fails (0=disabled, 120)\n"
161 " --socket-timeout <seconds>\n"
162 " seconds before a remote command fails (0=disabled, 300)\n"
165 " --ca-cert <filename>\n"
166 " certificate authority (CA) used to sign the server cert\n"
167 " --client-cert <filename>\n"
168 " client certificate to use for authentication\n"
169 " --client-key <filename>\n"
170 " key file used to protect the client certificate\n"
171 " --tls-priority <string>\n"
172 " compression, cipher and hash algorithm string\n"
173 " (SECURE256:SECURE192:SECURE128:-VERS-SSL3.0)\n"
175 " verify the hostname against the server certificate\n"
176 " --tls-fingerprint <string>\n"
177 " a SHA-256 hash of the server fingerprint to verify against\n"
181 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
182 " --identity, -i <filename>\n"
183 " the ssh identity file to use for authentication\n"
184 " --knownhosts, -k <filename>\n"
185 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
186 " --ssh-needs-passphrase\n"
187 " prompt for a passphrase for the SSH identity file\n"
190 " do not lock the data file upon opening it\n"
191 " --lock-timeout <N>\n"
192 " time in tenths of a second to wait for a locked data file (50)\n"
193 " --name, -n <string>\n"
194 " set the client name\n"
195 " --pinentry <path>\n"
196 " the full path to the pinentry binary\n"
197 " --local-pinentry\n"
198 " force using a local pinentry\n"
200 " disable pinentry both remotely and locally\n"
201 " --ttyname, -y <path>\n"
202 " tty that pinentry will use\n"
203 " --ttytype, -t <string>\n"
204 " pinentry terminal type (default is $TERM)\n"
206 " pinentry display (default is $DISPLAY)\n"
207 " --lc-ctype <string>\n"
208 " locale setting for pinentry\n"
209 " --lc-messages <string>\n"
210 " locale setting for pinentry\n"
212 " number of pinentry tries before failing (3)\n"
213 " --timeout <seconds>\n"
214 " pinentry timeout\n"
215 " --inquire <COMMAND>\n"
216 " the specified command (with any options) uses a server inquire while\n"
217 " command data is read via the inquire file descriptor (stdin)\n"
218 " --inquire-line, -L <STRING>\n"
219 " the initial line to send (i.e., element path) before the inquire data\n"
220 " --inquire-fd <FD>\n"
221 " read inquire data from the specified file descriptor (stdin)\n"
222 " --inquire-file <filename>\n"
223 " read inquire data from the specified filename\n"
224 " --output-fd <FD>\n"
225 " redirect command output to the specified file descriptor\n"
227 " send the SAVE command before exiting\n"
228 " --passphrase-file <filename>\n"
229 " obtain the passphrase from the specified filename\n"
230 " --new-passphrase-file <filename>\n"
231 " obtain the passphrase to save with from the specified filename\n"
232 " --sign-passphrase-file <filename>\n"
233 " obtain the passphrase to sign with (symmetric) from the specified filename\n"
234 " --key-params <filename>\n"
235 " key parameters to use for key generation (pwmd default)\n"
236 " --keyid <recipient>[,<recipient>]\n"
237 " the public key ID to u\n"
238 " --sign-keyid <string>\n"
239 " the key ID to sign the data file with\n"
241 " use conventional encryption with optional signer(s) for new files\n"
243 " disable showing of status messages from the server\n"
244 " --status-fd <FD>\n"
245 " redirect status messages to the specified file descriptor\n"
246 " --status-ignore <string[,...]>\n"
247 " prevent parsing of the specified status message keywords\n"
249 " disable showing of extra messages (implies --no-status)\n"
250 #ifdef HAVE_LIBREADLINE
252 " use a shell like interface to pwmd (allows more than one command)\n"
256 #ifdef DEFAULT_PWMD_SOCKET
262 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
264 "An optional url may be in the form of:\n"
265 " --url /path/to/socket\n"
266 " --url file://[path/to/socket]\n"
269 " --url ssh[46]://[username@]hostname[:port]\n"
270 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
274 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
275 " --client-key filename\n"
277 #ifdef HAVE_LIBREADLINE
279 "Interactive mode is used when input is from a terminal.\n"
286 inquire_cb (void *user
, const char *keyword
, gpg_error_t rc
,
287 char **data
, size_t * size
)
289 struct inquire_s
*inq
= user
;
291 int is_newpassword
= 0;
301 if (!strcmp (keyword
, "PASSPHRASE"))
303 else if (!strcmp (keyword
, "SIGN_PASSPHRASE"))
305 else if (!strcmp (keyword
, "NEW_PASSPHRASE"))
307 #ifdef HAVE_LIBREADLINE
308 else if (!strcmp (keyword
, "KEYPARAM") && !interactive
)
311 else if (!strcmp (keyword
, "KEYPARAM"))
315 if (!keyparams
|| !*keyparams
)
316 return gpg_error (GPG_ERR_INV_PARAMETER
);
318 fd
= open (keyparams
, O_RDONLY
);
321 fprintf (stderr
, "%s: %s\n", keyparams
, strerror (errno
));
322 return gpg_error_from_syserror ();
325 rc
= set_inquire (fd
, NULL
, &inq
);
333 fprintf (stderr
, N_("Using file '%s' as %s.\n"), keyparams
, keyword
);
338 if ((is_password
&& !keyfile
) || (is_newpassword
&& !new_keyfile
)
339 || (sign
&& !sign_keyfile
))
344 /* Try to use the local pinentry between inquires (new/sign/passphrase).
345 * If --no-pinentry was specified then the passphrase is read from the
346 * terminal as usual. */
347 pwmd_getopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, &local
);
348 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, 1);
349 rc
= pwmd_password (pwm
, keyword
, &tmp
, &inq
->len
);
350 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local
);
351 if (rc
&& gpg_err_code (rc
) != GPG_ERR_EOF
)
354 pwmd_free (inq
->line
);
358 return gpg_error (GPG_ERR_EOF
);
360 else if ((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
)
361 || (sign
&& sign_keyfile
))
366 fd
= open (sign_keyfile
, O_RDONLY
);
368 fd
= open (is_password
|| sign
? keyfile
: new_keyfile
, O_RDONLY
);
373 fprintf (stderr
, "%s: %s\n", sign_keyfile
, strerror (errno
));
375 fprintf (stderr
, "%s: %s\n", is_newpassword
? new_keyfile
376 : keyfile
, strerror (errno
));
377 return gpg_error_from_syserror ();
380 rc
= set_inquire (fd
, NULL
, &inq
);
388 fprintf (stderr
, N_("Using keyfile '%s' as %s.\n"),
389 sign
? sign_keyfile
: is_newpassword
? new_keyfile
392 #ifdef HAVE_LIBREADLINE
393 else if ((!inq
->last_keyword
|| strcmp (keyword
, inq
->last_keyword
))
398 ("%sPress CTRL-D to send the current line. Press twice to end. %s:\n"),
399 inq
->last_keyword
? "\n" : "", keyword
);
400 pwmd_free (inq
->last_keyword
);
401 inq
->last_keyword
= pwmd_strdup (keyword
);
405 /* The first part of the command data. */
411 return inq
->fd
== -1 ? gpg_error (GPG_ERR_EOF
) : 0;
414 *size
= read (inq
->fd
, inq
->line
, ASSUAN_LINELENGTH
);
418 return gpg_error (gpg_error_from_syserror ());
422 else if (inq
->fd
!= STDIN_FILENO
&&
423 (is_newpassword
|| is_password
|| sign
|| is_keyparam
))
431 if (((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
)
432 || (sign
&& sign_keyfile
) || (keyparams
&& is_keyparam
))
433 && *size
== inq
->size
)
434 return gpg_error (GPG_ERR_EOF
);
436 return *size
? 0 : gpg_error (GPG_ERR_EOF
);
440 status_msg_cb (void *data
, const char *line
)
442 char *p
= strchr (line
, ' ');
445 /* Ignore status messages specified by the client via --status-ignore. */
446 for (s
= status_ignore
; s
&& *s
; s
++)
448 char *tmp
= strchr (line
, ' ');
449 size_t len
= tmp
? strlen (line
) - strlen (tmp
) : strlen (line
);
451 if (!strncmp (line
, *s
, len
) && len
== strlen (*s
))
455 if (interactive
&& !strncmp (line
, "XFER ", 5) && *line
!= '#' && p
456 && strchr (p
, ' ') && *++p
)
458 char *p1
= strchr (p
, ' ');
459 int a
= strtol (p
, NULL
, 10);
461 if (isdigit (*p
) && p1
)
463 int b
= strtol (p1
, NULL
, 10);
465 int t
= a
&& b
? a
* 100 / b
: 0;
467 strncpy (l
, line
, strlen (line
) - strlen (p
) - 1);
468 fprintf (statusfp
, "\rS:%s %i/%i %i%%%s", l
, a
, b
, t
,
475 fprintf (statusfp
, "S:%s\n", line
);
477 #ifdef HAVE_LIBREADLINE
486 return pwmd_process (pwm
);
491 knownhost_cb (void *data
, const char *host
, const char *key
, size_t len
)
495 pwmd_strdup_printf (N_
496 ("Password Manager Daemon: %s\n\nWhile attempting an SSH connection to %s there was a problem verifying it's hostkey against the known and trusted hosts file because it's hostkey was not found.\n\nWould you like to treat this connection as trusted for this and future connections by adding %s's hostkey to the known hosts file?\n"),
497 (char *) data
, host
, host
);
499 if (no_pinentry
&& !isatty (STDIN_FILENO
))
501 fprintf (stderr
, N_("Input is not from a terminal! Failing.\n"));
503 return GPG_ERR_ENOTTY
;
505 else if (no_pinentry
)
507 for (char *p
= buf
, len
= 0; *p
; p
++, len
++)
516 while (len
&& !isspace (*(--p
)))
525 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_PROMPT
, N_("Accept [y/N]:"));
529 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, buf
);
535 return pwmd_getpin (pwm
, NULL
, NULL
, NULL
, PWMD_PINENTRY_CONFIRM
);
539 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
541 is_remote_url (const char *str
)
544 return PWMD_SOCKET_LOCAL
;
547 if (strstr (str
, "ssh://") || strstr (str
, "ssh4://")
548 || strstr (str
, "ssh6://"))
549 return PWMD_SOCKET_SSH
;
553 if (strstr (str
, "tls://") || strstr (str
, "tls4://")
554 || strstr (str
, "tls6://"))
555 return PWMD_SOCKET_TLS
;
558 return PWMD_SOCKET_LOCAL
;
563 escape (const char *str
)
566 char *buf
= pwmd_malloc (ASSUAN_LINELENGTH
+ 1), *b
= buf
;
569 for (p
= str
; *p
; p
++, len
++)
571 if (len
== ASSUAN_LINELENGTH
)
615 free_inquire (struct inquire_s
*inq
)
620 pwmd_free (inq
->line
);
622 if (inq
->fd
!= -1 && inq
->fd
!= STDIN_FILENO
)
625 pwmd_free (inq
->last_keyword
);
629 /* When *result is not NULL it is updated to the new values and not
632 set_inquire (int fd
, const char *line
, struct inquire_s
**result
)
634 struct inquire_s inq
= { 0 };
635 struct stat st
= { 0 };
640 if (fstat (fd
, &st
) == -1)
641 return gpg_error_from_syserror ();
643 inq
.size
= st
.st_size
;
647 inq
.line
= pwmd_calloc (1, ASSUAN_LINELENGTH
);
649 return GPG_ERR_ENOMEM
;
653 char *s
= escape (line
);
657 pwmd_free (inq
.line
);
658 return GPG_ERR_ENOMEM
;
661 if (strlen (s
) >= ASSUAN_LINELENGTH
)
663 pwmd_free (inq
.line
);
665 return GPG_ERR_LINE_TOO_LONG
;
668 strncpy (inq
.line
, s
, ASSUAN_LINELENGTH
- 1);
669 inq
.len
= strlen (s
);
673 rc
= pwmd_setopt (pwm
, PWMD_OPTION_INQUIRE_TOTAL
,
674 st
.st_size
? st
.st_size
+ strlen (inq
.line
) : 0);
677 pwmd_free (inq
.line
);
682 *result
= pwmd_malloc (sizeof (struct inquire_s
));
685 if ((*result
)->fd
!= -1 && (*result
)->fd
!= STDIN_FILENO
)
686 close ((*result
)->fd
);
688 pwmd_free ((*result
)->line
);
689 (*result
)->line
= NULL
;
694 memcpy (*result
, &inq
, sizeof (struct inquire_s
));
695 memset (&inq
, 0, sizeof (struct inquire_s
));
699 #ifdef HAVE_LIBREADLINE
701 interactive_hook (void)
703 interactive_error
= process_cmd ();
705 if (interactive_error
)
706 rl_event_hook
= NULL
;
712 get_readline_char (FILE *fp
)
715 && (!strncmp (rl_line_buffer
, ".set passphrase-file ", 16)
716 || !strncmp (rl_line_buffer
, ".set new-passphrase-file ", 20)
717 || !strncmp (rl_line_buffer
, ".set sign-passphrase-file ", 21)))
718 rl_inhibit_completion
= 0;
719 else if (rl_line_buffer
720 && !strncmp (rl_line_buffer
, ".redir ", 7))
722 char *p
= strchr (rl_line_buffer
, ' ');
724 if (strchr (++p
, ' '))
725 rl_inhibit_completion
= 1;
727 rl_inhibit_completion
= 0;
729 else if (rl_line_buffer
730 && !strncmp (rl_line_buffer
, ".read ", 6))
732 char *p
= rl_line_buffer
+ 6;
734 if (strstr (p
, "--prefix "))
736 p
= strstr (p
, "--prefix ");
743 if (!p
|| strchr (p
, ' '))
744 rl_inhibit_completion
= 1;
746 rl_inhibit_completion
= 0;
749 rl_inhibit_completion
= 1;
759 ("------------------------------------------------------------\n"
760 "Elements are TAB delimited. Type HELP for protocol commands.\n"
761 "Type .help for pwmc commands. Press CTRL-D to quit.\n"
762 "------------------------------------------------------------\n"));
767 parse_arg (const char *src
, char *dst
, size_t len
)
773 for (; s
&& *s
&& *s
!= ' ' && n
< len
; s
++, n
++)
781 parse_opt (char **line
, const char *opt
, gpg_error_t
* rc
)
783 static char result
[ASSUAN_LINELENGTH
] = { 0 }, *r
= result
;
784 char *s
= strstr (*line
, opt
);
794 size_t rlen
= strlen (opt
);
798 while (*p
&& *p
== ' ')
804 for (; *p
&& len
< sizeof (result
) - 1; p
++, rlen
++)
806 if (isspace (*p
) && !quote
)
809 if (*p
== '\"' && lastc
!= '\\')
822 if (len
>= sizeof (result
) - 1)
823 *rc
= GPG_ERR_LINE_TOO_LONG
;
828 while (*p
&& *p
== ' ')
839 read_command (const char *line
, char **result
, size_t * len
)
844 struct inquire_s
*inq
= NULL
;
845 char *p
= (char *) line
;
846 const char *prefix
= parse_opt (&p
, "--prefix", &rc
);
847 char filebuf
[ASSUAN_LINELENGTH
];
856 while (*p
&& isspace (*p
))
859 file
= parse_arg (p
, filebuf
, sizeof (filebuf
));
862 p
+= strlen (file
) + 1;
864 while (*p
&& isspace (*p
))
876 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
879 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\\ = \\)\n"));
883 fd
= open (file
, O_RDONLY
);
885 return gpg_error_from_syserror ();
887 rc
= set_inquire (fd
, prefix
&& *prefix
? prefix
: NULL
, &inq
);
894 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, "%s", p
);
900 redir_command (const char *line
)
902 const char *p
= line
;
904 gpg_error_t rc
= GPG_ERR_SYNTAX
;
906 struct inquire_s
*inq
= NULL
;
909 char filebuf
[ASSUAN_LINELENGTH
];
913 file
= parse_arg (p
, filebuf
, sizeof (filebuf
));
916 p
+= strlen (file
) + 1;
918 while (*p
&& isspace (*p
))
928 fprintf (stderr
, N_("Usage: .redir <filename> <command> [args]\n"));
932 fd
= open (file
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600);
934 return gpg_error_from_syserror ();
936 #ifdef HAVE_LIBREADLINE
937 rc
= set_inquire (interactive
? STDIN_FILENO
: inquirefd
, NULL
, &inq
);
939 rc
= set_inquire (inquirefd
, NULL
, &inq
);
947 rc
= parse_dotcommand (p
, &result
, &len
, inq
);
948 if (!rc
&& result
&& len
--)
949 { // null byte which is always appended
950 if (write (fd
, result
, len
) != len
)
951 rc
= GPG_ERR_TOO_SHORT
;
961 help_command (const char *line
)
964 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
965 " .redir <filename> <command>\n"
966 " redirect the output of a command to the specified file\n"
968 " .open <filename>\n"
969 " open the specified filename losing any changes to the current one\n"
971 " .read [--prefix <string>] <filename> <command> [args]\n"
972 " obtain data from the specified filename for an inquire command\n"
974 " .set help | <name> [<value>]\n"
975 " set option <name> to <value>\n"
978 " write changes of the file to disk\n"
981 " change the passphrase of a data file\n"
984 " this help text\n"));
989 open_command (char *line
)
991 struct inquire_s
*inq
= NULL
;
992 const char *file
= line
;
996 while (file
&& isspace (*file
))
1001 fprintf (stderr
, N_("Usage: .open <filename>\n"));
1002 return GPG_ERR_SYNTAX
;
1005 #ifdef HAVE_LIBREADLINE
1006 if (interactive
|| !quiet
)
1010 fprintf (stderr
, N_("Opening data file \"%s\" ...\n"), file
);
1012 #ifdef HAVE_LIBREADLINE
1013 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1015 rc
= set_inquire (-1, NULL
, &inq
);
1020 pwmd_getopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, &local
);
1024 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1026 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, 1);
1029 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1032 rc
= pwmd_open (pwm
, file
, inquire_cb
, inq
);
1034 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local
);
1036 #ifdef HAVE_LIBREADLINE
1042 if (!rc
&& file
!= filename
)
1044 pwmd_free (filename
);
1045 filename
= pwmd_strdup (file
);
1052 set_command (const char *line
)
1055 char name
[256] = { 0 };
1056 char value
[512] = { 0 };
1059 const char *p
= line
;
1061 while (p
&& *p
&& isspace (*p
))
1064 namep
= parse_arg (p
, name
, sizeof (name
));
1065 if (!namep
|| !*namep
)
1067 fprintf (stderr
, N_("Usage: .set help | <name> [<value>]\n"));
1068 return GPG_ERR_SYNTAX
;
1071 p
+= strlen (namep
);
1072 while (p
&& *p
&& isspace (*p
))
1075 valuep
= parse_arg (p
, value
, sizeof (value
));
1077 if (!strcmp (name
, "passphrase-file") || !strcmp (name
, "new-passphrase-file")
1078 || !strcmp (name
, "sign-passphrase-file"))
1080 int is_newkeyfile
= 1;
1081 int sign
= !strcmp (name
, "sign-passphrase-file");
1083 if (!strcmp (name
, "passphrase-file") || sign
)
1088 pwmd_free (new_keyfile
);
1093 pwmd_free (sign_keyfile
);
1094 sign_keyfile
= NULL
;
1098 pwmd_free (keyfile
);
1105 new_keyfile
= pwmd_strdup (value
);
1107 sign_keyfile
= pwmd_strdup (value
);
1109 keyfile
= pwmd_strdup (value
);
1111 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1113 else if (!local_pin
&& !no_pinentry
)
1117 pwmd_socket_type (pwm
, &t
);
1118 if (t
== PWMD_SOCKET_LOCAL
)
1119 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1122 else if (!strcmp(name
, "pinentry-timeout"))
1125 int n
= strtol(valuep
, &e
, 10);
1128 return gpg_error (GPG_ERR_INV_VALUE
);
1131 n
= DEFAULT_PIN_TIMEOUT
;
1133 rc
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, n
);
1135 else if (!strcmp (name
, "help"))
1139 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1140 "delimited. When no value is specified the option is unset.\n\n"
1141 "passphrase-file [<filename>]\n"
1142 " set or unset the file to be used when a passphrase is required (*)\n"
1144 "new-passphrase-file [<filename>]\n"
1145 " set or unset the file to be used when a new passphrase is required (*)\n"
1147 "sign-passphrase-file [<filename>]\n"
1148 " set or unset the file to be used when a passphrase is required for\n"
1149 " signing (symmetric) (*)\n"
1151 "pinentry-timeout <seconds>\n"
1152 " the amount of seconds before pinentry gives up waiting for input\n"
1154 "* = the next protocol command will unset this value\n"
1158 rc
= GPG_ERR_UNKNOWN_OPTION
;
1164 do_save_passwd_command (const char *line
, int save
)
1166 struct inquire_s
*inq
= NULL
;
1170 #ifdef HAVE_LIBREADLINE
1171 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1173 rc
= set_inquire (-1, NULL
, &inq
);
1178 pwmd_getopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, &local
);
1180 if (new_keyfile
|| keyfile
|| sign_keyfile
)
1182 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1184 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, 1);
1187 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1192 rc
= pwmd_save (pwm
, line
, inquire_cb
, inq
);
1194 rc
= pwmd_passwd (pwm
, line
, inquire_cb
, inq
);
1197 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local
);
1199 #ifdef HAVE_LIBREADLINE
1209 save_command (const char *line
)
1211 return do_save_passwd_command (line
, 1);
1215 parse_dotcommand (const char *line
, char **result
,
1216 size_t * len
, struct inquire_s
*inq
)
1218 const char *p
= line
;
1221 if (!strncmp (p
, ".read", 5))
1222 rc
= read_command (p
+ 5, result
, len
);
1223 else if (!strncmp (p
, ".redir", 6))
1224 rc
= redir_command (p
+ 6);
1225 else if (!strncmp (p
, ".help", 5))
1226 rc
= help_command (p
+ 5);
1227 else if (!strncmp (p
, ".open", 5))
1228 rc
= open_command ((char *)p
+ 5);
1229 else if (!strncmp (p
, ".set", 4))
1230 rc
= set_command (p
+ 4);
1231 else if (!strncmp (p
, ".save", 5))
1232 rc
= do_save_passwd_command (p
+ 5, 1);
1233 else if (!strncmp (p
, ".passwd", 7))
1234 rc
= do_save_passwd_command (p
+ 7, 0);
1237 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, "%s", line
);
1238 #ifdef HAVE_LIBREADLINE
1243 #ifdef HAVE_LIBREADLINE
1251 #ifdef HAVE_LIBREADLINE
1256 struct inquire_s
*inq
= NULL
;
1259 rc
= process_cmd ();
1263 rc
= set_inquire (STDIN_FILENO
, NULL
, &inq
);
1268 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1270 rl_event_hook
= &interactive_hook
;
1271 rl_getc_function
= get_readline_char
;
1272 rl_set_keyboard_input_timeout (100000);
1277 char *result
= NULL
;
1281 line
= readline ("pwmc> ");
1282 if (interactive_error
)
1285 rc
= interactive_error
;
1295 if (gpg_err_code (rc
) != GPG_ERR_CANCELED
&&
1296 gpg_err_code (rc
) != GPG_ERR_EOF
)
1297 fprintf (stderr
, "ERR %i: %s\n", rc
, gpg_strerror (rc
));
1307 #ifdef HAVE_READLINE_HISTORY
1310 rc
= parse_dotcommand (line
, &result
, &len
, inq
);
1316 if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
1317 (void) pwmd_command (pwm
, &tmp
, NULL
, NULL
, NULL
,
1318 "GETINFO last_error");
1320 show_error (pwm
, rc
, tmp
);
1323 else if (result
&& len
)
1324 printf ("%s%s", result
, result
[len
- 1] != '\n' ? "\n" : "");
1338 #ifdef HAVE_LIBREADLINE
1345 fprintf (stderr
, "\n");
1353 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1354 p
= fgets (buf
, sizeof (buf
), stdin
);
1368 return GPG_ERR_CANCELED
;
1372 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1373 "CLEARCACHE %s", filename
);
1377 interactive_hook ();
1393 if (save
&& !filename
)
1397 ("No filename was specified on the command line. Aborting.\n"));
1398 return GPG_ERR_CANCELED
;
1401 if (save
&& filename
)
1404 pwmd_strdup_printf ("%s %s%s %s%s %s",
1405 symmetric
? "--symmetric" : "",
1406 keyid
? "--keyid=" : "",
1408 sign_keyid
? "--sign-keyid=" : "",
1409 sign_keyid
? sign_keyid
: "",
1410 keyparams
? "--inquire-keyparam" : "");
1412 #ifdef HAVE_LIBREADLINE
1413 if (!quiet
|| interactive
)
1419 fprintf (stderr
, "\n");
1420 fprintf (stderr
, N_("Saving changes ...\n"));
1423 rc
= save_command (args
);
1427 #ifdef HAVE_LIBREADLINE
1429 return rc
? rc
: quit
? 0 : GPG_ERR_CANCELED
;
1436 parse_status_ignore (char *str
)
1441 for (p
= status_ignore
; p
&& *p
; p
++)
1444 pwmd_free (status_ignore
);
1445 status_ignore
= NULL
;
1449 while ((s
= strsep (&str
, ",")))
1451 p
= pwmd_realloc (status_ignore
, (n
+ 2) * sizeof (char *));
1452 p
[n
++] = pwmd_strdup (s
);
1459 main (int argc
, char *argv
[])
1464 char command
[ASSUAN_LINELENGTH
], *p
= NULL
;
1465 char *result
= NULL
;
1467 char *pinentry_path
= NULL
;
1468 char *display
= NULL
, *tty
= NULL
, *ttytype
= NULL
;
1469 char *lcctype
= NULL
, *lcmessages
= NULL
;
1470 int outfd
= STDOUT_FILENO
;
1471 FILE *outfp
= stdout
;
1472 FILE *inquirefp
= stdin
;
1473 int show_status
= 1;
1474 char *clientname
= "pwmc";
1475 char *inquire
= NULL
;
1476 char *inquire_line
= NULL
;
1479 int use_ssh_agent
= 1;
1480 char *knownhosts
= NULL
;
1481 char *identity
= NULL
;
1484 char *cacert
= NULL
;
1485 char *clientcert
= NULL
;
1486 char *clientkey
= NULL
;
1489 char *tls_fingerprint
= NULL
;
1491 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1492 pwmd_socket_t socktype
;
1493 long socket_timeout
= 300;
1494 int connect_timeout
= 120;
1495 int needs_passphrase
= 0;
1497 int lock_on_open
= 1;
1498 long lock_timeout
= 50;
1501 /* The order is important. */
1504 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1505 OPT_SOCKET_TIMEOUT
, OPT_CONNECT_TIMEOUT
,
1508 OPT_USE_SSH_AGENT
, OPT_IDENTITY
, OPT_KNOWNHOSTS
, OPT_SSH_NEEDS_PASSPHRASE
,
1511 OPT_CACERT
, OPT_CLIENTCERT
, OPT_CLIENTKEY
, OPT_PRIORITY
, OPT_VERIFY
,
1514 OPT_URL
, OPT_LOCAL
, OPT_TTYNAME
, OPT_TTYTYPE
, OPT_DISPLAY
, OPT_LC_CTYPE
,
1515 OPT_LC_MESSAGES
, OPT_TIMEOUT
, OPT_TRIES
, OPT_PINENTRY
, OPT_KEYFILE
,
1516 OPT_PASSPHRASE_FILE
, OPT_NEW_KEYFILE
, OPT_NEW_PASSPHRASE_FILE
,
1517 OPT_SIGN_KEYFILE
, OPT_SIGN_PASSPHRASE_FILE
, OPT_NOLOCK
, OPT_LOCK_TIMEOUT
,
1518 OPT_SAVE
, OPT_OUTPUT_FD
, OPT_INQUIRE
, OPT_INQUIRE_FD
, OPT_INQUIRE_FILE
,
1519 OPT_INQUIRE_LINE
, OPT_NO_STATUS
, OPT_STATUS_IGNORE
, OPT_STATUSFD
, OPT_NAME
,
1520 OPT_VERSION
, OPT_HELP
, OPT_KEYID
, OPT_SIGN_KEYID
, OPT_SYMMETRIC
,
1521 OPT_KEYPARAMS
, OPT_NO_PINENTRY
, OPT_QUIET
,
1522 #ifdef HAVE_LIBREADLINE
1526 const struct option long_opts
[] = {
1527 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1528 {"socket-timeout", 1, 0, 0},
1529 {"connect-timeout", 1, 0, 0},
1533 {"no-ssh-agent", 0, 0, 0},
1534 {"identity", 1, 0, 'i'},
1535 {"knownhosts", 1, 0, 'k'},
1536 {"ssh-needs-passphrase", 0, 0, 0},
1539 {"ca-cert", 1, 0, 0},
1540 {"client-cert", 1, 0, 0},
1541 {"client-key", 1, 0, 0},
1542 {"tls-priority", 1, 0, 0},
1543 {"tls-verify", 0, 0, 0},
1544 {"tls-fingerprint", 1, 0, 0},
1547 {"local-pinentry", 0, 0},
1548 {"ttyname", 1, 0, 'y'},
1549 {"ttytype", 1, 0, 't'},
1550 {"display", 1, 0, 'd'},
1551 {"lc-ctype", 1, 0, 0},
1552 {"lc-messages", 1, 0, 0},
1553 {"timeout", 1, 0, 0},
1555 {"pinentry", 1, 0, 0},
1556 {"key-file", 1, 0, 0},
1557 {"passphrase-file", 1, 0, 0},
1558 {"new-key-file", 1, 0, 0},
1559 {"new-passphrase-file", 1, 0, 0},
1560 {"sign-key-file", 1, 0, 0},
1561 {"sign-passphrase-file", 1, 0, 0},
1562 {"no-lock", 0, 0, 0},
1563 {"lock-timeout", 1, 0, 0},
1564 {"save", 0, 0, 'S'},
1565 {"output-fd", 1, 0, 0},
1566 {"inquire", 1, 0, 0},
1567 {"inquire-fd", 1, 0, 0},
1568 {"inquire-file", 1, 0, 0},
1569 {"inquire-line", 1, 0, 'L'},
1570 {"no-status", 0, 0, 0},
1571 {"status-ignore", 1, 0, 0},
1572 {"status-fd", 1, 0, 0},
1573 {"name", 1, 0, 'n'},
1574 {"version", 0, 0, 0},
1577 {"sign-keyid", 1, 0, 0},
1578 {"symmetric", 0, 0, 0},
1579 {"key-params", 1, 0, 0},
1580 {"no-pinentry", 0, 0, 0},
1582 #ifdef HAVE_LIBREADLINE
1583 {"interactive", 0, 0},
1588 const char *optstring
= "L:y:t:d:P:I:Sn:i:k:s";
1590 const char *optstring
= "L:y:t:d:P:I:Sn:s";
1595 setlocale (LC_ALL
, "");
1596 bindtextdomain ("libpwmd", LOCALEDIR
);
1599 tries
= DEFAULT_PIN_TRIES
;
1600 inquirefd
= STDIN_FILENO
;
1601 statusfd
= STDERR_FILENO
;
1602 statusfp
= fdopen (statusfd
, "w");
1603 tmp
= pwmd_strdup (DEFAULT_STATUS_IGNORE
);
1604 parse_status_ignore (tmp
);
1608 getopt_long (argc
, argv
, optstring
, long_opts
, &opt_index
)) != -1)
1612 /* Handle long options without a short option part. */
1616 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1617 case OPT_SOCKET_TIMEOUT
:
1618 socket_timeout
= strtol (optarg
, &p
, 10);
1620 case OPT_CONNECT_TIMEOUT
:
1621 connect_timeout
= strtol (optarg
, &p
, 10);
1625 case OPT_USE_SSH_AGENT
:
1628 case OPT_SSH_NEEDS_PASSPHRASE
:
1629 needs_passphrase
= 1;
1636 case OPT_CLIENTCERT
:
1637 clientcert
= optarg
;
1649 tls_fingerprint
= optarg
;
1659 case OPT_PASSPHRASE_FILE
:
1660 keyfile
= pwmd_strdup (optarg
);
1662 case OPT_NEW_KEYFILE
:
1663 case OPT_NEW_PASSPHRASE_FILE
:
1664 new_keyfile
= pwmd_strdup (optarg
);
1666 case OPT_SIGN_KEYFILE
:
1667 case OPT_SIGN_PASSPHRASE_FILE
:
1668 sign_keyfile
= pwmd_strdup (optarg
);
1673 case OPT_LOCK_TIMEOUT
:
1674 lock_timeout
= strtol (optarg
, &p
, 10);
1683 lcctype
= pwmd_strdup (optarg
);
1685 case OPT_LC_MESSAGES
:
1686 lcmessages
= pwmd_strdup (optarg
);
1689 timeout
= strtol (optarg
, &p
, 10);
1692 tries
= strtol (optarg
, &p
, 10);
1695 inquire
= escape (optarg
);
1697 case OPT_INQUIRE_FD
:
1698 inquirefd
= strtol (optarg
, &p
, 10);
1701 inquirefp
= fdopen (inquirefd
, "r");
1703 err (EXIT_FAILURE
, "%i", inquirefd
);
1706 case OPT_INQUIRE_FILE
:
1707 inquirefd
= open (optarg
, O_RDONLY
);
1708 if (inquirefd
== -1)
1709 err (EXIT_FAILURE
, "%s", optarg
);
1710 inquirefp
= fdopen (inquirefd
, "r");
1713 outfd
= strtol (optarg
, &p
, 10);
1716 outfp
= fdopen (outfd
, "w");
1718 err (EXIT_FAILURE
, "%i", outfd
);
1725 statusfd
= strtol (optarg
, &p
, 10);
1728 statusfp
= fdopen (statusfd
, "w");
1730 err (EXIT_FAILURE
, "%i", statusfd
);
1733 case OPT_STATUS_IGNORE
:
1734 parse_status_ignore (optarg
);
1737 printf ("%s (pwmc)\n\n"
1738 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016\n"
1740 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1741 "Compile-time features:\n"
1742 #ifdef HAVE_LIBREADLINE
1757 #ifdef WITH_PINENTRY
1772 "\n", PACKAGE_STRING
, PACKAGE_BUGREPORT
);
1773 exit (EXIT_SUCCESS
);
1775 pinentry_path
= optarg
;
1778 usage (argv
[0], EXIT_SUCCESS
);
1782 case OPT_SIGN_KEYID
:
1783 sign_keyid
= optarg
;
1789 case OPT_NO_PINENTRY
:
1792 #ifdef HAVE_LIBREADLINE
1793 case OPT_INTERACTIVE
:
1798 usage (argv
[0], EXIT_FAILURE
);
1803 fprintf (stderr
, N_("%s: invalid argument for option '--%s'\n"),
1804 argv
[0], long_opts
[opt_index
].name
);
1805 usage (argv
[0], EXIT_FAILURE
);
1814 knownhosts
= optarg
;
1818 inquire_line
= optarg
;
1833 clientname
= optarg
;
1836 usage (argv
[0], EXIT_FAILURE
);
1840 #ifdef HAVE_LIBREADLINE
1841 if (interactive
&& !isatty (STDIN_FILENO
))
1842 usage (argv
[0], EXIT_FAILURE
);
1843 else if (isatty (STDIN_FILENO
) && !inquire
&& !inquire_line
)
1848 rc
= pwmd_new (clientname
, &pwm
);
1852 filename
= argv
[optind
] ? pwmd_strdup (argv
[optind
]) : NULL
;
1853 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
1857 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local_pin
);
1861 pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TRIES
, tries
);
1863 fprintf (stderr
, N_("Connecting ...\n"));
1865 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1866 socktype
= is_remote_url (url
);
1867 if (socktype
!= PWMD_SOCKET_LOCAL
)
1870 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1871 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, connect_timeout
);
1876 if (socktype
== PWMD_SOCKET_SSH
)
1879 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_CB
, knownhost_cb
);
1883 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_DATA
, clientname
);
1887 if (!getenv ("SSH_AUTH_SOCK") || identity
)
1890 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_AGENT
, use_ssh_agent
);
1894 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_NEEDS_PASSPHRASE
,
1899 rc
= pwmd_connect (pwm
, url
, identity
, knownhosts
);
1905 rc
= pwmd_setopt (pwm
, PWMD_OPTION_TLS_VERIFY
, tls_verify
);
1909 rc
= pwmd_connect (pwm
, url
, clientcert
, clientkey
, cacert
, prio
,
1915 rc
= pwmd_connect (pwm
, url
);
1917 rc
= pwmd_connect (pwm
, url
);
1923 fprintf (stderr
, N_("Connected.\n"));
1926 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1927 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, socket_timeout
);
1934 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1935 "OPTION LOCK-TIMEOUT=%li", lock_timeout
);
1942 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCK_ON_OPEN
, 1);
1947 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, NULL
, NULL
);
1953 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, timeout
);
1960 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_PATH
, pinentry_path
);
1967 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DISPLAY
, display
);
1974 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TTY
, tty
);
1981 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TERM
, ttytype
);
1988 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_CTYPE
, lcctype
);
1995 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_MESSAGES
, lcmessages
);
2002 rc
= pwmd_setopt (pwm
, PWMD_OPTION_STATUS_CB
, status_msg_cb
);
2009 rc
= open_command (filename
);
2014 #ifdef HAVE_LIBREADLINE
2017 rc
= do_interactive ();
2025 struct inquire_s
*inq
= NULL
;
2027 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2029 rc
= pwmd_command (pwm
, &result
, &len
, inquire_cb
, inq
, "%s", inquire
);
2035 if (fcntl (STDIN_FILENO
, F_SETFL
, O_NONBLOCK
) == -1)
2037 rc
= gpg_error_from_errno (errno
);
2045 rc
= process_cmd ();
2050 n
= read (STDIN_FILENO
, command
, sizeof (command
)-1);
2053 if (errno
== EAGAIN
)
2059 rc
= gpg_error_from_errno (errno
);
2070 if (!p
|| !*p
|| !strcasecmp (p
, "BYE"))
2074 struct inquire_s
*inq
= NULL
;
2075 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2078 rc
= parse_dotcommand (command
, &result
, &len
, inq
);
2088 fwrite (result
, 1, result
[len
- 1] == 0 ? len
- 1 : len
, outfp
);
2096 else if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
2097 (void) pwmd_command (pwm
, &result
, NULL
, NULL
, NULL
,
2098 "GETINFO last_error");
2100 #ifdef HAVE_LIBREADLINE
2103 wipememory (command
, 0, sizeof (command
));
2106 show_error (pwm
, rc
, result
);
2112 pwmd_free (filename
);
2113 parse_status_ignore (NULL
);
2114 if (connected
&& !quiet
)
2115 fprintf (stderr
, N_("Connection closed.\n"));
2117 exit (rc
? EXIT_FAILURE
: EXIT_SUCCESS
);