2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015
3 Ben Kibbey <bjk@luxsci.net>
5 This file is part of libpwmd.
7 Libpwmd is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 2 of the License, or
10 (at your option) any later version.
12 Libpwmd is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Libpwmd. If not, see <http://www.gnu.org/licenses/>.
33 #include <sys/select.h>
35 #include <sys/types.h>
43 #include <gnutls/gnutls.h>
50 #ifdef HAVE_GETOPT_LONG
55 #include "getopt_long.h"
58 #ifdef HAVE_LIBREADLINE
59 #if defined(HAVE_READLINE_READLINE_H)
60 #include <readline/readline.h>
61 #elif defined(HAVE_READLINE_H)
63 #endif /* !defined(HAVE_READLINE_H) */
64 static int interactive_error
;
65 static int interactive
;
66 #endif /* HAVE_LIBREADLINE */
68 #ifdef HAVE_READLINE_HISTORY
69 #if defined(HAVE_READLINE_HISTORY_H)
70 #include <readline/history.h>
71 #elif defined(HAVE_HISTORY_H)
74 #endif /* HAVE_READLINE_HISTORY */
81 #define N_(msgid) gettext(msgid)
86 #define DEFAULT_STATUS_IGNORE "KEEPALIVE,STATE,GPGME,PASSPHRASE_INFO,PASSPHRASE_HINT"
87 #define DEFAULT_PIN_TIMEOUT 30
88 #define DEFAULT_PIN_TRIES 3
89 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
92 static int no_pinentry
;
94 static char *filename
;
97 static char *sign_keyid
;
99 static char *keyparams
;
100 static char *keyfile
;
101 static char *new_keyfile
;
102 static char *sign_keyfile
;
104 static int local_pin
;
105 static int inquirefd
;
109 static char **status_ignore
;
116 size_t size
; // from stat(2).
120 static gpg_error_t
finalize ();
121 static gpg_error_t
set_inquire (int fd
, const char *line
,
122 struct inquire_s
**result
);
123 static gpg_error_t
parse_dotcommand (const char *line
, char **result
,
124 size_t * len
, struct inquire_s
*inq
);
125 static gpg_error_t
open_command (const char *line
);
127 static gpg_error_t
get_password (char **result
, pwmd_pinentry_t w
, int echo
);
131 show_error (pwm_t
*pwm
, gpg_error_t rc
, const char *str
)
134 if (pwmd_tls_error (pwm
))
135 fprintf(stderr
, "TLS: %s\n", gnutls_strerror(pwmd_tls_error(pwm
)));
137 fprintf (stderr
, "ERR %i: %s%s%s%s", rc
, gpg_strerror (rc
),
138 str
? ": " : "", str
? str
: "", str
? "" : "\n");
145 pwmd_free (new_keyfile
);
146 pwmd_free (sign_keyfile
);
147 keyfile
= new_keyfile
= sign_keyfile
= NULL
;
151 usage (const char *pn
, int status
)
153 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
154 N_("Usage: pwmc [options] [file]\n"
156 " a url string to connect to (%s, see below)\n"
157 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
158 " --connect-timeout <seconds>\n"
159 " seconds before connecting to a remote host fails (0=disabled, 120)\n"
160 " --socket-timeout <seconds>\n"
161 " seconds before a remote command fails (0=disabled, 300)\n"
164 " --ca-cert <filename>\n"
165 " certificate authority (CA) used to sign the server cert\n"
166 " --client-cert <filename>\n"
167 " client certificate to use for authentication\n"
168 " --client-key <filename>\n"
169 " key file used to protect the client certificate\n"
170 " --tls-priority <string>\n"
171 " compression, cipher and hash algorithm string\n"
172 " (SECURE256:SECURE192:SECURE128:-VERS-SSL3.0)\n"
174 " verify the hostname against the server certificate\n"
175 " --tls-fingerprint <string>\n"
176 " a SHA-256 hash of the server fingerprint to verify against\n"
180 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
181 " --identity, -i <filename>\n"
182 " the ssh identity file to use for authentication\n"
183 " --knownhosts, -k <filename>\n"
184 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
187 " do not lock the data file upon opening it\n"
188 " --lock-timeout <N>\n"
189 " time in tenths of a second to wait for a locked data file (50)\n"
190 " --name, -n <string>\n"
191 " set the client name\n"
192 " --pinentry <path>\n"
193 " the full path to the pinentry binary\n"
194 " --local-pinentry\n"
195 " force using a local pinentry\n"
197 " disable pinentry both remotely and locally\n"
198 " --ttyname, -y <path>\n"
199 " tty that pinentry will use\n"
200 " --ttytype, -t <string>\n"
201 " pinentry terminal type (default is $TERM)\n"
203 " pinentry display (default is $DISPLAY)\n"
204 " --lc-ctype <string>\n"
205 " locale setting for pinentry\n"
206 " --lc-messages <string>\n"
207 " locale setting for pinentry\n"
209 " number of pinentry tries before failing (3)\n"
210 " --timeout <seconds>\n"
211 " pinentry timeout\n"
212 " --inquire <COMMAND>\n"
213 " the specified command (with any options) uses a server inquire while\n"
214 " command data is read via the inquire file descriptor (stdin)\n"
215 " --inquire-line, -L <STRING>\n"
216 " the initial line to send (i.e., element path) before the inquire data\n"
217 " --inquire-fd <FD>\n"
218 " read inquire data from the specified file descriptor (stdin)\n"
219 " --inquire-file <filename>\n"
220 " read inquire data from the specified filename\n"
221 " --output-fd <FD>\n"
222 " redirect command output to the specified file descriptor\n"
224 " send the SAVE command before exiting\n"
225 " --key-file <filename>\n"
226 " obtain the passphrase from the specified filename\n"
227 " --new-key-file <filename>\n"
228 " obtain the passphrase to save with from the specified filename\n"
229 " --sign-key-file <filename>\n"
230 " obtain the passphrase to sign (symmetric) with from the specified filename\n"
231 " --key-params <filename>\n"
232 " key parameters to use for key generation (pwmd default)\n"
233 " --keyid <recipient>[,<recipient>]\n"
234 " the public key ID to u\n"
235 " --sign-keyid <string>\n"
236 " the key ID to sign the data file with\n"
238 " use conventional encryption with optional signer(s) for new files\n"
240 " disable showing of status messages from the server\n"
241 " --status-ignore <string[,...]>\n"
242 " prevent parsing of the specified status message keywords\n"
244 " disable showing of extra messages (implies --no-status)\n"
245 " --status-fd <FD>\n"
246 " redirect status messages to the specified file descriptor\n"
247 #ifdef HAVE_LIBREADLINE
249 " use a shell like interface to pwmd (allows more than one command)\n"
253 #ifdef DEFAULT_PWMD_SOCKET
259 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
261 "An optional url may be in the form of:\n"
262 " --url /path/to/socket\n"
263 " --url file://[path/to/socket]\n"
266 " --url ssh[46]://[username@]hostname[:port]\n"
267 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
271 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
272 " --client-key filename\n"
274 #ifdef HAVE_LIBREADLINE
276 "Interactive mode is used when input is from a terminal.\n"
283 inquire_cb (void *user
, const char *keyword
, gpg_error_t rc
,
284 char **data
, size_t * size
)
286 struct inquire_s
*inq
= user
;
288 int is_newpassword
= 0;
298 if (!strcmp (keyword
, "PASSPHRASE"))
300 else if (!strcmp (keyword
, "SIGN_PASSPHRASE"))
301 is_password
= sign
= 1;
302 else if (!strcmp (keyword
, "NEW_PASSPHRASE"))
304 #ifdef HAVE_LIBREADLINE
305 else if (!strcmp (keyword
, "KEYPARAM") && !interactive
)
308 else if (!strcmp (keyword
, "KEYPARAM"))
312 if (!keyparams
|| !*keyparams
)
313 return gpg_error (GPG_ERR_INV_PARAMETER
);
315 fd
= open (keyparams
, O_RDONLY
);
318 fprintf (stderr
, "%s: %s\n", keyparams
, strerror (errno
));
319 return gpg_error_from_syserror ();
322 rc
= set_inquire (fd
, NULL
, &inq
);
330 fprintf (stderr
, N_("Using file '%s' as %s.\n"), keyparams
, keyword
);
335 if ((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
)
336 || (sign
&& sign_keyfile
))
341 fd
= open (sign_keyfile
, O_RDONLY
);
343 fd
= open (is_password
? keyfile
: new_keyfile
, O_RDONLY
);
348 fprintf (stderr
, "%s: %s\n", sign_keyfile
, strerror (errno
));
350 fprintf (stderr
, "%s: %s\n", is_newpassword
? new_keyfile
351 : keyfile
, strerror (errno
));
352 return gpg_error_from_syserror ();
355 rc
= set_inquire (fd
, NULL
, &inq
);
363 fprintf (stderr
, N_("Using keyfile '%s' as %s.\n"),
364 sign
? sign_keyfile
: is_newpassword
? new_keyfile
367 else if ((is_password
&& !keyfile
) || (is_newpassword
&& !new_keyfile
)
368 || (sign
&& !sign_keyfile
))
372 rc
= pwmd_password (pwm
, keyword
, &tmp
, &inq
->len
);
373 if (rc
&& gpg_err_code (rc
) != GPG_ERR_EOF
)
376 pwmd_free (inq
->line
);
380 return gpg_error (GPG_ERR_EOF
);
382 #ifdef HAVE_LIBREADLINE
383 else if ((!inq
->last_keyword
|| strcmp (keyword
, inq
->last_keyword
))
388 ("%sPress CTRL-D to send the current line. Press twice to end. %s:\n"),
389 inq
->last_keyword
? "\n" : "", keyword
);
390 pwmd_free (inq
->last_keyword
);
391 inq
->last_keyword
= pwmd_strdup (keyword
);
395 /* The first part of the command data. */
401 return inq
->fd
== -1 ? gpg_error (GPG_ERR_EOF
) : 0;
404 *size
= read (inq
->fd
, inq
->line
, ASSUAN_LINELENGTH
);
408 return gpg_error (gpg_error_from_syserror ());
412 else if (inq
->fd
!= STDIN_FILENO
&&
413 (is_newpassword
|| is_password
|| is_keyparam
))
421 if (((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
)
422 || (sign
&& sign_keyfile
) || (keyparams
&& is_keyparam
))
423 && *size
== inq
->size
)
424 return gpg_error (GPG_ERR_EOF
);
426 return *size
? 0 : gpg_error (GPG_ERR_EOF
);
430 status_msg_cb (void *data
, const char *line
)
432 char *p
= strchr (line
, ' ');
435 /* Ignore status messages specified by the client via --status-ignore. */
436 for (s
= status_ignore
; s
&& *s
; s
++)
438 char *tmp
= strchr (line
, ' ');
439 size_t len
= tmp
? strlen (line
) - strlen (tmp
) : strlen (line
);
441 if (!strncmp (line
, *s
, len
) && len
== strlen (*s
))
445 if (statusfd
!= STDERR_FILENO
&& strncmp (line
, "STATE ", 6) && *line
!= '#'
446 && p
&& strchr (p
, ' ') && *++p
)
448 char *p1
= strchr (p
, ' ');
449 int a
= strtol (p
, NULL
, 10);
451 if (isdigit (*p
) && p1
)
453 int b
= strtol (p1
, NULL
, 10);
455 int t
= a
&& b
? a
* 100 / b
: 0;
457 strncpy (l
, line
, strlen (line
) - strlen (p
) - 1);
458 fprintf (statusfp
, "\r%s %i/%i %i%%%s", l
, a
, b
, t
,
465 fprintf (statusfp
, "%s\n", line
);
467 #ifdef HAVE_LIBREADLINE
476 return pwmd_process (pwm
);
481 get_password (char **result
, pwmd_pinentry_t w
, int echo
)
483 char buf
[LINE_MAX
] = { 0 }, *p
;
484 struct termios told
, tnew
;
489 if (!isatty (STDIN_FILENO
))
491 fprintf (stderr
, N_("Input is not from a terminal! Failing.\n"));
492 return GPG_ERR_ENOTTY
;
497 if (tcgetattr (STDIN_FILENO
, &told
) == -1)
498 return gpg_error_from_syserror ();
500 memcpy (&tnew
, &told
, sizeof (struct termios
));
501 tnew
.c_lflag
&= ~(ECHO
);
502 tnew
.c_lflag
|= ICANON
| ECHONL
;
504 if (tcsetattr (STDIN_FILENO
, TCSANOW
, &tnew
) == -1)
508 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
509 return gpg_error_from_errno (n
);
515 case PWMD_PINENTRY_OPEN
:
516 fprintf (stderr
, N_("Password for %s: "), filename
);
518 case PWMD_PINENTRY_OPEN_FAILED
:
519 fprintf (stderr
, N_("Invalid password. Password for %s: "), filename
);
521 case PWMD_PINENTRY_SAVE
:
522 fprintf (stderr
, N_("New password for %s: "), filename
);
524 case PWMD_PINENTRY_SAVE_CONFIRM
:
525 fprintf (stderr
, N_("Confirm password: "));
531 if ((p
= fgets (buf
, sizeof (buf
), stdin
)) == NULL
)
534 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
540 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
545 return GPG_ERR_CANCELED
;
548 p
[strlen (p
) - 1] = 0;
552 key
= pwmd_strdup_printf ("%s", p
);
553 memset (&buf
, 0, sizeof (buf
));
556 return GPG_ERR_ENOMEM
;
564 knownhost_cb (void *data
, const char *host
, const char *key
, size_t len
)
568 pwmd_strdup_printf (N_
569 ("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?"),
570 (char *) data
, host
, host
);
572 if (no_pinentry
&& !isatty (STDIN_FILENO
))
574 fprintf (stderr
, N_("Input is not from a terminal! Failing.\n"));
576 return GPG_ERR_ENOTTY
;
578 else if (no_pinentry
)
580 for (char *p
= buf
, len
= 0; *p
; p
++, len
++)
589 while (!isspace (*(--p
)));
596 fprintf (stderr
, "%s\n\n", buf
);
603 fprintf (stderr
, N_("Trust this connection [y/N]: "));
605 rc
= get_password (&result
, PWMD_PINENTRY_CONFIRM
, 1);
610 if (!result
|| !*result
|| *result
== 'n' || *result
== 'N')
612 if (result
&& *result
)
615 return GPG_ERR_NOT_CONFIRMED
;
618 if ((*result
== 'y' || *result
== 'Y') && *(result
+ 1) == 0)
627 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, buf
);
633 return pwmd_getpin (pwm
, NULL
, NULL
, NULL
, PWMD_PINENTRY_CONFIRM
);
637 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
639 is_remote_url (const char *str
)
642 return PWMD_SOCKET_LOCAL
;
645 if (strstr (str
, "ssh://") || strstr (str
, "ssh4://")
646 || strstr (str
, "ssh6://"))
647 return PWMD_SOCKET_SSH
;
651 if (strstr (str
, "tls://") || strstr (str
, "tls4://")
652 || strstr (str
, "tls6://"))
653 return PWMD_SOCKET_TLS
;
656 return PWMD_SOCKET_LOCAL
;
661 escape (const char *str
)
664 char *buf
= pwmd_malloc (ASSUAN_LINELENGTH
+ 1), *b
= buf
;
667 for (p
= str
; *p
; p
++, len
++)
669 if (len
== ASSUAN_LINELENGTH
)
713 free_inquire (struct inquire_s
*inq
)
718 pwmd_free (inq
->line
);
720 if (inq
->fd
!= -1 && inq
->fd
!= STDIN_FILENO
)
723 pwmd_free (inq
->last_keyword
);
727 /* When *result is not NULL it is updated to the new values and not
730 set_inquire (int fd
, const char *line
, struct inquire_s
**result
)
732 struct inquire_s inq
= { 0 };
733 struct stat st
= { 0 };
738 if (fstat (fd
, &st
) == -1)
739 return gpg_error_from_syserror ();
741 inq
.size
= st
.st_size
;
745 inq
.line
= pwmd_calloc (1, ASSUAN_LINELENGTH
);
747 return GPG_ERR_ENOMEM
;
751 char *s
= escape (line
);
755 pwmd_free (inq
.line
);
756 return GPG_ERR_ENOMEM
;
759 if (strlen (s
) >= ASSUAN_LINELENGTH
)
761 pwmd_free (inq
.line
);
763 return GPG_ERR_LINE_TOO_LONG
;
766 strncpy (inq
.line
, s
, ASSUAN_LINELENGTH
- 1);
767 inq
.len
= strlen (s
);
771 rc
= pwmd_setopt (pwm
, PWMD_OPTION_INQUIRE_TOTAL
,
772 st
.st_size
? st
.st_size
+ strlen (inq
.line
) : 0);
775 pwmd_free (inq
.line
);
780 *result
= pwmd_malloc (sizeof (struct inquire_s
));
783 if ((*result
)->fd
!= -1 && (*result
)->fd
!= STDIN_FILENO
)
784 close ((*result
)->fd
);
786 pwmd_free ((*result
)->line
);
787 (*result
)->line
= NULL
;
792 memcpy (*result
, &inq
, sizeof (struct inquire_s
));
793 memset (&inq
, 0, sizeof (struct inquire_s
));
797 #ifdef HAVE_LIBREADLINE
799 interactive_hook (void)
801 interactive_error
= process_cmd ();
803 if (interactive_error
)
804 rl_event_hook
= NULL
;
814 ("------------------------------------------------------------------------------\n"
815 "Elements are TAB delimited. Press CTRL-V then TAB to insert from the prompt.\n"
817 "Type HELP for protocol commands. Type .help for pwmc commands. Press CTRL-D\n"
819 "------------------------------------------------------------------------------\n"));
824 parse_arg (const char *src
, char *dst
, size_t len
)
830 for (; s
&& *s
&& *s
!= ' ' && n
< len
; s
++, n
++)
838 parse_opt (char **line
, const char *opt
, gpg_error_t
* rc
)
840 static char result
[ASSUAN_LINELENGTH
] = { 0 }, *r
= result
;
841 char *s
= strstr (*line
, opt
);
851 size_t rlen
= strlen (opt
);
855 while (*p
&& *p
== ' ')
861 for (; *p
&& len
< sizeof (result
) - 1; p
++, rlen
++)
863 if (isspace (*p
) && !quote
)
866 if (*p
== '\"' && lastc
!= '\\')
879 if (len
>= sizeof (result
) - 1)
880 *rc
= GPG_ERR_LINE_TOO_LONG
;
885 while (*p
&& *p
== ' ')
896 read_command (const char *line
, char **result
, size_t * len
)
900 char *filename
= NULL
;
901 struct inquire_s
*inq
= NULL
;
902 char *p
= (char *) line
;
903 const char *prefix
= parse_opt (&p
, "--prefix", &rc
);
904 char filebuf
[ASSUAN_LINELENGTH
];
913 while (*p
&& isspace (*p
))
916 filename
= parse_arg (p
, filebuf
, sizeof (filebuf
));
917 if (filename
&& *filename
)
919 p
+= strlen (filename
) + 1;
921 while (*p
&& isspace (*p
))
933 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
936 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\" = \")\n"));
940 fd
= open (filename
, O_RDONLY
);
942 return gpg_error_from_syserror ();
944 rc
= set_inquire (fd
, prefix
&& *prefix
? prefix
: NULL
, &inq
);
951 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, "%s", p
);
957 redir_command (const char *line
)
959 const char *p
= line
;
961 gpg_error_t rc
= GPG_ERR_SYNTAX
;
962 char *filename
= NULL
;
963 struct inquire_s
*inq
= NULL
;
966 char filebuf
[ASSUAN_LINELENGTH
];
970 filename
= parse_arg (p
, filebuf
, sizeof (filebuf
));
971 if (filename
&& *filename
)
973 p
+= strlen (filename
) + 1;
975 while (*p
&& isspace (*p
))
985 fprintf (stderr
, N_("Usage: .redir <filename> <command> [args]\n"));
989 fd
= open (filename
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600);
991 return gpg_error_from_syserror ();
993 #ifdef HAVE_LIBREADLINE
994 rc
= set_inquire (interactive
? STDIN_FILENO
: inquirefd
, NULL
, &inq
);
996 rc
= set_inquire (inquirefd
, NULL
, &inq
);
1004 rc
= parse_dotcommand (p
, &result
, &len
, inq
);
1005 if (!rc
&& result
&& len
--)
1006 { // null byte which is always appended
1007 if (write (fd
, result
, len
) != len
)
1008 rc
= GPG_ERR_TOO_SHORT
;
1018 help_command (const char *line
)
1021 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
1022 " .redir <filename> <command>\n"
1023 " redirect the output of a command to the specified file\n"
1025 " .open <filename>\n"
1026 " open the specified filename losing any changes to the current one\n"
1028 " .read [--prefix <string>] <filename> <command> [args]\n"
1029 " obtain data from the specified filename for an inquire command\n"
1031 " .set help | <name> [<value>]\n"
1032 " set option <name> to <value>\n"
1035 " write changes of the file to disk\n"
1038 " change the passphrase of a data file\n"
1041 " this help text\n"));
1046 open_command (const char *line
)
1048 struct inquire_s
*inq
= NULL
;
1049 const char *filename
= line
;
1052 while (filename
&& isspace (*filename
))
1055 if (!filename
|| !*filename
)
1057 fprintf (stderr
, N_("Usage: .open <filename>\n"));
1058 return GPG_ERR_SYNTAX
;
1061 #ifdef HAVE_LIBREADLINE
1062 if (interactive
|| !quiet
)
1066 fprintf (stderr
, N_("Opening data file \"%s\" ...\n"), filename
);
1068 #ifdef HAVE_LIBREADLINE
1069 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1071 rc
= set_inquire (-1, NULL
, &inq
);
1078 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1080 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 1);
1084 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1086 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
1090 rc
= pwmd_open (pwm
, filename
, inquire_cb
, inq
);
1100 set_command (const char *line
)
1103 char name
[256] = { 0 };
1104 char value
[512] = { 0 };
1107 const char *p
= line
;
1109 while (p
&& *p
&& isspace (*p
))
1112 namep
= parse_arg (p
, name
, sizeof (name
));
1113 if (!namep
|| !*namep
)
1115 fprintf (stderr
, N_("Usage: .set help | <name> [<value>]\n"));
1116 return GPG_ERR_SYNTAX
;
1119 p
+= strlen (namep
);
1120 while (p
&& *p
&& isspace (*p
))
1123 valuep
= parse_arg (p
, value
, sizeof (value
));
1125 if (!strcmp (name
, "keyfile") || !strcmp (name
, "new-keyfile")
1126 || !strcmp (name
, "sign-keyfile"))
1128 int is_newkeyfile
= 1;
1129 int sign
= !strcmp (name
, "sign-keyfile");
1131 if (!strcmp (name
, "keyfile") || sign
)
1136 pwmd_free (new_keyfile
);
1141 pwmd_free (sign_keyfile
);
1142 sign_keyfile
= NULL
;
1146 pwmd_free (keyfile
);
1153 new_keyfile
= pwmd_strdup (value
);
1155 sign_keyfile
= pwmd_strdup (value
);
1157 keyfile
= pwmd_strdup (value
);
1161 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 1);
1163 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1166 else if (!local_pin
&& !no_pinentry
)
1170 pwmd_socket_type (pwm
, &t
);
1171 if (t
== PWMD_SOCKET_LOCAL
)
1173 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 0);
1175 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1179 else if (!strcmp(name
, "pinentry-timeout"))
1182 int n
= strtol(valuep
, &e
, 10);
1185 return gpg_error (GPG_ERR_INV_VALUE
);
1188 n
= DEFAULT_PIN_TIMEOUT
;
1190 rc
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, n
);
1192 else if (!strcmp (name
, "help"))
1196 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1197 "delimited. When no value is specified the option is unset.\n\n"
1198 "keyfile [<filename>]\n"
1199 " set or unset the keyfile to be used when a passphrase is required (*)\n"
1201 "new-keyfile [<filename>]\n"
1202 " set or unset the keyfile to be used when a new passphrase is required (*)\n"
1204 "sign-keyfile [<filename>]\n"
1205 " set or unset the keyfile to be used when a passphrase is required for\n"
1206 " signing (symmetric) (*)\n"
1208 "pinentry-timeout <seconds>\n"
1209 " the amount of seconds before pinentry gives up waiting for input\n"
1211 "* = the next protocol command will unset this value\n"
1215 rc
= GPG_ERR_UNKNOWN_OPTION
;
1221 save_command (const char *line
)
1223 struct inquire_s
*inq
= NULL
;
1226 #ifdef HAVE_LIBREADLINE
1227 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1229 rc
= set_inquire (-1, NULL
, &inq
);
1234 if (new_keyfile
|| keyfile
|| sign_keyfile
)
1236 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1238 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 1);
1242 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1244 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
1248 rc
= pwmd_save (pwm
, line
, inquire_cb
, inq
);
1258 do_save_passwd_command (const char *line
, int save
)
1260 struct inquire_s
*inq
= NULL
;
1263 #ifdef HAVE_LIBREADLINE
1264 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1266 rc
= set_inquire (-1, NULL
, &inq
);
1271 if (new_keyfile
|| keyfile
|| sign_keyfile
)
1273 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1275 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 1);
1279 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1281 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
1287 rc
= pwmd_save (pwm
, line
, inquire_cb
, inq
);
1289 rc
= pwmd_passwd (pwm
, line
, inquire_cb
, inq
);
1300 parse_dotcommand (const char *line
, char **result
,
1301 size_t * len
, struct inquire_s
*inq
)
1303 const char *p
= line
;
1306 if (!strncmp (p
, ".read", 5))
1307 rc
= read_command (p
+ 5, result
, len
);
1308 else if (!strncmp (p
, ".redir", 6))
1309 rc
= redir_command (p
+ 6);
1310 else if (!strncmp (p
, ".help", 5))
1311 rc
= help_command (p
+ 5);
1312 else if (!strncmp (p
, ".open", 5))
1313 rc
= open_command (p
+ 5);
1314 else if (!strncmp (p
, ".set", 4))
1315 rc
= set_command (p
+ 4);
1316 else if (!strncmp (p
, ".save", 5))
1317 rc
= do_save_passwd_command (p
+ 5, 1);
1318 else if (!strncmp (p
, ".passwd", 7))
1319 rc
= do_save_passwd_command (p
+ 7, 0);
1322 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, "%s", line
);
1323 #ifdef HAVE_LIBREADLINE
1328 #ifdef HAVE_LIBREADLINE
1336 #ifdef HAVE_LIBREADLINE
1341 struct inquire_s
*inq
= NULL
;
1344 rc
= process_cmd ();
1348 rc
= set_inquire (STDIN_FILENO
, NULL
, &inq
);
1353 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1355 rl_event_hook
= &interactive_hook
;
1356 rl_set_keyboard_input_timeout (100000);
1361 char *result
= NULL
;
1365 line
= readline ("pwm> ");
1366 if (interactive_error
)
1369 rc
= interactive_error
;
1379 if (gpg_err_code (rc
) != GPG_ERR_CANCELED
&&
1380 gpg_err_code (rc
) != GPG_ERR_EOF
)
1381 fprintf (stderr
, "ERR %i: %s\n", rc
, gpg_strerror (rc
));
1391 #ifdef HAVE_READLINE_HISTORY
1394 rc
= parse_dotcommand (line
, &result
, &len
, inq
);
1400 if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
1401 (void) pwmd_command (pwm
, &tmp
, NULL
, NULL
, NULL
,
1402 "GETINFO last_error");
1404 show_error (pwm
, rc
, tmp
);
1407 else if (result
&& len
)
1408 printf ("%s%s", result
, result
[len
- 1] != '\n' ? "\n" : "");
1422 #ifdef HAVE_LIBREADLINE
1429 fprintf (stderr
, "\n");
1437 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1438 p
= fgets (buf
, sizeof (buf
), stdin
);
1452 return GPG_ERR_CANCELED
;
1456 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1457 "CLEARCACHE %s", filename
);
1461 interactive_hook ();
1477 if (save
&& !filename
)
1481 ("No filename was specified on the command line. Aborting.\n"));
1482 return GPG_ERR_CANCELED
;
1485 if (save
&& filename
)
1488 pwmd_strdup_printf ("%s %s%s %s%s %s",
1489 symmetric
? "--symmetric" : "",
1490 keyid
? "--keyid=" : "",
1492 sign_keyid
? "--sign-keyid=" : "",
1493 sign_keyid
? sign_keyid
: "",
1494 keyparams
? "--inquire-keyparam" : "");
1496 #ifdef HAVE_LIBREADLINE
1497 if (!quiet
|| interactive
)
1503 fprintf (stderr
, "\n");
1504 fprintf (stderr
, N_("Saving changes ...\n"));
1507 rc
= save_command (args
);
1511 #ifdef HAVE_LIBREADLINE
1513 return rc
? rc
: quit
? 0 : GPG_ERR_CANCELED
;
1520 parse_status_ignore (char *str
)
1525 for (p
= status_ignore
; p
&& *p
; p
++)
1528 pwmd_free (status_ignore
);
1529 status_ignore
= NULL
;
1533 while ((s
= strsep (&str
, ",")))
1535 p
= pwmd_realloc (status_ignore
, (n
+ 2) * sizeof (char *));
1536 p
[n
++] = pwmd_strdup (s
);
1543 main (int argc
, char *argv
[])
1548 char command
[ASSUAN_LINELENGTH
], *p
= NULL
;
1549 char *result
= NULL
;
1551 char *pinentry_path
= NULL
;
1552 char *display
= NULL
, *tty
= NULL
, *ttytype
= NULL
;
1553 char *lcctype
= NULL
, *lcmessages
= NULL
;
1554 int outfd
= STDOUT_FILENO
;
1555 FILE *outfp
= stdout
;
1556 FILE *inquirefp
= stdin
;
1557 int show_status
= 1;
1558 char *clientname
= "pwmc";
1559 char *inquire
= NULL
;
1560 char *inquire_line
= NULL
;
1563 int use_ssh_agent
= 1;
1564 char *knownhosts
= NULL
;
1565 char *identity
= NULL
;
1568 char *cacert
= NULL
;
1569 char *clientcert
= NULL
;
1570 char *clientkey
= NULL
;
1573 char *tls_fingerprint
= NULL
;
1575 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1576 pwmd_socket_t socktype
;
1577 long socket_timeout
= 300;
1578 int connect_timeout
= 120;
1580 int lock_on_open
= 1;
1581 long lock_timeout
= 50;
1584 /* The order is important. */
1587 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1588 OPT_SOCKET_TIMEOUT
, OPT_CONNECT_TIMEOUT
,
1591 OPT_USE_SSH_AGENT
, OPT_IDENTITY
, OPT_KNOWNHOSTS
,
1594 OPT_CACERT
, OPT_CLIENTCERT
, OPT_CLIENTKEY
, OPT_PRIORITY
, OPT_VERIFY
,
1597 OPT_URL
, OPT_LOCAL
, OPT_TTYNAME
, OPT_TTYTYPE
,
1598 OPT_DISPLAY
, OPT_LC_CTYPE
, OPT_LC_MESSAGES
, OPT_TIMEOUT
, OPT_TRIES
,
1599 OPT_PINENTRY
, OPT_KEYFILE
, OPT_NEW_KEYFILE
, OPT_SIGN_KEYFILE
, OPT_NOLOCK
,
1600 OPT_LOCK_TIMEOUT
, OPT_SAVE
, OPT_OUTPUT_FD
, OPT_INQUIRE
,
1601 OPT_INQUIRE_FD
, OPT_INQUIRE_FILE
, OPT_INQUIRE_LINE
, OPT_NO_STATUS
,
1603 OPT_STATUSFD
, OPT_NAME
, OPT_VERSION
, OPT_HELP
, OPT_KEYID
, OPT_SIGN_KEYID
,
1604 OPT_SYMMETRIC
, OPT_KEYPARAMS
, OPT_NO_PINENTRY
, OPT_QUIET
,
1605 #ifdef HAVE_LIBREADLINE
1609 const struct option long_opts
[] = {
1610 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1611 {"socket-timeout", 1, 0, 0},
1612 {"connect-timeout", 1, 0, 0},
1616 {"no-ssh-agent", 0, 0, 0},
1617 {"identity", 1, 0, 'i'},
1618 {"knownhosts", 1, 0, 'k'},
1621 {"ca-cert", 1, 0, 0},
1622 {"client-cert", 1, 0, 0},
1623 {"client-key", 1, 0, 0},
1624 {"tls-priority", 1, 0, 0},
1625 {"tls-verify", 0, 0, 0},
1626 {"tls-fingerprint", 1, 0, 0},
1629 {"local-pinentry", 0, 0},
1630 {"ttyname", 1, 0, 'y'},
1631 {"ttytype", 1, 0, 't'},
1632 {"display", 1, 0, 'd'},
1633 {"lc-ctype", 1, 0, 0},
1634 {"lc-messages", 1, 0, 0},
1635 {"timeout", 1, 0, 0},
1637 {"pinentry", 1, 0, 0},
1638 {"key-file", 1, 0, 0},
1639 {"new-key-file", 1, 0, 0},
1640 {"sign-key-file", 1, 0, 0},
1641 {"no-lock", 0, 0, 0},
1642 {"lock-timeout", 1, 0, 0},
1643 {"save", 0, 0, 'S'},
1644 {"output-fd", 1, 0, 0},
1645 {"inquire", 1, 0, 0},
1646 {"inquire-fd", 1, 0, 0},
1647 {"inquire-file", 1, 0, 0},
1648 {"inquire-line", 1, 0, 'L'},
1649 {"no-status", 0, 0, 0},
1650 {"status-ignore", 1, 0, 0},
1651 {"status-fd", 1, 0, 0},
1652 {"name", 1, 0, 'n'},
1653 {"version", 0, 0, 0},
1656 {"sign-keyid", 1, 0, 0},
1657 {"symmetric", 0, 0, 0},
1658 {"key-params", 1, 0, 0},
1659 {"no-pinentry", 0, 0, 0},
1661 #ifdef HAVE_LIBREADLINE
1662 {"interactive", 0, 0},
1667 const char *optstring
= "L:y:t:d:P:I:Sn:i:k:s";
1669 const char *optstring
= "L:y:t:d:P:I:Sn:s";
1674 setlocale (LC_ALL
, "");
1675 bindtextdomain ("libpwmd", LOCALEDIR
);
1678 tries
= DEFAULT_PIN_TRIES
;
1679 inquirefd
= STDIN_FILENO
;
1680 statusfd
= STDERR_FILENO
;
1681 statusfp
= fdopen (statusfd
, "w");
1682 tmp
= pwmd_strdup (DEFAULT_STATUS_IGNORE
);
1683 parse_status_ignore (tmp
);
1687 getopt_long (argc
, argv
, optstring
, long_opts
, &opt_index
)) != -1)
1691 /* Handle long options without a short option part. */
1695 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1696 case OPT_SOCKET_TIMEOUT
:
1697 socket_timeout
= strtol (optarg
, &p
, 10);
1699 case OPT_CONNECT_TIMEOUT
:
1700 connect_timeout
= strtol (optarg
, &p
, 10);
1704 case OPT_USE_SSH_AGENT
:
1712 case OPT_CLIENTCERT
:
1713 clientcert
= optarg
;
1725 tls_fingerprint
= optarg
;
1735 keyfile
= pwmd_strdup (optarg
);
1737 case OPT_NEW_KEYFILE
:
1738 new_keyfile
= pwmd_strdup (optarg
);
1740 case OPT_SIGN_KEYFILE
:
1741 sign_keyfile
= pwmd_strdup (optarg
);
1746 case OPT_LOCK_TIMEOUT
:
1747 lock_timeout
= strtol (optarg
, &p
, 10);
1756 lcctype
= pwmd_strdup (optarg
);
1758 case OPT_LC_MESSAGES
:
1759 lcmessages
= pwmd_strdup (optarg
);
1762 timeout
= strtol (optarg
, &p
, 10);
1765 tries
= strtol (optarg
, &p
, 10);
1768 inquire
= escape (optarg
);
1770 case OPT_INQUIRE_FD
:
1771 inquirefd
= strtol (optarg
, &p
, 10);
1774 inquirefp
= fdopen (inquirefd
, "r");
1776 err (EXIT_FAILURE
, "%i", inquirefd
);
1779 case OPT_INQUIRE_FILE
:
1780 inquirefd
= open (optarg
, O_RDONLY
);
1781 if (inquirefd
== -1)
1782 err (EXIT_FAILURE
, "%s", optarg
);
1783 inquirefp
= fdopen (inquirefd
, "r");
1786 outfd
= strtol (optarg
, &p
, 10);
1789 outfp
= fdopen (outfd
, "w");
1791 err (EXIT_FAILURE
, "%i", outfd
);
1798 statusfd
= strtol (optarg
, &p
, 10);
1801 statusfp
= fdopen (statusfd
, "w");
1803 err (EXIT_FAILURE
, "%i", statusfd
);
1806 case OPT_STATUS_IGNORE
:
1807 parse_status_ignore (optarg
);
1810 printf ("%s (pwmc)\n\n"
1811 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015\n"
1813 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1814 "Compile-time features:\n"
1815 #ifdef HAVE_LIBREADLINE
1830 #ifdef WITH_PINENTRY
1845 "\n", PACKAGE_STRING
, PACKAGE_BUGREPORT
);
1846 exit (EXIT_SUCCESS
);
1848 pinentry_path
= optarg
;
1851 usage (argv
[0], EXIT_SUCCESS
);
1855 case OPT_SIGN_KEYID
:
1856 sign_keyid
= optarg
;
1862 case OPT_NO_PINENTRY
:
1865 #ifdef HAVE_LIBREADLINE
1866 case OPT_INTERACTIVE
:
1871 usage (argv
[0], EXIT_FAILURE
);
1876 fprintf (stderr
, N_("%s: invalid argument for option '--%s'\n"),
1877 argv
[0], long_opts
[opt_index
].name
);
1878 usage (argv
[0], EXIT_FAILURE
);
1887 knownhosts
= optarg
;
1891 inquire_line
= optarg
;
1906 clientname
= optarg
;
1909 usage (argv
[0], EXIT_FAILURE
);
1913 #ifdef HAVE_LIBREADLINE
1914 if (interactive
&& !isatty (STDIN_FILENO
))
1915 usage (argv
[0], EXIT_FAILURE
);
1916 else if (isatty (STDIN_FILENO
) && !inquire
&& !inquire_line
)
1920 filename
= argv
[optind
];
1922 rc
= pwmd_new (clientname
, &pwm
);
1926 pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TRIES
, tries
);
1928 fprintf (stderr
, N_("Connecting ...\n"));
1930 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1931 socktype
= is_remote_url (url
);
1932 if (socktype
!= PWMD_SOCKET_LOCAL
)
1935 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1936 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, connect_timeout
);
1941 if (socktype
== PWMD_SOCKET_SSH
)
1944 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_CB
, knownhost_cb
);
1948 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_DATA
, clientname
);
1952 if (!getenv ("SSH_AUTH_SOCK") || identity
)
1955 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_AGENT
, use_ssh_agent
);
1959 rc
= pwmd_connect (pwm
, url
, identity
, knownhosts
);
1965 rc
= pwmd_setopt (pwm
, PWMD_OPTION_TLS_VERIFY
, tls_verify
);
1969 rc
= pwmd_connect (pwm
, url
, clientcert
, clientkey
, cacert
, prio
,
1975 rc
= pwmd_connect (pwm
, url
);
1977 rc
= pwmd_connect (pwm
, url
);
1983 fprintf (stderr
, N_("Connected.\n"));
1986 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1987 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, socket_timeout
);
1994 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1995 "OPTION LOCK-TIMEOUT=%li", lock_timeout
);
2002 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCK_ON_OPEN
, 1);
2007 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, NULL
, NULL
);
2013 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, timeout
);
2018 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
2022 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
,
2023 (local_pin
|| keyfile
|| new_keyfile
|| sign_keyfile
));
2029 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_PATH
, pinentry_path
);
2036 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DISPLAY
, display
);
2043 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TTY
, tty
);
2050 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TERM
, ttytype
);
2057 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_CTYPE
, lcctype
);
2064 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_MESSAGES
, lcmessages
);
2071 rc
= pwmd_setopt (pwm
, PWMD_OPTION_STATUS_CB
, status_msg_cb
);
2078 rc
= open_command (filename
);
2083 #ifdef HAVE_LIBREADLINE
2086 rc
= do_interactive ();
2094 struct inquire_s
*inq
= NULL
;
2096 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2098 rc
= pwmd_command (pwm
, &result
, &len
, inquire_cb
, inq
, "%s", inquire
);
2104 if (fcntl (STDIN_FILENO
, F_SETFL
, O_NONBLOCK
) == -1)
2106 rc
= gpg_error_from_errno (errno
);
2114 rc
= process_cmd ();
2119 n
= read (STDIN_FILENO
, command
, sizeof (command
)-1);
2122 if (errno
== EAGAIN
)
2128 rc
= gpg_error_from_errno (errno
);
2139 if (!p
|| !*p
|| !strcasecmp (p
, "BYE"))
2143 struct inquire_s
*inq
= NULL
;
2144 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2147 rc
= parse_dotcommand (command
, &result
, &len
, inq
);
2157 fwrite (result
, 1, result
[len
- 1] == 0 ? len
- 1 : len
, outfp
);
2165 else if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
2166 (void) pwmd_command (pwm
, &result
, NULL
, NULL
, NULL
,
2167 "GETINFO last_error");
2169 #ifdef HAVE_LIBREADLINE
2172 memset (command
, 0, sizeof (command
));
2175 show_error (pwm
, rc
, result
);
2181 parse_status_ignore (NULL
);
2182 if (connected
&& !quiet
)
2183 fprintf (stderr
, N_("Connection closed.\n"));
2185 exit (rc
? EXIT_FAILURE
: EXIT_SUCCESS
);