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
))
394 && interactive
&& inq
->fd
== STDIN_FILENO
)
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 #ifdef HAVE_LIBREADLINE
456 if (interactive
&& !strncmp (line
, "XFER ", 5)
458 if (!strncmp (line
, "XFER ", 5)
460 && *line
!= '#' && p
&& strchr (p
, ' ') && *++p
)
462 char *p1
= strchr (p
, ' ');
463 int a
= strtol (p
, NULL
, 10);
465 if (isdigit (*p
) && p1
)
467 int b
= strtol (p1
, NULL
, 10);
469 int t
= a
&& b
? a
* 100 / b
: 0;
471 strncpy (l
, line
, strlen (line
) - strlen (p
) - 1);
472 fprintf (statusfp
, "\rS:%s %i/%i %i%%%s", l
, a
, b
, t
,
479 fprintf (statusfp
, "S:%s\n", line
);
481 #ifdef HAVE_LIBREADLINE
490 return pwmd_process (pwm
);
495 knownhost_cb (void *data
, const char *host
, const char *key
, size_t len
)
499 pwmd_strdup_printf (N_
500 ("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"),
501 (char *) data
, host
, host
);
503 if (no_pinentry
&& !isatty (STDIN_FILENO
))
505 fprintf (stderr
, N_("Input is not from a terminal! Failing.\n"));
507 return GPG_ERR_ENOTTY
;
509 else if (no_pinentry
)
511 for (char *p
= buf
, len
= 0; *p
; p
++, len
++)
520 while (len
&& !isspace (*(--p
)))
529 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_PROMPT
, N_("Accept [y/N]:"));
533 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, buf
);
539 return pwmd_getpin (pwm
, NULL
, NULL
, NULL
, PWMD_PINENTRY_CONFIRM
);
543 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
545 is_remote_url (const char *str
)
548 return PWMD_SOCKET_LOCAL
;
551 if (strstr (str
, "ssh://") || strstr (str
, "ssh4://")
552 || strstr (str
, "ssh6://"))
553 return PWMD_SOCKET_SSH
;
557 if (strstr (str
, "tls://") || strstr (str
, "tls4://")
558 || strstr (str
, "tls6://"))
559 return PWMD_SOCKET_TLS
;
562 return PWMD_SOCKET_LOCAL
;
567 escape (const char *str
)
570 char *buf
= pwmd_malloc (ASSUAN_LINELENGTH
+ 1), *b
= buf
;
573 for (p
= str
; *p
; p
++, len
++)
575 if (len
== ASSUAN_LINELENGTH
)
619 free_inquire (struct inquire_s
*inq
)
624 pwmd_free (inq
->line
);
626 if (inq
->fd
!= -1 && inq
->fd
!= STDIN_FILENO
)
629 pwmd_free (inq
->last_keyword
);
633 /* When *result is not NULL it is updated to the new values and not
636 set_inquire (int fd
, const char *line
, struct inquire_s
**result
)
638 struct inquire_s inq
= { 0 };
639 struct stat st
= { 0 };
644 if (fstat (fd
, &st
) == -1)
645 return gpg_error_from_syserror ();
647 inq
.size
= st
.st_size
;
651 inq
.line
= pwmd_calloc (1, ASSUAN_LINELENGTH
);
653 return GPG_ERR_ENOMEM
;
657 char *s
= escape (line
);
661 pwmd_free (inq
.line
);
662 return GPG_ERR_ENOMEM
;
665 if (strlen (s
) >= ASSUAN_LINELENGTH
)
667 pwmd_free (inq
.line
);
669 return GPG_ERR_LINE_TOO_LONG
;
672 strncpy (inq
.line
, s
, ASSUAN_LINELENGTH
- 1);
673 inq
.len
= strlen (s
);
677 rc
= pwmd_setopt (pwm
, PWMD_OPTION_INQUIRE_TOTAL
,
678 st
.st_size
? st
.st_size
+ strlen (inq
.line
) : 0);
681 pwmd_free (inq
.line
);
686 *result
= pwmd_malloc (sizeof (struct inquire_s
));
689 if ((*result
)->fd
!= -1 && (*result
)->fd
!= STDIN_FILENO
)
690 close ((*result
)->fd
);
692 pwmd_free ((*result
)->line
);
693 (*result
)->line
= NULL
;
698 memcpy (*result
, &inq
, sizeof (struct inquire_s
));
699 memset (&inq
, 0, sizeof (struct inquire_s
));
703 #ifdef HAVE_LIBREADLINE
705 interactive_hook (void)
707 interactive_error
= process_cmd ();
709 if (interactive_error
)
710 rl_event_hook
= NULL
;
716 get_readline_char (FILE *fp
)
719 && (!strncmp (rl_line_buffer
, ".set passphrase-file ", 16)
720 || !strncmp (rl_line_buffer
, ".set new-passphrase-file ", 20)
721 || !strncmp (rl_line_buffer
, ".set sign-passphrase-file ", 21)))
722 rl_inhibit_completion
= 0;
723 else if (rl_line_buffer
724 && !strncmp (rl_line_buffer
, ".redir ", 7))
726 char *p
= strchr (rl_line_buffer
, ' ');
728 if (strchr (++p
, ' '))
729 rl_inhibit_completion
= 1;
731 rl_inhibit_completion
= 0;
733 else if (rl_line_buffer
734 && !strncmp (rl_line_buffer
, ".read ", 6))
736 char *p
= rl_line_buffer
+ 6;
738 if (strstr (p
, "--prefix "))
740 p
= strstr (p
, "--prefix ");
747 if (!p
|| strchr (p
, ' '))
748 rl_inhibit_completion
= 1;
750 rl_inhibit_completion
= 0;
753 rl_inhibit_completion
= 1;
763 ("------------------------------------------------------------\n"
764 "Elements are TAB delimited. Type HELP for protocol commands.\n"
765 "Type .help for pwmc commands. Press CTRL-D to quit.\n"
766 "------------------------------------------------------------\n"));
771 parse_arg (const char *src
, char *dst
, size_t len
)
777 for (; s
&& *s
&& *s
!= ' ' && n
< len
; s
++, n
++)
785 parse_opt (char **line
, const char *opt
, gpg_error_t
* rc
)
787 static char result
[ASSUAN_LINELENGTH
] = { 0 }, *r
= result
;
788 char *s
= strstr (*line
, opt
);
798 size_t rlen
= strlen (opt
);
802 while (*p
&& *p
== ' ')
808 for (; *p
&& len
< sizeof (result
) - 1; p
++, rlen
++)
810 if (isspace (*p
) && !quote
)
813 if (*p
== '\"' && lastc
!= '\\')
826 if (len
>= sizeof (result
) - 1)
827 *rc
= GPG_ERR_LINE_TOO_LONG
;
832 while (*p
&& *p
== ' ')
843 read_command (const char *line
, char **result
, size_t * len
)
848 struct inquire_s
*inq
= NULL
;
849 char *p
= (char *) line
;
850 const char *prefix
= parse_opt (&p
, "--prefix", &rc
);
851 char filebuf
[ASSUAN_LINELENGTH
];
860 while (*p
&& isspace (*p
))
863 file
= parse_arg (p
, filebuf
, sizeof (filebuf
));
866 p
+= strlen (file
) + 1;
868 while (*p
&& isspace (*p
))
880 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
883 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\\ = \\)\n"));
887 fd
= open (file
, O_RDONLY
);
889 return gpg_error_from_syserror ();
891 rc
= set_inquire (fd
, prefix
&& *prefix
? prefix
: NULL
, &inq
);
898 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, "%s", p
);
904 redir_command (const char *line
)
906 const char *p
= line
;
908 gpg_error_t rc
= GPG_ERR_SYNTAX
;
910 struct inquire_s
*inq
= NULL
;
913 char filebuf
[ASSUAN_LINELENGTH
];
917 file
= parse_arg (p
, filebuf
, sizeof (filebuf
));
920 p
+= strlen (file
) + 1;
922 while (*p
&& isspace (*p
))
932 fprintf (stderr
, N_("Usage: .redir <filename> <command> [args]\n"));
936 fd
= open (file
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600);
938 return gpg_error_from_syserror ();
940 #ifdef HAVE_LIBREADLINE
941 rc
= set_inquire (interactive
? STDIN_FILENO
: inquirefd
, NULL
, &inq
);
943 rc
= set_inquire (inquirefd
, NULL
, &inq
);
951 rc
= parse_dotcommand (p
, &result
, &len
, inq
);
952 if (!rc
&& result
&& len
--)
953 { // null byte which is always appended
954 if (write (fd
, result
, len
) != len
)
955 rc
= GPG_ERR_TOO_SHORT
;
965 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 " write changes of the file to disk\n"
985 " change the passphrase of a data file\n"
988 " this help text\n"));
993 open_command (char *line
)
995 struct inquire_s
*inq
= NULL
;
996 const char *file
= line
;
1000 while (file
&& isspace (*file
))
1003 if (!file
|| !*file
)
1005 fprintf (stderr
, N_("Usage: .open <filename>\n"));
1006 return GPG_ERR_SYNTAX
;
1009 #ifdef HAVE_LIBREADLINE
1010 if (interactive
|| !quiet
)
1014 fprintf (stderr
, N_("Opening data file \"%s\" ...\n"), file
);
1016 #ifdef HAVE_LIBREADLINE
1017 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1019 rc
= set_inquire (-1, NULL
, &inq
);
1024 pwmd_getopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, &local
);
1028 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1030 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, 1);
1033 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1036 rc
= pwmd_open (pwm
, file
, inquire_cb
, inq
);
1038 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local
);
1040 #ifdef HAVE_LIBREADLINE
1046 if (!rc
&& file
!= filename
)
1048 pwmd_free (filename
);
1049 filename
= pwmd_strdup (file
);
1056 set_command (const char *line
)
1059 char name
[256] = { 0 };
1060 char value
[512] = { 0 };
1063 const char *p
= line
;
1065 while (p
&& *p
&& isspace (*p
))
1068 namep
= parse_arg (p
, name
, sizeof (name
));
1069 if (!namep
|| !*namep
)
1071 fprintf (stderr
, N_("Usage: .set help | <name> [<value>]\n"));
1072 return GPG_ERR_SYNTAX
;
1075 p
+= strlen (namep
);
1076 while (p
&& *p
&& isspace (*p
))
1079 valuep
= parse_arg (p
, value
, sizeof (value
));
1081 if (!strcmp (name
, "passphrase-file") || !strcmp (name
, "new-passphrase-file")
1082 || !strcmp (name
, "sign-passphrase-file"))
1084 int is_newkeyfile
= 1;
1085 int sign
= !strcmp (name
, "sign-passphrase-file");
1087 if (!strcmp (name
, "passphrase-file") || sign
)
1092 pwmd_free (new_keyfile
);
1097 pwmd_free (sign_keyfile
);
1098 sign_keyfile
= NULL
;
1102 pwmd_free (keyfile
);
1109 new_keyfile
= pwmd_strdup (value
);
1111 sign_keyfile
= pwmd_strdup (value
);
1113 keyfile
= pwmd_strdup (value
);
1115 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1117 else if (!local_pin
&& !no_pinentry
)
1121 pwmd_socket_type (pwm
, &t
);
1122 if (t
== PWMD_SOCKET_LOCAL
)
1123 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1126 else if (!strcmp(name
, "pinentry-timeout"))
1129 int n
= strtol(valuep
, &e
, 10);
1132 return gpg_error (GPG_ERR_INV_VALUE
);
1135 n
= DEFAULT_PIN_TIMEOUT
;
1137 rc
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, n
);
1139 else if (!strcmp (name
, "help"))
1143 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1144 "delimited. When no value is specified the option is unset.\n\n"
1145 "passphrase-file [<filename>]\n"
1146 " set or unset the file to be used when a passphrase is required (*)\n"
1148 "new-passphrase-file [<filename>]\n"
1149 " set or unset the file to be used when a new passphrase is required (*)\n"
1151 "sign-passphrase-file [<filename>]\n"
1152 " set or unset the file to be used when a passphrase is required for\n"
1153 " signing (symmetric) (*)\n"
1155 "pinentry-timeout <seconds>\n"
1156 " the amount of seconds before pinentry gives up waiting for input\n"
1158 "* = the next protocol command will unset this value\n"
1162 rc
= GPG_ERR_UNKNOWN_OPTION
;
1168 do_save_passwd_command (const char *line
, int save
)
1170 struct inquire_s
*inq
= NULL
;
1174 #ifdef HAVE_LIBREADLINE
1175 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1177 rc
= set_inquire (-1, NULL
, &inq
);
1182 pwmd_getopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, &local
);
1184 if (new_keyfile
|| keyfile
|| sign_keyfile
)
1186 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1188 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, 1);
1191 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1196 rc
= pwmd_save (pwm
, line
, inquire_cb
, inq
);
1198 rc
= pwmd_passwd (pwm
, line
, inquire_cb
, inq
);
1201 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local
);
1203 #ifdef HAVE_LIBREADLINE
1213 save_command (const char *line
)
1215 return do_save_passwd_command (line
, 1);
1219 parse_dotcommand (const char *line
, char **result
,
1220 size_t * len
, struct inquire_s
*inq
)
1222 const char *p
= line
;
1225 if (!strncmp (p
, ".read", 5))
1226 rc
= read_command (p
+ 5, result
, len
);
1227 else if (!strncmp (p
, ".redir", 6))
1228 rc
= redir_command (p
+ 6);
1229 else if (!strncmp (p
, ".help", 5))
1230 rc
= help_command (p
+ 5);
1231 else if (!strncmp (p
, ".open", 5))
1232 rc
= open_command ((char *)p
+ 5);
1233 else if (!strncmp (p
, ".set", 4))
1234 rc
= set_command (p
+ 4);
1235 else if (!strncmp (p
, ".save", 5))
1236 rc
= do_save_passwd_command (p
+ 5, 1);
1237 else if (!strncmp (p
, ".passwd", 7))
1238 rc
= do_save_passwd_command (p
+ 7, 0);
1241 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, "%s", line
);
1242 #ifdef HAVE_LIBREADLINE
1247 #ifdef HAVE_LIBREADLINE
1255 #ifdef HAVE_LIBREADLINE
1260 struct inquire_s
*inq
= NULL
;
1263 rc
= process_cmd ();
1267 rc
= set_inquire (STDIN_FILENO
, NULL
, &inq
);
1272 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1274 rl_event_hook
= &interactive_hook
;
1275 rl_getc_function
= get_readline_char
;
1276 rl_set_keyboard_input_timeout (100000);
1281 char *result
= NULL
;
1285 line
= readline ("pwmc> ");
1286 if (interactive_error
)
1289 rc
= interactive_error
;
1299 if (gpg_err_code (rc
) != GPG_ERR_CANCELED
&&
1300 gpg_err_code (rc
) != GPG_ERR_EOF
)
1301 fprintf (stderr
, "ERR %i: %s\n", rc
, gpg_strerror (rc
));
1311 #ifdef HAVE_READLINE_HISTORY
1314 rc
= parse_dotcommand (line
, &result
, &len
, inq
);
1320 if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
1321 (void) pwmd_command (pwm
, &tmp
, NULL
, NULL
, NULL
,
1322 "GETINFO last_error");
1324 show_error (pwm
, rc
, tmp
);
1327 else if (result
&& len
)
1328 printf ("%s%s", result
, result
[len
- 1] != '\n' ? "\n" : "");
1342 #ifdef HAVE_LIBREADLINE
1349 fprintf (stderr
, "\n");
1357 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1358 p
= fgets (buf
, sizeof (buf
), stdin
);
1372 return GPG_ERR_CANCELED
;
1376 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1377 "CLEARCACHE %s", filename
);
1381 interactive_hook ();
1397 if (save
&& !filename
)
1401 ("No filename was specified on the command line. Aborting.\n"));
1402 return GPG_ERR_CANCELED
;
1405 if (save
&& filename
)
1408 pwmd_strdup_printf ("%s %s%s %s%s %s",
1409 symmetric
? "--symmetric" : "",
1410 keyid
? "--keyid=" : "",
1412 sign_keyid
? "--sign-keyid=" : "",
1413 sign_keyid
? sign_keyid
: "",
1414 keyparams
? "--inquire-keyparam" : "");
1416 #ifdef HAVE_LIBREADLINE
1417 if (!quiet
|| interactive
)
1423 fprintf (stderr
, "\n");
1424 fprintf (stderr
, N_("Saving changes ...\n"));
1427 rc
= save_command (args
);
1431 #ifdef HAVE_LIBREADLINE
1433 return rc
? rc
: quit
? 0 : GPG_ERR_CANCELED
;
1440 parse_status_ignore (char *str
)
1445 for (p
= status_ignore
; p
&& *p
; p
++)
1448 pwmd_free (status_ignore
);
1449 status_ignore
= NULL
;
1453 while ((s
= strsep (&str
, ",")))
1455 p
= pwmd_realloc (status_ignore
, (n
+ 2) * sizeof (char *));
1456 p
[n
++] = pwmd_strdup (s
);
1463 main (int argc
, char *argv
[])
1468 char command
[ASSUAN_LINELENGTH
], *p
= NULL
;
1469 char *result
= NULL
;
1471 char *pinentry_path
= NULL
;
1472 char *display
= NULL
, *tty
= NULL
, *ttytype
= NULL
;
1473 char *lcctype
= NULL
, *lcmessages
= NULL
;
1474 int outfd
= STDOUT_FILENO
;
1475 FILE *outfp
= stdout
;
1476 FILE *inquirefp
= stdin
;
1477 int show_status
= 1;
1478 char *clientname
= "pwmc";
1479 char *inquire
= NULL
;
1480 char *inquire_line
= NULL
;
1483 int use_ssh_agent
= 1;
1484 char *knownhosts
= NULL
;
1485 char *identity
= NULL
;
1486 int needs_passphrase
= 0;
1489 char *cacert
= NULL
;
1490 char *clientcert
= NULL
;
1491 char *clientkey
= NULL
;
1494 char *tls_fingerprint
= NULL
;
1496 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1497 pwmd_socket_t socktype
;
1498 long socket_timeout
= 300;
1499 int connect_timeout
= 120;
1501 int lock_on_open
= 1;
1502 long lock_timeout
= 50;
1505 /* The order is important. */
1508 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1509 OPT_SOCKET_TIMEOUT
, OPT_CONNECT_TIMEOUT
,
1512 OPT_USE_SSH_AGENT
, OPT_IDENTITY
, OPT_KNOWNHOSTS
, OPT_SSH_NEEDS_PASSPHRASE
,
1515 OPT_CACERT
, OPT_CLIENTCERT
, OPT_CLIENTKEY
, OPT_PRIORITY
, OPT_VERIFY
,
1518 OPT_URL
, OPT_LOCAL
, OPT_TTYNAME
, OPT_TTYTYPE
, OPT_DISPLAY
, OPT_LC_CTYPE
,
1519 OPT_LC_MESSAGES
, OPT_TIMEOUT
, OPT_TRIES
, OPT_PINENTRY
, OPT_KEYFILE
,
1520 OPT_PASSPHRASE_FILE
, OPT_NEW_KEYFILE
, OPT_NEW_PASSPHRASE_FILE
,
1521 OPT_SIGN_KEYFILE
, OPT_SIGN_PASSPHRASE_FILE
, OPT_NOLOCK
, OPT_LOCK_TIMEOUT
,
1522 OPT_SAVE
, OPT_OUTPUT_FD
, OPT_INQUIRE
, OPT_INQUIRE_FD
, OPT_INQUIRE_FILE
,
1523 OPT_INQUIRE_LINE
, OPT_NO_STATUS
, OPT_STATUS_IGNORE
, OPT_STATUSFD
, OPT_NAME
,
1524 OPT_VERSION
, OPT_HELP
, OPT_KEYID
, OPT_SIGN_KEYID
, OPT_SYMMETRIC
,
1525 OPT_KEYPARAMS
, OPT_NO_PINENTRY
, OPT_QUIET
,
1526 #ifdef HAVE_LIBREADLINE
1530 const struct option long_opts
[] = {
1531 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1532 {"socket-timeout", 1, 0, 0},
1533 {"connect-timeout", 1, 0, 0},
1537 {"no-ssh-agent", 0, 0, 0},
1538 {"identity", 1, 0, 'i'},
1539 {"knownhosts", 1, 0, 'k'},
1540 {"ssh-needs-passphrase", 0, 0, 0},
1543 {"ca-cert", 1, 0, 0},
1544 {"client-cert", 1, 0, 0},
1545 {"client-key", 1, 0, 0},
1546 {"tls-priority", 1, 0, 0},
1547 {"tls-verify", 0, 0, 0},
1548 {"tls-fingerprint", 1, 0, 0},
1551 {"local-pinentry", 0, 0},
1552 {"ttyname", 1, 0, 'y'},
1553 {"ttytype", 1, 0, 't'},
1554 {"display", 1, 0, 'd'},
1555 {"lc-ctype", 1, 0, 0},
1556 {"lc-messages", 1, 0, 0},
1557 {"timeout", 1, 0, 0},
1559 {"pinentry", 1, 0, 0},
1560 {"key-file", 1, 0, 0},
1561 {"passphrase-file", 1, 0, 0},
1562 {"new-key-file", 1, 0, 0},
1563 {"new-passphrase-file", 1, 0, 0},
1564 {"sign-key-file", 1, 0, 0},
1565 {"sign-passphrase-file", 1, 0, 0},
1566 {"no-lock", 0, 0, 0},
1567 {"lock-timeout", 1, 0, 0},
1568 {"save", 0, 0, 'S'},
1569 {"output-fd", 1, 0, 0},
1570 {"inquire", 1, 0, 0},
1571 {"inquire-fd", 1, 0, 0},
1572 {"inquire-file", 1, 0, 0},
1573 {"inquire-line", 1, 0, 'L'},
1574 {"no-status", 0, 0, 0},
1575 {"status-ignore", 1, 0, 0},
1576 {"status-fd", 1, 0, 0},
1577 {"name", 1, 0, 'n'},
1578 {"version", 0, 0, 0},
1581 {"sign-keyid", 1, 0, 0},
1582 {"symmetric", 0, 0, 0},
1583 {"key-params", 1, 0, 0},
1584 {"no-pinentry", 0, 0, 0},
1586 #ifdef HAVE_LIBREADLINE
1587 {"interactive", 0, 0},
1592 const char *optstring
= "L:y:t:d:P:I:Sn:i:k:s";
1594 const char *optstring
= "L:y:t:d:P:I:Sn:s";
1599 setlocale (LC_ALL
, "");
1600 bindtextdomain ("libpwmd", LOCALEDIR
);
1603 tries
= DEFAULT_PIN_TRIES
;
1604 inquirefd
= STDIN_FILENO
;
1605 statusfd
= STDERR_FILENO
;
1607 tmp
= pwmd_strdup (DEFAULT_STATUS_IGNORE
);
1608 parse_status_ignore (tmp
);
1612 getopt_long (argc
, argv
, optstring
, long_opts
, &opt_index
)) != -1)
1616 /* Handle long options without a short option part. */
1620 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1621 case OPT_SOCKET_TIMEOUT
:
1622 socket_timeout
= strtol (optarg
, &p
, 10);
1624 case OPT_CONNECT_TIMEOUT
:
1625 connect_timeout
= strtol (optarg
, &p
, 10);
1629 case OPT_USE_SSH_AGENT
:
1632 case OPT_SSH_NEEDS_PASSPHRASE
:
1633 needs_passphrase
= 1;
1640 case OPT_CLIENTCERT
:
1641 clientcert
= optarg
;
1653 tls_fingerprint
= optarg
;
1663 case OPT_PASSPHRASE_FILE
:
1664 keyfile
= pwmd_strdup (optarg
);
1666 case OPT_NEW_KEYFILE
:
1667 case OPT_NEW_PASSPHRASE_FILE
:
1668 new_keyfile
= pwmd_strdup (optarg
);
1670 case OPT_SIGN_KEYFILE
:
1671 case OPT_SIGN_PASSPHRASE_FILE
:
1672 sign_keyfile
= pwmd_strdup (optarg
);
1677 case OPT_LOCK_TIMEOUT
:
1678 lock_timeout
= strtol (optarg
, &p
, 10);
1687 lcctype
= pwmd_strdup (optarg
);
1689 case OPT_LC_MESSAGES
:
1690 lcmessages
= pwmd_strdup (optarg
);
1693 timeout
= strtol (optarg
, &p
, 10);
1696 tries
= strtol (optarg
, &p
, 10);
1699 inquire
= escape (optarg
);
1701 case OPT_INQUIRE_FD
:
1702 inquirefd
= strtol (optarg
, &p
, 10);
1705 inquirefp
= fdopen (inquirefd
, "r");
1707 err (EXIT_FAILURE
, "%i", inquirefd
);
1710 case OPT_INQUIRE_FILE
:
1711 inquirefd
= open (optarg
, O_RDONLY
);
1712 if (inquirefd
== -1)
1713 err (EXIT_FAILURE
, "%s", optarg
);
1714 inquirefp
= fdopen (inquirefd
, "r");
1717 outfd
= strtol (optarg
, &p
, 10);
1720 outfp
= fdopen (outfd
, "w");
1722 err (EXIT_FAILURE
, "%i", outfd
);
1729 statusfd
= strtol (optarg
, &p
, 10);
1732 statusfp
= fdopen (statusfd
, "w");
1734 err (EXIT_FAILURE
, "%i", statusfd
);
1737 case OPT_STATUS_IGNORE
:
1738 parse_status_ignore (optarg
);
1741 printf ("%s (pwmc)\n\n"
1742 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016\n"
1744 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1745 "Compile-time features:\n"
1746 #ifdef HAVE_LIBREADLINE
1761 #ifdef WITH_PINENTRY
1776 "\n", PACKAGE_STRING
, PACKAGE_BUGREPORT
);
1777 exit (EXIT_SUCCESS
);
1779 pinentry_path
= optarg
;
1782 usage (argv
[0], EXIT_SUCCESS
);
1786 case OPT_SIGN_KEYID
:
1787 sign_keyid
= optarg
;
1793 case OPT_NO_PINENTRY
:
1796 #ifdef HAVE_LIBREADLINE
1797 case OPT_INTERACTIVE
:
1802 usage (argv
[0], EXIT_FAILURE
);
1807 fprintf (stderr
, N_("%s: invalid argument for option '--%s'\n"),
1808 argv
[0], long_opts
[opt_index
].name
);
1809 usage (argv
[0], EXIT_FAILURE
);
1818 knownhosts
= optarg
;
1822 inquire_line
= optarg
;
1837 clientname
= optarg
;
1840 usage (argv
[0], EXIT_FAILURE
);
1844 #ifdef HAVE_LIBREADLINE
1845 if (interactive
&& !isatty (STDIN_FILENO
))
1846 usage (argv
[0], EXIT_FAILURE
);
1847 else if (isatty (STDIN_FILENO
) && !inquire
&& !inquire_line
)
1852 rc
= pwmd_new (clientname
, &pwm
);
1856 filename
= argv
[optind
] ? pwmd_strdup (argv
[optind
]) : NULL
;
1857 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
1861 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local_pin
);
1865 pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TRIES
, tries
);
1867 fprintf (stderr
, N_("Connecting ...\n"));
1869 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1870 socktype
= is_remote_url (url
);
1871 if (socktype
!= PWMD_SOCKET_LOCAL
)
1874 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1875 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, connect_timeout
);
1880 if (socktype
== PWMD_SOCKET_SSH
)
1883 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_CB
, knownhost_cb
);
1887 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_DATA
, clientname
);
1891 if (!getenv ("SSH_AUTH_SOCK") || identity
)
1894 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_AGENT
, use_ssh_agent
);
1898 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_NEEDS_PASSPHRASE
,
1903 rc
= pwmd_connect (pwm
, url
, identity
, knownhosts
);
1909 rc
= pwmd_setopt (pwm
, PWMD_OPTION_TLS_VERIFY
, tls_verify
);
1913 rc
= pwmd_connect (pwm
, url
, clientcert
, clientkey
, cacert
, prio
,
1919 rc
= pwmd_connect (pwm
, url
);
1921 rc
= pwmd_connect (pwm
, url
);
1927 fprintf (stderr
, N_("Connected.\n"));
1930 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1931 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, socket_timeout
);
1938 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1939 "OPTION LOCK-TIMEOUT=%li", lock_timeout
);
1946 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCK_ON_OPEN
, 1);
1951 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, NULL
, NULL
);
1957 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, timeout
);
1964 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_PATH
, pinentry_path
);
1971 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DISPLAY
, display
);
1978 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TTY
, tty
);
1985 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TERM
, ttytype
);
1992 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_CTYPE
, lcctype
);
1999 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_MESSAGES
, lcmessages
);
2006 rc
= pwmd_setopt (pwm
, PWMD_OPTION_STATUS_CB
, status_msg_cb
);
2013 rc
= open_command (filename
);
2018 #ifdef HAVE_LIBREADLINE
2021 rc
= do_interactive ();
2029 struct inquire_s
*inq
= NULL
;
2031 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2033 rc
= pwmd_command (pwm
, &result
, &len
, inquire_cb
, inq
, "%s", inquire
);
2039 if (fcntl (STDIN_FILENO
, F_SETFL
, O_NONBLOCK
) == -1)
2041 rc
= gpg_error_from_errno (errno
);
2049 rc
= process_cmd ();
2054 n
= read (STDIN_FILENO
, command
, sizeof (command
)-1);
2057 if (errno
== EAGAIN
)
2063 rc
= gpg_error_from_errno (errno
);
2074 if (!p
|| !*p
|| !strcasecmp (p
, "BYE"))
2078 struct inquire_s
*inq
= NULL
;
2079 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2082 rc
= parse_dotcommand (command
, &result
, &len
, inq
);
2092 fwrite (result
, 1, result
[len
- 1] == 0 ? len
- 1 : len
, outfp
);
2100 else if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
2101 (void) pwmd_command (pwm
, &result
, NULL
, NULL
, NULL
,
2102 "GETINFO last_error");
2104 #ifdef HAVE_LIBREADLINE
2107 wipememory (command
, 0, sizeof (command
));
2110 show_error (pwm
, rc
, result
);
2116 pwmd_free (filename
);
2117 parse_status_ignore (NULL
);
2118 if (connected
&& !quiet
)
2119 fprintf (stderr
, N_("Connection closed.\n"));
2121 exit (rc
? EXIT_FAILURE
: EXIT_SUCCESS
);