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
;
98 static char *keyparams
;
100 static char *new_keyfile
;
102 static int local_pin
;
103 static int inquirefd
;
107 static char **status_ignore
;
114 size_t size
; // from stat(2).
118 static gpg_error_t
finalize ();
119 static gpg_error_t
set_inquire (int fd
, const char *line
,
120 struct inquire_s
**result
);
121 static gpg_error_t
parse_dotcommand (const char *line
, char **result
,
122 size_t * len
, struct inquire_s
*inq
);
123 static gpg_error_t
open_command (const char *line
);
125 static gpg_error_t
get_password (char **result
, pwmd_pinentry_t w
, int echo
);
129 show_error (pwm_t
*pwm
, gpg_error_t rc
, const char *str
)
132 if (pwmd_tls_error (pwm
))
133 fprintf(stderr
, "TLS: %s\n", gnutls_strerror(pwmd_tls_error(pwm
)));
135 fprintf (stderr
, "ERR %i: %s%s%s%s", rc
, gpg_strerror (rc
),
136 str
? ": " : "", str
? str
: "", str
? "" : "\n");
143 pwmd_free (new_keyfile
);
144 keyfile
= new_keyfile
= NULL
;
148 usage (const char *pn
, int status
)
150 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
151 N_("Usage: pwmc [options] [file]\n"
153 " a url string to connect to (%s, see below)\n"
154 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
155 " --connect-timeout <seconds>\n"
156 " seconds before connecting to a remote host fails (0=disabled, 120)\n"
157 " --socket-timeout <seconds>\n"
158 " seconds before a remote command fails (0=disabled, 300)\n"
161 " --ca-cert <filename>\n"
162 " certificate authority (CA) used to sign the server cert\n"
163 " --client-cert <filename>\n"
164 " client certificate to use for authentication\n"
165 " --client-key <filename>\n"
166 " key file used to protect the client certificate\n"
167 " --tls-priority <string>\n"
168 " compression, cipher and hash algorithm string\n"
169 " (SECURE256:SECURE192:SECURE128:-VERS-SSL3.0)\n"
171 " verify the hostname against the server certificate\n"
172 " --tls-fingerprint <string>\n"
173 " a SHA-256 hash of the server fingerprint to verify against\n"
177 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
178 " --identity, -i <filename>\n"
179 " the ssh identity file to use for authentication\n"
180 " --knownhosts, -k <filename>\n"
181 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
184 " do not lock the data file upon opening it\n"
185 " --lock-timeout <N>\n"
186 " time in tenths of a second to wait for a locked data file (50)\n"
187 " --name, -n <string>\n"
188 " set the client name\n"
189 " --pinentry <path>\n"
190 " the full path to the pinentry binary\n"
191 " --local-pinentry\n"
192 " force using a local pinentry\n"
194 " disable pinentry both remotely and locally\n"
195 " --ttyname, -y <path>\n"
196 " tty that pinentry will use\n"
197 " --ttytype, -t <string>\n"
198 " pinentry terminal type (default is $TERM)\n"
200 " pinentry display (default is $DISPLAY)\n"
201 " --lc-ctype <string>\n"
202 " locale setting for pinentry\n"
203 " --lc-messages <string>\n"
204 " locale setting for pinentry\n"
206 " number of pinentry tries before failing (3)\n"
207 " --timeout <seconds>\n"
208 " pinentry timeout\n"
209 " --inquire <COMMAND>\n"
210 " the specified command (with any options) uses a server inquire while\n"
211 " command data is read via the inquire file descriptor (stdin)\n"
212 " --inquire-line, -L <STRING>\n"
213 " the initial line to send (i.e., element path) before the inquire data\n"
214 " --inquire-fd <FD>\n"
215 " read inquire data from the specified file descriptor (stdin)\n"
216 " --inquire-file <filename>\n"
217 " read inquire data from the specified filename\n"
218 " --output-fd <FD>\n"
219 " redirect command output to the specified file descriptor\n"
221 " send the SAVE command before exiting\n"
222 " --key-file <filename>\n"
223 " obtain the passphrase from the specified filename\n"
224 " --new-key-file <filename>\n"
225 " obtain the passphrase to save with from the specified filename\n"
226 " --key-params <string>\n"
227 " the key parameters to use when saving a new file (pwmd default)\n"
228 " --keyid <recipient>[,<recipient>]\n"
229 " the public key ID to u\n"
230 " --sign-keyid <string>\n"
231 " the key ID to sign the data file with\n"
233 " disable showing of status messages from the server\n"
234 " --status-ignore <string[,...]>\n"
235 " prevent parsing of the specified status message keywords\n"
237 " disable showing of extra messages (implies --no-status)\n"
238 " --status-fd <FD>\n"
239 " redirect status messages to the specified file descriptor\n"
240 #ifdef HAVE_LIBREADLINE
242 " use a shell like interface to pwmd (allows more than one command)\n"
246 #ifdef DEFAULT_PWMD_SOCKET
252 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
254 "An optional url may be in the form of:\n"
255 " --url /path/to/socket\n"
256 " --url file://[path/to/socket]\n"
259 " --url ssh[46]://[username@]hostname[:port]\n"
260 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
264 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
265 " --client-key filename\n"
267 #ifdef HAVE_LIBREADLINE
269 "Interactive mode is used when input is from a terminal.\n"
276 inquire_cb (void *user
, const char *keyword
, gpg_error_t rc
,
277 char **data
, size_t * size
)
279 struct inquire_s
*inq
= user
;
281 int is_newpassword
= 0;
289 if (!strcmp (keyword
, "PASSPHRASE"))
291 else if (!strcmp (keyword
, "NEW_PASSPHRASE"))
293 #ifdef HAVE_LIBREADLINE
294 else if (!strcmp (keyword
, "KEYPARAM") && !interactive
)
297 else if (!strcmp (keyword
, "KEYPARAM"))
300 if (!keyparams
|| !*keyparams
)
301 return gpg_error (GPG_ERR_INV_PARAMETER
);
304 *size
= strlen (keyparams
);
305 return gpg_error (GPG_ERR_EOF
);
308 if ((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
))
310 int fd
= open (is_password
? keyfile
: new_keyfile
, O_RDONLY
);
314 fprintf (stderr
, "%s: %s\n", is_newpassword
? new_keyfile
: keyfile
,
316 return gpg_error_from_syserror ();
319 rc
= set_inquire (fd
, NULL
, &inq
);
327 fprintf (stderr
, N_("Using keyfile '%s' as %s.\n"),
328 is_newpassword
? new_keyfile
: keyfile
, keyword
);
330 else if ((is_password
&& !keyfile
) || (is_newpassword
&& !new_keyfile
))
334 rc
= pwmd_password (pwm
, keyword
, &tmp
, &inq
->len
);
335 if (rc
&& gpg_err_code (rc
) != GPG_ERR_EOF
)
338 pwmd_free (inq
->line
);
342 return gpg_error (GPG_ERR_EOF
);
344 #ifdef HAVE_LIBREADLINE
345 else if ((!inq
->last_keyword
|| strcmp (keyword
, inq
->last_keyword
))
350 ("%sPress CTRL-D to send the current line. Press twice to end. %s:\n"),
351 inq
->last_keyword
? "\n" : "", keyword
);
352 pwmd_free (inq
->last_keyword
);
353 inq
->last_keyword
= pwmd_strdup (keyword
);
357 /* The first part of the command data. */
363 return inq
->fd
== -1 ? gpg_error (GPG_ERR_EOF
) : 0;
366 *size
= read (inq
->fd
, inq
->line
, ASSUAN_LINELENGTH
);
370 return gpg_error (gpg_error_from_syserror ());
374 else if (inq
->fd
!= STDIN_FILENO
&& (is_newpassword
|| is_password
))
382 if (((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
))
383 && *size
== inq
->size
)
384 return gpg_error (GPG_ERR_EOF
);
386 return *size
? 0 : gpg_error (GPG_ERR_EOF
);
390 status_msg_cb (void *data
, const char *line
)
392 char *p
= strchr (line
, ' ');
395 /* Ignore status messages specified by the client via --status-ignore. */
396 for (s
= status_ignore
; s
&& *s
; s
++)
398 char *tmp
= strchr (line
, ' ');
399 size_t len
= tmp
? strlen (line
) - strlen (tmp
) : strlen (line
);
401 if (!strncmp (line
, *s
, len
) && len
== strlen (*s
))
405 if (statusfd
!= STDERR_FILENO
&& strncmp (line
, "STATE ", 6) && *line
!= '#'
406 && p
&& strchr (p
, ' ') && *++p
)
408 char *p1
= strchr (p
, ' ');
409 int a
= strtol (p
, NULL
, 10);
411 if (isdigit (*p
) && p1
)
413 int b
= strtol (p1
, NULL
, 10);
415 int t
= a
&& b
? a
* 100 / b
: 0;
417 strncpy (l
, line
, strlen (line
) - strlen (p
) - 1);
418 fprintf (statusfp
, "\r%s %i/%i %i%%%s", l
, a
, b
, t
,
425 fprintf (statusfp
, "%s\n", line
);
427 #ifdef HAVE_LIBREADLINE
436 return pwmd_process (pwm
);
441 get_password (char **result
, pwmd_pinentry_t w
, int echo
)
443 char buf
[LINE_MAX
] = { 0 }, *p
;
444 struct termios told
, tnew
;
449 if (!isatty (STDIN_FILENO
))
451 fprintf (stderr
, N_("Input is not from a terminal! Failing.\n"));
452 return GPG_ERR_ENOTTY
;
457 if (tcgetattr (STDIN_FILENO
, &told
) == -1)
458 return gpg_error_from_syserror ();
460 memcpy (&tnew
, &told
, sizeof (struct termios
));
461 tnew
.c_lflag
&= ~(ECHO
);
462 tnew
.c_lflag
|= ICANON
| ECHONL
;
464 if (tcsetattr (STDIN_FILENO
, TCSANOW
, &tnew
) == -1)
468 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
469 return gpg_error_from_errno (n
);
475 case PWMD_PINENTRY_OPEN
:
476 fprintf (stderr
, N_("Password for %s: "), filename
);
478 case PWMD_PINENTRY_OPEN_FAILED
:
479 fprintf (stderr
, N_("Invalid password. Password for %s: "), filename
);
481 case PWMD_PINENTRY_SAVE
:
482 fprintf (stderr
, N_("New password for %s: "), filename
);
484 case PWMD_PINENTRY_SAVE_CONFIRM
:
485 fprintf (stderr
, N_("Confirm password: "));
491 if ((p
= fgets (buf
, sizeof (buf
), stdin
)) == NULL
)
494 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
500 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
505 return GPG_ERR_CANCELED
;
508 p
[strlen (p
) - 1] = 0;
512 key
= pwmd_strdup_printf ("%s", p
);
513 memset (&buf
, 0, sizeof (buf
));
516 return GPG_ERR_ENOMEM
;
524 knownhost_cb (void *data
, const char *host
, const char *key
, size_t len
)
528 pwmd_strdup_printf (N_
529 ("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?"),
530 (char *) data
, host
, host
);
532 if (no_pinentry
&& !isatty (STDIN_FILENO
))
534 fprintf (stderr
, N_("Input is not from a terminal! Failing.\n"));
536 return GPG_ERR_ENOTTY
;
538 else if (no_pinentry
)
540 for (char *p
= buf
, len
= 0; *p
; p
++, len
++)
549 while (!isspace (*(--p
)));
556 fprintf (stderr
, "%s\n\n", buf
);
563 fprintf (stderr
, N_("Trust this connection [y/N]: "));
565 rc
= get_password (&result
, PWMD_PINENTRY_CONFIRM
, 1);
570 if (!result
|| !*result
|| *result
== 'n' || *result
== 'N')
572 if (result
&& *result
)
575 return GPG_ERR_NOT_CONFIRMED
;
578 if ((*result
== 'y' || *result
== 'Y') && *(result
+ 1) == 0)
587 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, buf
);
593 return pwmd_getpin (pwm
, NULL
, NULL
, NULL
, PWMD_PINENTRY_CONFIRM
);
597 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
599 is_remote_url (const char *str
)
602 return PWMD_SOCKET_LOCAL
;
605 if (strstr (str
, "ssh://") || strstr (str
, "ssh4://")
606 || strstr (str
, "ssh6://"))
607 return PWMD_SOCKET_SSH
;
611 if (strstr (str
, "tls://") || strstr (str
, "tls4://")
612 || strstr (str
, "tls6://"))
613 return PWMD_SOCKET_TLS
;
616 return PWMD_SOCKET_LOCAL
;
621 escape (const char *str
)
624 char *buf
= pwmd_malloc (ASSUAN_LINELENGTH
+ 1), *b
= buf
;
627 for (p
= str
; *p
; p
++, len
++)
629 if (len
== ASSUAN_LINELENGTH
)
673 free_inquire (struct inquire_s
*inq
)
678 pwmd_free (inq
->line
);
680 if (inq
->fd
!= -1 && inq
->fd
!= STDIN_FILENO
)
683 pwmd_free (inq
->last_keyword
);
687 /* When *result is not NULL it is updated to the new values and not
690 set_inquire (int fd
, const char *line
, struct inquire_s
**result
)
692 struct inquire_s inq
= { 0 };
693 struct stat st
= { 0 };
698 if (fstat (fd
, &st
) == -1)
699 return gpg_error_from_syserror ();
701 inq
.size
= st
.st_size
;
705 inq
.line
= pwmd_calloc (1, ASSUAN_LINELENGTH
);
707 return GPG_ERR_ENOMEM
;
711 char *s
= escape (line
);
715 pwmd_free (inq
.line
);
716 return GPG_ERR_ENOMEM
;
719 if (strlen (s
) >= ASSUAN_LINELENGTH
)
721 pwmd_free (inq
.line
);
723 return GPG_ERR_LINE_TOO_LONG
;
726 strncpy (inq
.line
, s
, ASSUAN_LINELENGTH
- 1);
727 inq
.len
= strlen (s
);
731 rc
= pwmd_setopt (pwm
, PWMD_OPTION_INQUIRE_TOTAL
,
732 st
.st_size
? st
.st_size
+ strlen (inq
.line
) : 0);
735 pwmd_free (inq
.line
);
740 *result
= pwmd_malloc (sizeof (struct inquire_s
));
743 if ((*result
)->fd
!= -1 && (*result
)->fd
!= STDIN_FILENO
)
744 close ((*result
)->fd
);
746 pwmd_free ((*result
)->line
);
747 (*result
)->line
= NULL
;
752 memcpy (*result
, &inq
, sizeof (struct inquire_s
));
753 memset (&inq
, 0, sizeof (struct inquire_s
));
757 #ifdef HAVE_LIBREADLINE
759 interactive_hook (void)
761 interactive_error
= process_cmd ();
763 if (interactive_error
)
764 rl_event_hook
= NULL
;
774 ("------------------------------------------------------------------------------\n"
775 "Elements are TAB delimited. Press CTRL-V then TAB to insert from the prompt.\n"
777 "Type HELP for protocol commands. Type .help for pwmc commands. Press CTRL-D\n"
779 "------------------------------------------------------------------------------\n"));
784 parse_arg (const char *src
, char *dst
, size_t len
)
790 for (; s
&& *s
&& *s
!= ' ' && n
< len
; s
++, n
++)
798 parse_opt (char **line
, const char *opt
, gpg_error_t
* rc
)
800 static char result
[ASSUAN_LINELENGTH
] = { 0 }, *r
= result
;
801 char *s
= strstr (*line
, opt
);
811 size_t rlen
= strlen (opt
);
815 while (*p
&& *p
== ' ')
821 for (; *p
&& len
< sizeof (result
) - 1; p
++, rlen
++)
823 if (isspace (*p
) && !quote
)
826 if (*p
== '\"' && lastc
!= '\\')
839 if (len
>= sizeof (result
) - 1)
840 *rc
= GPG_ERR_LINE_TOO_LONG
;
845 while (*p
&& *p
== ' ')
856 read_command (const char *line
, char **result
, size_t * len
)
860 char *filename
= NULL
;
861 struct inquire_s
*inq
= NULL
;
862 char *p
= (char *) line
;
863 const char *prefix
= parse_opt (&p
, "--prefix", &rc
);
864 char filebuf
[ASSUAN_LINELENGTH
];
873 while (*p
&& isspace (*p
))
876 filename
= parse_arg (p
, filebuf
, sizeof (filebuf
));
877 if (filename
&& *filename
)
879 p
+= strlen (filename
) + 1;
881 while (*p
&& isspace (*p
))
893 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
896 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\" = \")\n"));
900 fd
= open (filename
, O_RDONLY
);
902 return gpg_error_from_syserror ();
904 rc
= set_inquire (fd
, prefix
&& *prefix
? prefix
: NULL
, &inq
);
911 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, "%s", p
);
917 redir_command (const char *line
)
919 const char *p
= line
;
921 gpg_error_t rc
= GPG_ERR_SYNTAX
;
922 char *filename
= NULL
;
923 struct inquire_s
*inq
= NULL
;
926 char filebuf
[ASSUAN_LINELENGTH
];
930 filename
= parse_arg (p
, filebuf
, sizeof (filebuf
));
931 if (filename
&& *filename
)
933 p
+= strlen (filename
) + 1;
935 while (*p
&& isspace (*p
))
945 fprintf (stderr
, N_("Usage: .redir <filename> <command> [args]\n"));
949 fd
= open (filename
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600);
951 return gpg_error_from_syserror ();
953 #ifdef HAVE_LIBREADLINE
954 rc
= set_inquire (interactive
? STDIN_FILENO
: inquirefd
, NULL
, &inq
);
956 rc
= set_inquire (inquirefd
, NULL
, &inq
);
964 rc
= parse_dotcommand (p
, &result
, &len
, inq
);
965 if (!rc
&& result
&& len
--)
966 { // null byte which is always appended
967 if (write (fd
, result
, len
) != len
)
968 rc
= GPG_ERR_TOO_SHORT
;
978 help_command (const char *line
)
981 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
982 " .redir <filename> <command>\n"
983 " redirect the output of a command to the specified file\n"
985 " .open <filename>\n"
986 " open the specified filename losing any changes to the current one\n"
988 " .read [--prefix <string>] <filename> <command> [args]\n"
989 " obtain data from the specified filename for an inquire command\n"
991 " .set help | <name> [<value>]\n"
992 " set option <name> to <value>\n"
995 " write changes of the file to disk\n"
998 " change the passphrase of a data file\n"
1001 " this help text\n"));
1006 open_command (const char *line
)
1008 struct inquire_s
*inq
= NULL
;
1009 const char *filename
= line
;
1012 while (filename
&& isspace (*filename
))
1015 if (!filename
|| !*filename
)
1017 fprintf (stderr
, N_("Usage: .open <filename>\n"));
1018 return GPG_ERR_SYNTAX
;
1021 #ifdef HAVE_LIBREADLINE
1022 if (interactive
|| !quiet
)
1026 fprintf (stderr
, N_("Opening data file \"%s\" ...\n"), filename
);
1028 #ifdef HAVE_LIBREADLINE
1029 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1031 rc
= set_inquire (-1, NULL
, &inq
);
1038 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1040 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 1);
1044 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1046 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
1050 rc
= pwmd_open (pwm
, filename
, inquire_cb
, inq
);
1058 set_command (const char *line
)
1061 char name
[256] = { 0 };
1062 char value
[512] = { 0 };
1065 const char *p
= line
;
1067 while (p
&& *p
&& isspace (*p
))
1070 namep
= parse_arg (p
, name
, sizeof (name
));
1071 if (!namep
|| !*namep
)
1073 fprintf (stderr
, N_("Usage: .set help | <name> [<value>]\n"));
1074 return GPG_ERR_SYNTAX
;
1077 p
+= strlen (namep
);
1078 while (p
&& *p
&& isspace (*p
))
1081 valuep
= parse_arg (p
, value
, sizeof (value
));
1083 if (!strcmp (name
, "keyfile") || !strcmp (name
, "new-keyfile"))
1085 int is_newkeyfile
= 1;
1087 if (!strcmp (name
, "keyfile"))
1092 pwmd_free (new_keyfile
);
1097 pwmd_free (keyfile
);
1101 p
+= strlen (valuep
);
1102 while (p
&& *p
&& isspace (*p
))
1105 valuep
= (char *) p
;
1109 new_keyfile
= pwmd_strdup (value
);
1111 keyfile
= pwmd_strdup (value
);
1115 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 1);
1117 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1120 else if (!local_pin
&& !no_pinentry
)
1124 pwmd_socket_type (pwm
, &t
);
1125 if (t
== PWMD_SOCKET_LOCAL
)
1127 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 0);
1129 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1133 else if (!strcmp(name
, "pinentry-timeout"))
1136 int n
= strtol(valuep
, &e
, 10);
1139 return gpg_error (GPG_ERR_INV_VALUE
);
1142 n
= DEFAULT_PIN_TIMEOUT
;
1144 rc
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, n
);
1146 else if (!strcmp (name
, "help"))
1150 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1151 "delimited. When no value is specified the option is unset.\n\n"
1152 "keyfile <datafile> [<filename>]\n"
1153 " set or unset the keyfile to be used when a passphrase is required (*)\n"
1155 "new-keyfile <datafile> [<filename>]\n"
1156 " set or unset the keyfile to be used when a new passphrase is required (*)\n"
1158 "pinentry-timeout <seconds>\n"
1159 " the amount of seconds before pinentry gives up waiting for input\n"
1161 "* = the next protocol command will unset this value\n"
1165 rc
= GPG_ERR_UNKNOWN_OPTION
;
1171 save_command (const char *line
)
1173 struct inquire_s
*inq
= NULL
;
1176 #ifdef HAVE_LIBREADLINE
1177 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1179 rc
= set_inquire (-1, NULL
, &inq
);
1184 if (new_keyfile
|| keyfile
)
1186 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1188 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 1);
1192 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1194 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
1198 rc
= pwmd_save (pwm
, line
, inquire_cb
, inq
);
1206 do_save_passwd_command (const char *line
, int save
)
1208 struct inquire_s
*inq
= NULL
;
1211 #ifdef HAVE_LIBREADLINE
1212 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1214 rc
= set_inquire (-1, NULL
, &inq
);
1219 if (new_keyfile
|| keyfile
)
1221 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1223 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 1);
1227 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1229 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
1235 rc
= pwmd_save (pwm
, line
, inquire_cb
, inq
);
1237 rc
= pwmd_passwd (pwm
, line
, inquire_cb
, inq
);
1246 parse_dotcommand (const char *line
, char **result
,
1247 size_t * len
, struct inquire_s
*inq
)
1249 const char *p
= line
;
1252 if (!strncmp (p
, ".read", 5))
1253 rc
= read_command (p
+ 5, result
, len
);
1254 else if (!strncmp (p
, ".redir", 6))
1255 rc
= redir_command (p
+ 6);
1256 else if (!strncmp (p
, ".help", 5))
1257 rc
= help_command (p
+ 5);
1258 else if (!strncmp (p
, ".open", 5))
1259 rc
= open_command (p
+ 5);
1260 else if (!strncmp (p
, ".set", 4))
1261 rc
= set_command (p
+ 4);
1262 else if (!strncmp (p
, ".save", 5))
1263 rc
= do_save_passwd_command (p
+ 5, 1);
1264 else if (!strncmp (p
, ".passwd", 7))
1265 rc
= do_save_passwd_command (p
+ 7, 0);
1268 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, "%s", line
);
1269 #ifdef HAVE_LIBREADLINE
1274 #ifdef HAVE_LIBREADLINE
1282 #ifdef HAVE_LIBREADLINE
1287 struct inquire_s
*inq
= NULL
;
1290 rc
= process_cmd ();
1294 rc
= set_inquire (STDIN_FILENO
, NULL
, &inq
);
1299 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1301 rl_event_hook
= &interactive_hook
;
1302 rl_set_keyboard_input_timeout (100000);
1307 char *result
= NULL
;
1311 line
= readline ("pwm> ");
1312 if (interactive_error
)
1315 rc
= interactive_error
;
1325 if (gpg_err_code (rc
) != GPG_ERR_CANCELED
&&
1326 gpg_err_code (rc
) != GPG_ERR_EOF
)
1327 fprintf (stderr
, "ERR %i: %s\n", rc
, gpg_strerror (rc
));
1337 #ifdef HAVE_READLINE_HISTORY
1340 rc
= parse_dotcommand (line
, &result
, &len
, inq
);
1346 if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
1347 (void) pwmd_command (pwm
, &tmp
, NULL
, NULL
, NULL
,
1348 "GETINFO last_error");
1350 show_error (pwm
, rc
, tmp
);
1353 else if (result
&& len
)
1354 printf ("%s%s", result
, result
[len
- 1] != '\n' ? "\n" : "");
1368 #ifdef HAVE_LIBREADLINE
1375 fprintf (stderr
, "\n");
1383 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1384 p
= fgets (buf
, sizeof (buf
), stdin
);
1398 return GPG_ERR_CANCELED
;
1402 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1403 "CLEARCACHE %s", filename
);
1407 interactive_hook ();
1423 if (save
&& !filename
)
1427 ("No filename was specified on the command line. Aborting.\n"));
1428 return GPG_ERR_CANCELED
;
1431 if (save
&& filename
)
1434 pwmd_strdup_printf ("%s%s %s%s %s",
1435 keyid
? "--keyid=" : "",
1437 sign_keyid
? "--sign-keyid=" : "",
1438 sign_keyid
? sign_keyid
: "",
1439 keyparams
? "--inquire-keyparam" : "");
1441 #ifdef HAVE_LIBREADLINE
1442 if (!quiet
|| interactive
)
1448 fprintf (stderr
, "\n");
1449 fprintf (stderr
, N_("Saving changes ...\n"));
1452 rc
= save_command (args
);
1456 #ifdef HAVE_LIBREADLINE
1458 return rc
? rc
: quit
? 0 : GPG_ERR_CANCELED
;
1465 parse_status_ignore (char *str
)
1470 for (p
= status_ignore
; p
&& *p
; p
++)
1473 pwmd_free (status_ignore
);
1474 status_ignore
= NULL
;
1478 while ((s
= strsep (&str
, ",")))
1480 p
= pwmd_realloc (status_ignore
, (n
+ 2) * sizeof (char *));
1481 p
[n
++] = pwmd_strdup (s
);
1488 main (int argc
, char *argv
[])
1493 char command
[ASSUAN_LINELENGTH
], *p
= NULL
;
1494 char *result
= NULL
;
1496 char *pinentry_path
= NULL
;
1497 char *display
= NULL
, *tty
= NULL
, *ttytype
= NULL
;
1498 char *lcctype
= NULL
, *lcmessages
= NULL
;
1499 int outfd
= STDOUT_FILENO
;
1500 FILE *outfp
= stdout
;
1501 FILE *inquirefp
= stdin
;
1502 int show_status
= 1;
1503 char *clientname
= "pwmc";
1504 char *inquire
= NULL
;
1505 char *inquire_line
= NULL
;
1508 int use_ssh_agent
= 1;
1509 char *knownhosts
= NULL
;
1510 char *identity
= NULL
;
1513 char *cacert
= NULL
;
1514 char *clientcert
= NULL
;
1515 char *clientkey
= NULL
;
1518 char *tls_fingerprint
= NULL
;
1520 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1521 pwmd_socket_t socktype
;
1522 long socket_timeout
= 300;
1523 int connect_timeout
= 120;
1525 int lock_on_open
= 1;
1526 long lock_timeout
= 50;
1529 /* The order is important. */
1532 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1533 OPT_SOCKET_TIMEOUT
, OPT_CONNECT_TIMEOUT
,
1536 OPT_USE_SSH_AGENT
, OPT_IDENTITY
, OPT_KNOWNHOSTS
,
1539 OPT_CACERT
, OPT_CLIENTCERT
, OPT_CLIENTKEY
, OPT_PRIORITY
, OPT_VERIFY
,
1542 OPT_URL
, OPT_LOCAL
, OPT_TTYNAME
, OPT_TTYTYPE
,
1543 OPT_DISPLAY
, OPT_LC_CTYPE
, OPT_LC_MESSAGES
, OPT_TIMEOUT
, OPT_TRIES
,
1544 OPT_PINENTRY
, OPT_KEYFILE
, OPT_NEW_KEYFILE
, OPT_NOLOCK
,
1545 OPT_LOCK_TIMEOUT
, OPT_SAVE
, OPT_OUTPUT_FD
, OPT_INQUIRE
,
1546 OPT_INQUIRE_FD
, OPT_INQUIRE_FILE
, OPT_INQUIRE_LINE
, OPT_NO_STATUS
,
1548 OPT_STATUSFD
, OPT_NAME
, OPT_VERSION
, OPT_HELP
, OPT_KEYID
, OPT_SIGN_KEYID
,
1549 OPT_KEYPARAMS
, OPT_NO_PINENTRY
, OPT_QUIET
,
1550 #ifdef HAVE_LIBREADLINE
1554 const struct option long_opts
[] = {
1555 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1556 {"socket-timeout", 1, 0, 0},
1557 {"connect-timeout", 1, 0, 0},
1561 {"no-ssh-agent", 0, 0, 0},
1562 {"identity", 1, 0, 'i'},
1563 {"knownhosts", 1, 0, 'k'},
1566 {"ca-cert", 1, 0, 0},
1567 {"client-cert", 1, 0, 0},
1568 {"client-key", 1, 0, 0},
1569 {"tls-priority", 1, 0, 0},
1570 {"tls-verify", 0, 0, 0},
1571 {"tls-fingerprint", 1, 0, 0},
1574 {"local-pinentry", 0, 0},
1575 {"ttyname", 1, 0, 'y'},
1576 {"ttytype", 1, 0, 't'},
1577 {"display", 1, 0, 'd'},
1578 {"lc-ctype", 1, 0, 0},
1579 {"lc-messages", 1, 0, 0},
1580 {"timeout", 1, 0, 0},
1582 {"pinentry", 1, 0, 0},
1583 {"key-file", 1, 0, 0},
1584 {"new-key-file", 1, 0, 0},
1585 {"no-lock", 0, 0, 0},
1586 {"lock-timeout", 1, 0, 0},
1587 {"save", 0, 0, 'S'},
1588 {"output-fd", 1, 0, 0},
1589 {"inquire", 1, 0, 0},
1590 {"inquire-fd", 1, 0, 0},
1591 {"inquire-file", 1, 0, 0},
1592 {"inquire-line", 1, 0, 'L'},
1593 {"no-status", 0, 0, 0},
1594 {"status-ignore", 1, 0, 0},
1595 {"status-fd", 1, 0, 0},
1596 {"name", 1, 0, 'n'},
1597 {"version", 0, 0, 0},
1600 {"sign-keyid", 1, 0, 0},
1601 {"key-params", 1, 0, 0},
1602 {"no-pinentry", 0, 0, 0},
1604 #ifdef HAVE_LIBREADLINE
1605 {"interactive", 0, 0},
1610 const char *optstring
= "L:y:t:d:P:I:Sn:i:k:";
1612 const char *optstring
= "L:y:t:d:P:I:Sn:";
1617 setlocale (LC_ALL
, "");
1618 bindtextdomain ("libpwmd", LOCALEDIR
);
1621 tries
= DEFAULT_PIN_TRIES
;
1622 inquirefd
= STDIN_FILENO
;
1623 statusfd
= STDERR_FILENO
;
1624 statusfp
= fdopen (statusfd
, "w");
1625 tmp
= pwmd_strdup (DEFAULT_STATUS_IGNORE
);
1626 parse_status_ignore (tmp
);
1630 getopt_long (argc
, argv
, optstring
, long_opts
, &opt_index
)) != -1)
1634 /* Handle long options without a short option part. */
1638 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1639 case OPT_SOCKET_TIMEOUT
:
1640 socket_timeout
= strtol (optarg
, &p
, 10);
1642 case OPT_CONNECT_TIMEOUT
:
1643 connect_timeout
= strtol (optarg
, &p
, 10);
1647 case OPT_USE_SSH_AGENT
:
1655 case OPT_CLIENTCERT
:
1656 clientcert
= optarg
;
1668 tls_fingerprint
= optarg
;
1675 keyfile
= pwmd_strdup (optarg
);
1677 case OPT_NEW_KEYFILE
:
1678 new_keyfile
= pwmd_strdup (optarg
);
1683 case OPT_LOCK_TIMEOUT
:
1684 lock_timeout
= strtol (optarg
, &p
, 10);
1693 lcctype
= pwmd_strdup (optarg
);
1695 case OPT_LC_MESSAGES
:
1696 lcmessages
= pwmd_strdup (optarg
);
1699 timeout
= strtol (optarg
, &p
, 10);
1702 tries
= strtol (optarg
, &p
, 10);
1705 inquire
= escape (optarg
);
1707 case OPT_INQUIRE_FD
:
1708 inquirefd
= strtol (optarg
, &p
, 10);
1711 inquirefp
= fdopen (inquirefd
, "r");
1713 err (EXIT_FAILURE
, "%i", inquirefd
);
1716 case OPT_INQUIRE_FILE
:
1717 inquirefd
= open (optarg
, O_RDONLY
);
1718 if (inquirefd
== -1)
1719 err (EXIT_FAILURE
, "%s", optarg
);
1720 inquirefp
= fdopen (inquirefd
, "r");
1723 outfd
= strtol (optarg
, &p
, 10);
1726 outfp
= fdopen (outfd
, "w");
1728 err (EXIT_FAILURE
, "%i", outfd
);
1735 statusfd
= strtol (optarg
, &p
, 10);
1738 statusfp
= fdopen (statusfd
, "w");
1740 err (EXIT_FAILURE
, "%i", statusfd
);
1743 case OPT_STATUS_IGNORE
:
1744 parse_status_ignore (optarg
);
1747 printf ("%s (pwmc)\n\n"
1748 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015\n"
1750 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1751 "Compile-time features:\n"
1752 #ifdef HAVE_LIBREADLINE
1767 #ifdef WITH_PINENTRY
1782 "\n", PACKAGE_STRING
, PACKAGE_BUGREPORT
);
1783 exit (EXIT_SUCCESS
);
1785 pinentry_path
= optarg
;
1788 usage (argv
[0], EXIT_SUCCESS
);
1792 case OPT_SIGN_KEYID
:
1793 sign_keyid
= optarg
;
1799 case OPT_NO_PINENTRY
:
1802 #ifdef HAVE_LIBREADLINE
1803 case OPT_INTERACTIVE
:
1808 usage (argv
[0], EXIT_FAILURE
);
1813 fprintf (stderr
, N_("%s: invalid argument for option '--%s'\n"),
1814 argv
[0], long_opts
[opt_index
].name
);
1815 usage (argv
[0], EXIT_FAILURE
);
1824 knownhosts
= optarg
;
1828 inquire_line
= optarg
;
1843 clientname
= optarg
;
1846 usage (argv
[0], EXIT_FAILURE
);
1850 #ifdef HAVE_LIBREADLINE
1851 if (interactive
&& !isatty (STDIN_FILENO
))
1852 usage (argv
[0], EXIT_FAILURE
);
1853 else if (isatty (STDIN_FILENO
) && !inquire
&& !inquire_line
)
1857 filename
= argv
[optind
];
1859 gnutls_global_set_mem_functions (pwmd_malloc
, pwmd_malloc
, NULL
,
1860 pwmd_realloc
, pwmd_free
);
1863 rc
= pwmd_new (clientname
, &pwm
);
1867 pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TRIES
, tries
);
1869 fprintf (stderr
, N_("Connecting ...\n"));
1871 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1872 socktype
= is_remote_url (url
);
1873 if (socktype
!= PWMD_SOCKET_LOCAL
)
1876 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1877 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, connect_timeout
);
1882 if (socktype
== PWMD_SOCKET_SSH
)
1885 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_CB
, knownhost_cb
);
1889 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_DATA
, clientname
);
1893 if (!getenv ("SSH_AUTH_SOCK") || identity
)
1896 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_AGENT
, use_ssh_agent
);
1900 rc
= pwmd_connect (pwm
, url
, identity
, knownhosts
);
1906 rc
= pwmd_setopt (pwm
, PWMD_OPTION_TLS_VERIFY
, tls_verify
);
1910 rc
= pwmd_connect (pwm
, url
, clientcert
, clientkey
, cacert
, prio
,
1916 rc
= pwmd_connect (pwm
, url
);
1918 rc
= pwmd_connect (pwm
, url
);
1924 fprintf (stderr
, N_("Connected.\n"));
1927 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1928 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, socket_timeout
);
1935 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1936 "OPTION LOCK-TIMEOUT=%li", lock_timeout
);
1943 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCK_ON_OPEN
, 1);
1948 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, NULL
, NULL
);
1954 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, timeout
);
1959 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
1963 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
,
1964 (local_pin
|| keyfile
|| new_keyfile
));
1970 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_PATH
, pinentry_path
);
1977 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DISPLAY
, display
);
1984 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TTY
, tty
);
1991 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TERM
, ttytype
);
1998 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_CTYPE
, lcctype
);
2005 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_MESSAGES
, lcmessages
);
2012 rc
= pwmd_setopt (pwm
, PWMD_OPTION_STATUS_CB
, status_msg_cb
);
2019 rc
= open_command (filename
);
2024 #ifdef HAVE_LIBREADLINE
2027 rc
= do_interactive ();
2035 struct inquire_s
*inq
= NULL
;
2037 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2039 rc
= pwmd_command (pwm
, &result
, &len
, inquire_cb
, inq
, "%s", inquire
);
2045 if (fcntl (STDIN_FILENO
, F_SETFL
, O_NONBLOCK
) == -1)
2047 rc
= gpg_error_from_errno (errno
);
2055 rc
= process_cmd ();
2060 n
= read (STDIN_FILENO
, command
, sizeof (command
)-1);
2063 if (errno
== EAGAIN
)
2069 rc
= gpg_error_from_errno (errno
);
2080 if (!p
|| !*p
|| !strcasecmp (p
, "BYE"))
2084 struct inquire_s
*inq
= NULL
;
2085 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2088 rc
= parse_dotcommand (command
, &result
, &len
, inq
);
2098 fwrite (result
, 1, result
[len
- 1] == 0 ? len
- 1 : len
, outfp
);
2106 else if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
2107 (void) pwmd_command (pwm
, &result
, NULL
, NULL
, NULL
,
2108 "GETINFO last_error");
2110 #ifdef HAVE_LIBREADLINE
2113 memset (command
, 0, sizeof (command
));
2116 show_error (pwm
, rc
, result
);
2122 parse_status_ignore (NULL
);
2123 if (connected
&& !quiet
)
2124 fprintf (stderr
, N_("Connection closed.\n"));
2126 exit (rc
? EXIT_FAILURE
: EXIT_SUCCESS
);