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");
140 usage (const char *pn
, int status
)
142 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
143 N_("Usage: pwmc [options] [file]\n"
145 " a url string to connect to (%s, see below)\n"
146 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
147 " --connect-timeout <seconds>\n"
148 " seconds before connecting to a remote host fails (0=disabled, 120)\n"
149 " --socket-timeout <seconds>\n"
150 " seconds before a remote command fails (0=disabled, 300)\n"
153 " --ca-cert <filename>\n"
154 " certificate authority (CA) used to sign the server cert\n"
155 " --client-cert <filename>\n"
156 " client certificate to use for authentication\n"
157 " --client-key <filename>\n"
158 " key file used to protect the client certificate\n"
159 " --tls-priority <string>\n"
160 " compression, cipher and hash algorithm string (SECURE256)\n"
162 " verify the hostname against the server certificate\n"
163 " --tls-fingerprint <string>\n"
164 " a SHA-256 hash of the server fingerprint to verify against\n"
168 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
169 " --identity, -i <filename>\n"
170 " the ssh identity file to use for authentication\n"
171 " --knownhosts, -k <filename>\n"
172 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
175 " do not lock the data file upon opening it\n"
176 " --lock-timeout <N>\n"
177 " time in tenths of a second to wait for a locked data file (50)\n"
178 " --name, -n <string>\n"
179 " set the client name\n"
180 " --pinentry <path>\n"
181 " the full path to the pinentry binary\n"
182 " --local-pinentry\n"
183 " force using a local pinentry\n"
185 " disable pinentry both remotely and locally\n"
186 " --ttyname, -y <path>\n"
187 " tty that pinentry will use\n"
188 " --ttytype, -t <string>\n"
189 " pinentry terminal type (default is $TERM)\n"
191 " pinentry display (default is $DISPLAY)\n"
192 " --lc-ctype <string>\n"
193 " locale setting for pinentry\n"
194 " --lc-messages <string>\n"
195 " locale setting for pinentry\n"
197 " number of pinentry tries before failing (3)\n"
198 " --timeout <seconds>\n"
199 " pinentry timeout\n"
200 " --inquire <COMMAND>\n"
201 " the specified command (with any options) uses a server inquire while\n"
202 " command data is read via the inquire file descriptor (stdin)\n"
203 " --inquire-line, -L <STRING>\n"
204 " the initial line to send (i.e., element path) before the inquire data\n"
205 " --inquire-fd <FD>\n"
206 " read inquire data from the specified file descriptor (stdin)\n"
207 " --inquire-file <filename>\n"
208 " read inquire data from the specified filename\n"
209 " --output-fd <FD>\n"
210 " redirect command output to the specified file descriptor\n"
212 " send the SAVE command before exiting\n"
213 " --key-file <filename>\n"
214 " obtain the passphrase from the specified filename\n"
215 " --new-key-file <filename>\n"
216 " obtain the passphrase to save with from the specified filename\n"
217 " --key-params <string>\n"
218 " the key parameters to use when saving a new file (pwmd default)\n"
219 " --keyid <recipient>[,<recipient>]\n"
220 " the public key ID to u\n"
221 " --sign-keyid <string>\n"
222 " the key ID to sign the data file with\n"
224 " disable showing of status messages from the server\n"
225 " --status-ignore <string[,...]>\n"
226 " prevent parsing of the specified status message keywords\n"
228 " disable showing of extra messages (implies --no-status)\n"
229 " --status-fd <FD>\n"
230 " redirect status messages to the specified file descriptor\n"
231 #ifdef HAVE_LIBREADLINE
233 " use a shell like interface to pwmd (allows more than one command)\n"
237 #ifdef DEFAULT_PWMD_SOCKET
243 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
245 "An optional url may be in the form of:\n"
246 " --url /path/to/socket\n"
247 " --url file://[path/to/socket]\n"
250 " --url ssh[46]://[username@]hostname[:port]\n"
251 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
255 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
256 " --client-key filename\n"
258 #ifdef HAVE_LIBREADLINE
260 "Interactive mode is used when input is from a terminal.\n"
267 inquire_cb (void *user
, const char *keyword
, gpg_error_t rc
,
268 char **data
, size_t * size
)
270 struct inquire_s
*inq
= user
;
272 int is_newpassword
= 0;
280 if (!strcmp (keyword
, "PASSPHRASE"))
282 else if (!strcmp (keyword
, "NEW_PASSPHRASE"))
284 #ifdef HAVE_LIBREADLINE
285 else if (!strcmp (keyword
, "KEYPARAM") && !interactive
)
288 else if (!strcmp (keyword
, "KEYPARAM"))
291 if (!keyparams
|| !*keyparams
)
292 return gpg_error (GPG_ERR_INV_PARAMETER
);
295 *size
= strlen (keyparams
);
296 return gpg_error (GPG_ERR_EOF
);
299 if ((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
))
301 int fd
= open (is_password
? keyfile
: new_keyfile
, O_RDONLY
);
305 fprintf (stderr
, "%s: %s\n", is_newpassword
? new_keyfile
: keyfile
,
307 return gpg_error_from_syserror ();
310 rc
= set_inquire (fd
, NULL
, &inq
);
318 fprintf (stderr
, N_("Using keyfile '%s' as %s.\n"),
319 is_newpassword
? new_keyfile
: keyfile
, keyword
);
321 if (!new_keyfile
|| is_newpassword
)
325 pwmd_socket_type (pwm
, &t
);
326 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
327 if (!no_pinentry
&& t
== PWMD_SOCKET_LOCAL
)
328 pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 0);
331 else if ((is_password
&& !keyfile
) || (is_newpassword
&& !new_keyfile
))
335 rc
= pwmd_password (pwm
, keyword
, &tmp
, &inq
->len
);
336 if (rc
&& gpg_err_code (rc
) != GPG_ERR_EOF
)
339 pwmd_free (inq
->line
);
343 return gpg_error (GPG_ERR_EOF
);
345 #ifdef HAVE_LIBREADLINE
346 else if ((!inq
->last_keyword
|| strcmp (keyword
, inq
->last_keyword
))
351 ("%sPress CTRL-D to send the current line. Press twice to end. %s:\n"),
352 inq
->last_keyword
? "\n" : "", keyword
);
353 pwmd_free (inq
->last_keyword
);
354 inq
->last_keyword
= pwmd_strdup (keyword
);
358 /* The first part of the command data. */
364 return inq
->fd
== -1 ? gpg_error (GPG_ERR_EOF
) : 0;
367 *size
= read (inq
->fd
, inq
->line
, ASSUAN_LINELENGTH
);
371 return gpg_error (gpg_error_from_syserror ());
375 else if (inq
->fd
!= STDIN_FILENO
&& (is_newpassword
|| is_password
))
383 if (((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
))
384 && *size
== inq
->size
)
385 return gpg_error (GPG_ERR_EOF
);
387 return *size
? 0 : gpg_error (GPG_ERR_EOF
);
391 status_msg_cb (void *data
, const char *line
)
393 char *p
= strchr (line
, ' ');
396 /* Ignore status messages specified by the client via --status-ignore. */
397 for (s
= status_ignore
; s
&& *s
; s
++)
399 char *tmp
= strchr (line
, ' ');
400 size_t len
= tmp
? strlen (line
) - strlen (tmp
) : strlen (line
);
402 if (!strncmp (line
, *s
, len
) && len
== strlen (*s
))
406 if (statusfd
!= STDERR_FILENO
&& strncmp (line
, "STATE ", 6) && *line
!= '#'
407 && p
&& strchr (p
, ' ') && *++p
)
409 char *p1
= strchr (p
, ' ');
410 int a
= strtol (p
, NULL
, 10);
412 if (isdigit (*p
) && p1
)
414 int b
= strtol (p1
, NULL
, 10);
416 int t
= a
&& b
? a
* 100 / b
: 0;
418 strncpy (l
, line
, strlen (line
) - strlen (p
) - 1);
419 fprintf (statusfp
, "\r%s %i/%i %i%%%s", l
, a
, b
, t
,
426 fprintf (statusfp
, "%s\n", line
);
428 #ifdef HAVE_LIBREADLINE
437 return pwmd_process (pwm
);
442 get_password (char **result
, pwmd_pinentry_t w
, int echo
)
444 char buf
[LINE_MAX
] = { 0 }, *p
;
445 struct termios told
, tnew
;
450 if (!isatty (STDIN_FILENO
))
452 fprintf (stderr
, N_("Input is not from a terminal! Failing.\n"));
453 return GPG_ERR_ENOTTY
;
458 if (tcgetattr (STDIN_FILENO
, &told
) == -1)
459 return gpg_error_from_syserror ();
461 memcpy (&tnew
, &told
, sizeof (struct termios
));
462 tnew
.c_lflag
&= ~(ECHO
);
463 tnew
.c_lflag
|= ICANON
| ECHONL
;
465 if (tcsetattr (STDIN_FILENO
, TCSANOW
, &tnew
) == -1)
469 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
470 return gpg_error_from_errno (n
);
476 case PWMD_PINENTRY_OPEN
:
477 fprintf (stderr
, N_("Password for %s: "), filename
);
479 case PWMD_PINENTRY_OPEN_FAILED
:
480 fprintf (stderr
, N_("Invalid password. Password for %s: "), filename
);
482 case PWMD_PINENTRY_SAVE
:
483 fprintf (stderr
, N_("New password for %s: "), filename
);
485 case PWMD_PINENTRY_SAVE_CONFIRM
:
486 fprintf (stderr
, N_("Confirm password: "));
492 if ((p
= fgets (buf
, sizeof (buf
), stdin
)) == NULL
)
494 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
499 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
504 return GPG_ERR_CANCELED
;
507 p
[strlen (p
) - 1] = 0;
511 key
= pwmd_strdup_printf ("%s", p
);
512 memset (&buf
, 0, sizeof (buf
));
515 return GPG_ERR_ENOMEM
;
523 knownhost_cb (void *data
, const char *host
, const char *key
, size_t len
)
527 pwmd_strdup_printf (N_
528 ("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?"),
529 (char *) data
, host
, host
);
531 if (no_pinentry
&& !isatty (STDIN_FILENO
))
533 fprintf (stderr
, N_("Input is not from a terminal! Failing.\n"));
535 return GPG_ERR_ENOTTY
;
537 else if (no_pinentry
)
539 for (char *p
= buf
, len
= 0; *p
; p
++, len
++)
548 while (!isspace (*(--p
)));
555 fprintf (stderr
, "%s\n\n", buf
);
562 fprintf (stderr
, N_("Trust this connection [y/N]: "));
564 rc
= get_password (&result
, PWMD_PINENTRY_CONFIRM
, 1);
569 if (!result
|| !*result
|| *result
== 'n' || *result
== 'N')
571 if (result
&& *result
)
574 return GPG_ERR_NOT_CONFIRMED
;
577 if ((*result
== 'y' || *result
== 'Y') && *(result
+ 1) == 0)
586 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, buf
);
592 return pwmd_getpin (pwm
, NULL
, NULL
, NULL
, PWMD_PINENTRY_CONFIRM
);
596 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
598 is_remote_url (const char *str
)
601 return PWMD_SOCKET_LOCAL
;
604 if (strstr (str
, "ssh://") || strstr (str
, "ssh4://")
605 || strstr (str
, "ssh6://"))
606 return PWMD_SOCKET_SSH
;
610 if (strstr (str
, "tls://") || strstr (str
, "tls4://")
611 || strstr (str
, "tls6://"))
612 return PWMD_SOCKET_TLS
;
615 return PWMD_SOCKET_LOCAL
;
620 escape (const char *str
)
623 char *buf
= pwmd_malloc (ASSUAN_LINELENGTH
+ 1), *b
= buf
;
626 for (p
= str
; *p
; p
++, len
++)
628 if (len
== ASSUAN_LINELENGTH
)
672 free_inquire (struct inquire_s
*inq
)
677 pwmd_free (inq
->line
);
679 if (inq
->fd
!= -1 && inq
->fd
!= STDIN_FILENO
)
682 pwmd_free (inq
->last_keyword
);
686 /* When *result is not NULL it is updated to the new values and not
689 set_inquire (int fd
, const char *line
, struct inquire_s
**result
)
691 struct inquire_s inq
= { 0 };
692 struct stat st
= { 0 };
697 if (fstat (fd
, &st
) == -1)
698 return gpg_error_from_syserror ();
700 inq
.size
= st
.st_size
;
704 inq
.line
= pwmd_calloc (1, ASSUAN_LINELENGTH
);
706 return GPG_ERR_ENOMEM
;
710 char *s
= escape (line
);
714 pwmd_free (inq
.line
);
715 return GPG_ERR_ENOMEM
;
718 if (strlen (s
) >= ASSUAN_LINELENGTH
)
720 pwmd_free (inq
.line
);
722 return GPG_ERR_LINE_TOO_LONG
;
725 strncpy (inq
.line
, s
, ASSUAN_LINELENGTH
- 1);
726 inq
.len
= strlen (s
);
730 rc
= pwmd_setopt (pwm
, PWMD_OPTION_INQUIRE_TOTAL
,
731 st
.st_size
? st
.st_size
+ strlen (inq
.line
) : 0);
734 pwmd_free (inq
.line
);
739 *result
= pwmd_malloc (sizeof (struct inquire_s
));
742 if ((*result
)->fd
!= -1 && (*result
)->fd
!= STDIN_FILENO
)
743 close ((*result
)->fd
);
745 pwmd_free ((*result
)->line
);
746 (*result
)->line
= NULL
;
751 memcpy (*result
, &inq
, sizeof (struct inquire_s
));
752 memset (&inq
, 0, sizeof (struct inquire_s
));
756 #ifdef HAVE_LIBREADLINE
758 interactive_hook (void)
760 interactive_error
= process_cmd ();
762 if (interactive_error
)
763 rl_event_hook
= NULL
;
773 ("------------------------------------------------------------------------------\n"
774 "Elements are TAB delimited. Press CTRL-V then TAB to insert from the prompt.\n"
776 "Type HELP for protocol commands. Type .help for pwmc commands. Press CTRL-D\n"
778 "------------------------------------------------------------------------------\n"));
783 parse_arg (const char *src
, char *dst
, size_t len
)
789 for (; s
&& *s
&& *s
!= ' ' && n
< len
; s
++, n
++)
797 parse_opt (char **line
, const char *opt
, gpg_error_t
* rc
)
799 static char result
[ASSUAN_LINELENGTH
] = { 0 }, *r
= result
;
800 char *s
= strstr (*line
, opt
);
810 size_t rlen
= strlen (opt
);
814 while (*p
&& *p
== ' ')
820 for (; *p
&& len
< sizeof (result
) - 1; p
++, rlen
++)
822 if (isspace (*p
) && !quote
)
825 if (*p
== '\"' && lastc
!= '\\')
838 if (len
>= sizeof (result
) - 1)
839 *rc
= GPG_ERR_LINE_TOO_LONG
;
844 while (*p
&& *p
== ' ')
855 read_command (const char *line
, char **result
, size_t * len
)
859 char *filename
= NULL
;
860 struct inquire_s
*inq
= NULL
;
861 char *p
= (char *) line
;
862 const char *prefix
= parse_opt (&p
, "--prefix", &rc
);
871 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
, 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
;
929 char filebuf
[ASSUAN_LINELENGTH
];
931 filename
= parse_arg (p
, filebuf
, sizeof (filebuf
));
932 if (filename
&& *filename
)
934 p
+= strlen (filename
) + 1;
936 while (*p
&& isspace (*p
))
946 fprintf (stderr
, N_("Usage: .redir <filename> <command> [args]\n"));
950 fd
= open (filename
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600);
952 return gpg_error_from_syserror ();
954 #ifdef HAVE_LIBREADLINE
955 rc
= set_inquire (interactive
? STDIN_FILENO
: inquirefd
, NULL
, &inq
);
957 rc
= set_inquire (inquirefd
, NULL
, &inq
);
965 rc
= parse_dotcommand (p
, &result
, &len
, inq
);
966 if (!rc
&& result
&& len
--)
967 { // null byte which is always appended
968 if (write (fd
, result
, len
) != len
)
969 rc
= GPG_ERR_TOO_SHORT
;
979 help_command (const char *line
)
982 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
983 " .redir <filename> <command>\n"
984 " redirect the output of a command to the specified file\n"
986 " .open <filename>\n"
987 " open the specified filename losing any changes to the current one\n"
989 " .read [--prefix <string>] <filename> <command> [args]\n"
990 " obtain data from the specified filename for an inquire command\n"
992 " .set help | <name> [<value>]\n"
993 " set option <name> to <value>\n"
996 " write changes of the file to disk\n"
999 " change the passphrase of a data file\n"
1002 " this help text\n"));
1007 open_command (const char *line
)
1009 struct inquire_s
*inq
= NULL
;
1010 const char *filename
= line
;
1013 while (filename
&& isspace (*filename
))
1016 if (!filename
|| !*filename
)
1018 fprintf (stderr
, N_("Usage: .open <filename>\n"));
1019 return GPG_ERR_SYNTAX
;
1022 #ifdef HAVE_LIBREADLINE
1023 if (interactive
|| !quiet
)
1027 fprintf (stderr
, N_("Opening data file \"%s\" ...\n"), filename
);
1029 #ifdef HAVE_LIBREADLINE
1030 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1032 rc
= set_inquire (-1, NULL
, &inq
);
1038 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1040 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1042 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
1043 rc
= pwmd_open (pwm
, filename
, inquire_cb
, inq
);
1049 set_command (const char *line
)
1052 char name
[256] = { 0 };
1053 char value
[512] = { 0 };
1056 const char *p
= line
;
1058 while (p
&& *p
&& isspace (*p
))
1061 namep
= parse_arg (p
, name
, sizeof (name
));
1062 if (!namep
|| !*namep
)
1064 fprintf (stderr
, N_("Usage: .set help | <name> [<value>]\n"));
1065 return GPG_ERR_SYNTAX
;
1068 p
+= strlen (namep
);
1069 while (p
&& *p
&& isspace (*p
))
1072 valuep
= parse_arg (p
, value
, sizeof (value
));
1074 if (!strcmp (name
, "keyfile") || !strcmp (name
, "new-keyfile"))
1076 int is_newkeyfile
= 1;
1078 if (!strcmp (name
, "keyfile"))
1083 pwmd_free (new_keyfile
);
1088 pwmd_free (keyfile
);
1092 p
+= strlen (valuep
);
1093 while (p
&& *p
&& isspace (*p
))
1096 valuep
= (char *) p
;
1100 new_keyfile
= pwmd_strdup (value
);
1102 keyfile
= pwmd_strdup (value
);
1106 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 1);
1108 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1111 else if (!local_pin
&& !no_pinentry
)
1115 pwmd_socket_type (pwm
, &t
);
1116 if (t
== PWMD_SOCKET_LOCAL
)
1118 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 0);
1120 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1124 else if (!strcmp(name
, "pinentry-timeout"))
1127 int n
= strtol(valuep
, &e
, 10);
1130 return gpg_error (GPG_ERR_INV_VALUE
);
1132 if (!valuep
|| !*valuep
)
1133 n
= DEFAULT_PIN_TIMEOUT
;
1135 rc
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, n
);
1137 else if (!strcmp (name
, "help"))
1141 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1142 "delimited. When no value is specified the option is unset.\n\n"
1143 "keyfile <datafile> [<filename>]\n"
1144 " set or unset the keyfile to be used when a passphrase is required (*)\n"
1146 "new-keyfile <datafile> [<filename>]\n"
1147 " set or unset the keyfile to be used when a new passphrase is required (*)\n"
1149 "pinentry-timeout <seconds>\n"
1150 " the amount of seconds before pinentry gives up waiting for input\n"
1152 "* = the next protocol command will unset this value\n"
1156 rc
= GPG_ERR_UNKNOWN_OPTION
;
1162 save_command (const char *line
)
1164 struct inquire_s
*inq
= NULL
;
1167 #ifdef HAVE_LIBREADLINE
1168 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1170 rc
= set_inquire (-1, NULL
, &inq
);
1175 if (new_keyfile
|| keyfile
)
1176 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1178 rc
= pwmd_save (pwm
, line
, inquire_cb
, inq
);
1179 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1185 do_save_passwd_command (const char *line
, int save
)
1187 struct inquire_s
*inq
= NULL
;
1190 #ifdef HAVE_LIBREADLINE
1191 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1193 rc
= set_inquire (-1, NULL
, &inq
);
1198 if (new_keyfile
|| keyfile
)
1199 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1202 rc
= pwmd_save (pwm
, line
, inquire_cb
, inq
);
1204 rc
= pwmd_passwd (pwm
, line
, inquire_cb
, inq
);
1206 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1212 parse_dotcommand (const char *line
, char **result
,
1213 size_t * len
, struct inquire_s
*inq
)
1215 const char *p
= line
;
1218 if (!strncmp (p
, ".read", 5))
1219 rc
= read_command (p
+ 5, result
, len
);
1220 else if (!strncmp (p
, ".redir", 6))
1221 rc
= redir_command (p
+ 6);
1222 else if (!strncmp (p
, ".help", 5))
1223 rc
= help_command (p
+ 5);
1224 else if (!strncmp (p
, ".open", 5))
1225 rc
= open_command (p
+ 5);
1226 else if (!strncmp (p
, ".set", 4))
1227 rc
= set_command (p
+ 4);
1228 else if (!strncmp (p
, ".save", 5))
1229 rc
= do_save_passwd_command (p
+ 5, 1);
1230 else if (!strncmp (p
, ".passwd", 7))
1231 rc
= do_save_passwd_command (p
+ 7, 0);
1234 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, line
);
1235 #ifdef HAVE_LIBREADLINE
1239 pwmd_free (keyfile
);
1240 pwmd_free (new_keyfile
);
1241 keyfile
= new_keyfile
= NULL
;
1242 #ifdef HAVE_LIBREADLINE
1250 #ifdef HAVE_LIBREADLINE
1255 struct inquire_s
*inq
= NULL
;
1258 rc
= process_cmd ();
1262 rc
= set_inquire (STDIN_FILENO
, NULL
, &inq
);
1267 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1269 rl_event_hook
= &interactive_hook
;
1270 rl_set_keyboard_input_timeout (100000);
1275 char *result
= NULL
;
1279 line
= readline ("pwm> ");
1280 if (interactive_error
)
1283 rc
= interactive_error
;
1293 if (gpg_err_code (rc
) != GPG_ERR_CANCELED
&&
1294 gpg_err_code (rc
) != GPG_ERR_EOF
)
1295 fprintf (stderr
, "ERR %i: %s\n", rc
, gpg_strerror (rc
));
1305 #ifdef HAVE_READLINE_HISTORY
1308 rc
= parse_dotcommand (line
, &result
, &len
, inq
);
1314 if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
1315 (void) pwmd_command (pwm
, &tmp
, NULL
, NULL
, NULL
,
1316 "GETINFO last_error");
1318 show_error (pwm
, rc
, tmp
);
1321 else if (result
&& len
)
1322 printf ("%s%s", result
, result
[len
- 1] != '\n' ? "\n" : "");
1336 #ifdef HAVE_LIBREADLINE
1343 fprintf (stderr
, "\n");
1351 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1352 p
= fgets (buf
, sizeof (buf
), stdin
);
1366 return GPG_ERR_CANCELED
;
1370 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1371 "CLEARCACHE %s", filename
);
1375 interactive_hook ();
1391 if (save
&& !filename
)
1395 ("No filename was specified on the command line. Aborting.\n"));
1396 return GPG_ERR_CANCELED
;
1399 if (save
&& filename
)
1402 pwmd_strdup_printf ("%s%s %s%s %s",
1403 keyid
? "--keyid=" : "",
1405 sign_keyid
? "--sign-keyid=" : "",
1406 sign_keyid
? sign_keyid
: "",
1407 keyparams
? "--inquire-keyparam" : "");
1409 #ifdef HAVE_LIBREADLINE
1410 if (!quiet
|| interactive
)
1416 fprintf (stderr
, "\n");
1417 fprintf (stderr
, N_("Saving changes ...\n"));
1420 rc
= save_command (args
);
1424 #ifdef HAVE_LIBREADLINE
1426 return rc
? rc
: quit
? 0 : GPG_ERR_CANCELED
;
1433 parse_status_ignore (char *str
)
1438 for (p
= status_ignore
; p
&& *p
; p
++)
1441 pwmd_free (status_ignore
);
1442 status_ignore
= NULL
;
1446 while ((s
= strsep (&str
, ",")))
1448 p
= pwmd_realloc (status_ignore
, (n
+ 2) * sizeof (char **));
1449 p
[n
++] = pwmd_strdup (s
);
1456 main (int argc
, char *argv
[])
1461 char command
[ASSUAN_LINELENGTH
], *p
= NULL
;
1462 char *result
= NULL
;
1464 char *pinentry_path
= NULL
;
1465 char *display
= NULL
, *tty
= NULL
, *ttytype
= NULL
;
1466 char *lcctype
= NULL
, *lcmessages
= NULL
;
1467 int outfd
= STDOUT_FILENO
;
1468 FILE *outfp
= stdout
;
1469 FILE *inquirefp
= stdin
;
1470 int show_status
= 1;
1471 char *clientname
= "pwmc";
1472 char *inquire
= NULL
;
1473 char *inquire_line
= NULL
;
1476 int use_ssh_agent
= 1;
1477 char *knownhosts
= NULL
;
1478 char *identity
= NULL
;
1481 char *cacert
= NULL
;
1482 char *clientcert
= NULL
;
1483 char *clientkey
= NULL
;
1486 char *tls_fingerprint
= NULL
;
1488 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1489 pwmd_socket_t socktype
;
1490 long socket_timeout
= 300;
1491 int connect_timeout
= 120;
1493 int lock_on_open
= 1;
1494 long lock_timeout
= 50;
1497 /* The order is important. */
1500 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1501 OPT_SOCKET_TIMEOUT
, OPT_CONNECT_TIMEOUT
,
1504 OPT_USE_SSH_AGENT
, OPT_IDENTITY
, OPT_KNOWNHOSTS
,
1507 OPT_CACERT
, OPT_CLIENTCERT
, OPT_CLIENTKEY
, OPT_PRIORITY
, OPT_VERIFY
,
1510 OPT_URL
, OPT_LOCAL
, OPT_TTYNAME
, OPT_TTYTYPE
,
1511 OPT_DISPLAY
, OPT_LC_CTYPE
, OPT_LC_MESSAGES
, OPT_TIMEOUT
, OPT_TRIES
,
1512 OPT_PINENTRY
, OPT_KEYFILE
, OPT_NEW_KEYFILE
, OPT_NOLOCK
,
1513 OPT_LOCK_TIMEOUT
, OPT_SAVE
, OPT_OUTPUT_FD
, OPT_INQUIRE
,
1514 OPT_INQUIRE_FD
, OPT_INQUIRE_FILE
, OPT_INQUIRE_LINE
, OPT_NO_STATUS
,
1516 OPT_STATUSFD
, OPT_NAME
, OPT_VERSION
, OPT_HELP
, OPT_KEYID
, OPT_SIGN_KEYID
,
1517 OPT_KEYPARAMS
, OPT_NO_PINENTRY
, OPT_QUIET
,
1518 #ifdef HAVE_LIBREADLINE
1522 const struct option long_opts
[] = {
1523 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1524 {"socket-timeout", 1, 0, 0},
1525 {"connect-timeout", 1, 0, 0},
1529 {"no-ssh-agent", 0, 0, 0},
1530 {"identity", 1, 0, 'i'},
1531 {"knownhosts", 1, 0, 'k'},
1534 {"ca-cert", 1, 0, 0},
1535 {"client-cert", 1, 0, 0},
1536 {"client-key", 1, 0, 0},
1537 {"tls-priority", 1, 0, 0},
1538 {"tls-verify", 0, 0, 0},
1539 {"tls-fingerprint", 1, 0, 0},
1542 {"local-pinentry", 0, 0},
1543 {"ttyname", 1, 0, 'y'},
1544 {"ttytype", 1, 0, 't'},
1545 {"display", 1, 0, 'd'},
1546 {"lc-ctype", 1, 0, 0},
1547 {"lc-messages", 1, 0, 0},
1548 {"timeout", 1, 0, 0},
1550 {"pinentry", 1, 0, 0},
1551 {"key-file", 1, 0, 0},
1552 {"new-key-file", 1, 0, 0},
1553 {"no-lock", 0, 0, 0},
1554 {"lock-timeout", 1, 0, 0},
1555 {"save", 0, 0, 'S'},
1556 {"output-fd", 1, 0, 0},
1557 {"inquire", 1, 0, 0},
1558 {"inquire-fd", 1, 0, 0},
1559 {"inquire-file", 1, 0, 0},
1560 {"inquire-line", 1, 0, 'L'},
1561 {"no-status", 0, 0, 0},
1562 {"status-ignore", 1, 0, 0},
1563 {"status-fd", 1, 0, 0},
1564 {"name", 1, 0, 'n'},
1565 {"version", 0, 0, 0},
1568 {"sign-keyid", 1, 0, 0},
1569 {"key-params", 1, 0, 0},
1570 {"no-pinentry", 0, 0, 0},
1572 #ifdef HAVE_LIBREADLINE
1573 {"interactive", 0, 0},
1578 const char *optstring
= "L:y:t:d:P:I:Sn:i:k:";
1580 const char *optstring
= "L:y:t:d:P:I:Sn:";
1585 setlocale (LC_ALL
, "");
1586 bindtextdomain ("libpwmd", LOCALEDIR
);
1589 tries
= DEFAULT_PIN_TRIES
;
1590 inquirefd
= STDIN_FILENO
;
1591 statusfd
= STDERR_FILENO
;
1592 statusfp
= fdopen (statusfd
, "w");
1593 tmp
= pwmd_strdup (DEFAULT_STATUS_IGNORE
);
1594 parse_status_ignore (tmp
);
1598 getopt_long (argc
, argv
, optstring
, long_opts
, &opt_index
)) != -1)
1602 /* Handle long options without a short option part. */
1606 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1607 case OPT_SOCKET_TIMEOUT
:
1608 socket_timeout
= strtol (optarg
, &p
, 10);
1610 case OPT_CONNECT_TIMEOUT
:
1611 connect_timeout
= strtol (optarg
, &p
, 10);
1615 case OPT_USE_SSH_AGENT
:
1623 case OPT_CLIENTCERT
:
1624 clientcert
= optarg
;
1636 tls_fingerprint
= optarg
;
1643 keyfile
= pwmd_strdup (optarg
);
1645 case OPT_NEW_KEYFILE
:
1646 new_keyfile
= pwmd_strdup (optarg
);
1651 case OPT_LOCK_TIMEOUT
:
1652 lock_timeout
= strtol (optarg
, &p
, 10);
1661 lcctype
= pwmd_strdup (optarg
);
1663 case OPT_LC_MESSAGES
:
1664 lcmessages
= pwmd_strdup (optarg
);
1667 timeout
= strtol (optarg
, &p
, 10);
1670 tries
= strtol (optarg
, &p
, 10);
1673 inquire
= escape (optarg
);
1675 case OPT_INQUIRE_FD
:
1676 inquirefd
= strtol (optarg
, &p
, 10);
1679 inquirefp
= fdopen (inquirefd
, "r");
1681 err (EXIT_FAILURE
, "%i", inquirefd
);
1684 case OPT_INQUIRE_FILE
:
1685 inquirefd
= open (optarg
, O_RDONLY
);
1686 if (inquirefd
== -1)
1687 err (EXIT_FAILURE
, "%s", optarg
);
1688 inquirefp
= fdopen (inquirefd
, "r");
1691 outfd
= strtol (optarg
, &p
, 10);
1694 outfp
= fdopen (outfd
, "w");
1696 err (EXIT_FAILURE
, "%i", outfd
);
1703 statusfd
= strtol (optarg
, &p
, 10);
1706 statusfp
= fdopen (statusfd
, "w");
1708 err (EXIT_FAILURE
, "%i", statusfd
);
1711 case OPT_STATUS_IGNORE
:
1712 parse_status_ignore (optarg
);
1715 printf ("%s (pwmc)\n\n"
1716 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015\n"
1718 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1719 "Compile-time features:\n"
1720 #ifdef HAVE_LIBREADLINE
1735 #ifdef WITH_PINENTRY
1750 "\n", PACKAGE_STRING
, PACKAGE_BUGREPORT
);
1751 exit (EXIT_SUCCESS
);
1753 pinentry_path
= optarg
;
1756 usage (argv
[0], EXIT_SUCCESS
);
1760 case OPT_SIGN_KEYID
:
1761 sign_keyid
= optarg
;
1767 case OPT_NO_PINENTRY
:
1770 #ifdef HAVE_LIBREADLINE
1771 case OPT_INTERACTIVE
:
1776 usage (argv
[0], EXIT_FAILURE
);
1781 fprintf (stderr
, N_("%s: invalid argument for option '--%s'\n"),
1782 argv
[0], long_opts
[opt_index
].name
);
1783 usage (argv
[0], EXIT_FAILURE
);
1792 knownhosts
= optarg
;
1796 inquire_line
= optarg
;
1811 clientname
= optarg
;
1814 usage (argv
[0], EXIT_FAILURE
);
1818 #ifdef HAVE_LIBREADLINE
1819 if (interactive
&& !isatty (STDIN_FILENO
))
1820 usage (argv
[0], EXIT_FAILURE
);
1821 else if (isatty (STDIN_FILENO
) && !inquire
&& !inquire_line
)
1825 filename
= argv
[optind
];
1827 gnutls_global_set_mem_functions (pwmd_malloc
, pwmd_malloc
, NULL
,
1828 pwmd_realloc
, pwmd_free
);
1831 rc
= pwmd_new (clientname
, &pwm
);
1835 pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TRIES
, tries
);
1837 fprintf (stderr
, N_("Connecting ...\n"));
1839 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1840 socktype
= is_remote_url (url
);
1841 if (socktype
!= PWMD_SOCKET_LOCAL
)
1844 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1845 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, connect_timeout
);
1850 if (socktype
== PWMD_SOCKET_SSH
)
1853 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_CB
, knownhost_cb
);
1857 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_DATA
, clientname
);
1861 if (!getenv ("SSH_AUTH_SOCK") || identity
)
1864 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_AGENT
, use_ssh_agent
);
1868 rc
= pwmd_connect (pwm
, url
, identity
, knownhosts
);
1874 rc
= pwmd_setopt (pwm
, PWMD_OPTION_TLS_VERIFY
, tls_verify
);
1878 rc
= pwmd_connect (pwm
, url
, clientcert
, clientkey
, cacert
, prio
,
1884 rc
= pwmd_connect (pwm
, url
);
1886 rc
= pwmd_connect (pwm
, url
);
1892 fprintf (stderr
, N_("Connected.\n"));
1895 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1896 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, socket_timeout
);
1903 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1904 "OPTION LOCK-TIMEOUT=%li", lock_timeout
);
1911 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCK_ON_OPEN
, 1);
1916 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, NULL
, NULL
);
1922 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, timeout
);
1927 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
1931 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
,
1932 (local_pin
|| keyfile
|| new_keyfile
));
1938 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_PATH
, pinentry_path
);
1945 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DISPLAY
, display
);
1952 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TTY
, tty
);
1959 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TERM
, ttytype
);
1966 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_CTYPE
, lcctype
);
1973 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_MESSAGES
, lcmessages
);
1980 rc
= pwmd_setopt (pwm
, PWMD_OPTION_STATUS_CB
, status_msg_cb
);
1987 rc
= open_command (filename
);
1992 #ifdef HAVE_LIBREADLINE
1995 rc
= do_interactive ();
2003 struct inquire_s
*inq
= NULL
;
2005 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2007 rc
= pwmd_command (pwm
, &result
, &len
, inquire_cb
, inq
, inquire
);
2013 fcntl (STDIN_FILENO
, F_SETFL
, O_NONBLOCK
);
2018 rc
= process_cmd ();
2023 n
= read (STDIN_FILENO
, command
, sizeof (command
));
2026 if (errno
== EAGAIN
)
2032 rc
= gpg_error_from_errno (errno
);
2043 if (!p
|| !*p
|| !strcasecmp (p
, "BYE"))
2047 struct inquire_s
*inq
= NULL
;
2048 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2051 rc
= parse_dotcommand (command
, &result
, &len
, inq
);
2061 fwrite (result
, 1, result
[len
- 1] == 0 ? len
- 1 : len
, outfp
);
2069 else if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
2070 (void) pwmd_command (pwm
, &result
, NULL
, NULL
, NULL
,
2071 "GETINFO last_error");
2073 #ifdef HAVE_LIBREADLINE
2076 memset (command
, 0, sizeof (command
));
2079 show_error (pwm
, rc
, result
);
2082 pwmd_free (keyfile
);
2083 pwmd_free (new_keyfile
);
2086 parse_status_ignore (NULL
);
2087 if (connected
&& !quiet
)
2088 fprintf (stderr
, N_("Connection closed.\n"));
2090 exit (rc
? EXIT_FAILURE
: EXIT_SUCCESS
);