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
;
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
);
1037 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1039 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1041 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
1042 rc
= pwmd_open (pwm
, filename
, inquire_cb
, inq
);
1048 set_command (const char *line
)
1051 char name
[256] = { 0 };
1052 char value
[512] = { 0 };
1055 const char *p
= line
;
1057 while (p
&& *p
&& isspace (*p
))
1060 namep
= parse_arg (p
, name
, sizeof (name
));
1061 if (!namep
|| !*namep
)
1063 fprintf (stderr
, N_("Usage: .set help | <name> [<value>]\n"));
1064 return GPG_ERR_SYNTAX
;
1067 p
+= strlen (namep
);
1068 while (p
&& *p
&& isspace (*p
))
1071 valuep
= parse_arg (p
, value
, sizeof (value
));
1073 if (!strcmp (name
, "keyfile") || !strcmp (name
, "new-keyfile"))
1075 int is_newkeyfile
= 1;
1077 if (!strcmp (name
, "keyfile"))
1082 pwmd_free (new_keyfile
);
1087 pwmd_free (keyfile
);
1091 p
+= strlen (valuep
);
1092 while (p
&& *p
&& isspace (*p
))
1095 valuep
= (char *) p
;
1099 new_keyfile
= pwmd_strdup (value
);
1101 keyfile
= pwmd_strdup (value
);
1105 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 1);
1107 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1110 else if (!local_pin
&& !no_pinentry
)
1114 pwmd_socket_type (pwm
, &t
);
1115 if (t
== PWMD_SOCKET_LOCAL
)
1117 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 0);
1119 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1123 else if (!strcmp(name
, "pinentry-timeout"))
1126 int n
= strtol(valuep
, &e
, 10);
1129 return gpg_error (GPG_ERR_INV_VALUE
);
1132 n
= DEFAULT_PIN_TIMEOUT
;
1134 rc
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, n
);
1136 else if (!strcmp (name
, "help"))
1140 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1141 "delimited. When no value is specified the option is unset.\n\n"
1142 "keyfile <datafile> [<filename>]\n"
1143 " set or unset the keyfile to be used when a passphrase is required (*)\n"
1145 "new-keyfile <datafile> [<filename>]\n"
1146 " set or unset the keyfile to be used when a new passphrase is required (*)\n"
1148 "pinentry-timeout <seconds>\n"
1149 " the amount of seconds before pinentry gives up waiting for input\n"
1151 "* = the next protocol command will unset this value\n"
1155 rc
= GPG_ERR_UNKNOWN_OPTION
;
1161 save_command (const char *line
)
1163 struct inquire_s
*inq
= NULL
;
1166 #ifdef HAVE_LIBREADLINE
1167 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1169 rc
= set_inquire (-1, NULL
, &inq
);
1174 if (new_keyfile
|| keyfile
)
1175 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1177 rc
= pwmd_save (pwm
, line
, inquire_cb
, inq
);
1178 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1184 do_save_passwd_command (const char *line
, int save
)
1186 struct inquire_s
*inq
= NULL
;
1189 #ifdef HAVE_LIBREADLINE
1190 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1192 rc
= set_inquire (-1, NULL
, &inq
);
1197 if (new_keyfile
|| keyfile
)
1198 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1201 rc
= pwmd_save (pwm
, line
, inquire_cb
, inq
);
1203 rc
= pwmd_passwd (pwm
, line
, inquire_cb
, inq
);
1205 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1211 parse_dotcommand (const char *line
, char **result
,
1212 size_t * len
, struct inquire_s
*inq
)
1214 const char *p
= line
;
1217 if (!strncmp (p
, ".read", 5))
1218 rc
= read_command (p
+ 5, result
, len
);
1219 else if (!strncmp (p
, ".redir", 6))
1220 rc
= redir_command (p
+ 6);
1221 else if (!strncmp (p
, ".help", 5))
1222 rc
= help_command (p
+ 5);
1223 else if (!strncmp (p
, ".open", 5))
1224 rc
= open_command (p
+ 5);
1225 else if (!strncmp (p
, ".set", 4))
1226 rc
= set_command (p
+ 4);
1227 else if (!strncmp (p
, ".save", 5))
1228 rc
= do_save_passwd_command (p
+ 5, 1);
1229 else if (!strncmp (p
, ".passwd", 7))
1230 rc
= do_save_passwd_command (p
+ 7, 0);
1233 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, "%s", line
);
1234 #ifdef HAVE_LIBREADLINE
1238 pwmd_free (keyfile
);
1239 pwmd_free (new_keyfile
);
1240 keyfile
= new_keyfile
= NULL
;
1241 #ifdef HAVE_LIBREADLINE
1249 #ifdef HAVE_LIBREADLINE
1254 struct inquire_s
*inq
= NULL
;
1257 rc
= process_cmd ();
1261 rc
= set_inquire (STDIN_FILENO
, NULL
, &inq
);
1266 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1268 rl_event_hook
= &interactive_hook
;
1269 rl_set_keyboard_input_timeout (100000);
1274 char *result
= NULL
;
1278 line
= readline ("pwm> ");
1279 if (interactive_error
)
1282 rc
= interactive_error
;
1292 if (gpg_err_code (rc
) != GPG_ERR_CANCELED
&&
1293 gpg_err_code (rc
) != GPG_ERR_EOF
)
1294 fprintf (stderr
, "ERR %i: %s\n", rc
, gpg_strerror (rc
));
1304 #ifdef HAVE_READLINE_HISTORY
1307 rc
= parse_dotcommand (line
, &result
, &len
, inq
);
1313 if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
1314 (void) pwmd_command (pwm
, &tmp
, NULL
, NULL
, NULL
,
1315 "GETINFO last_error");
1317 show_error (pwm
, rc
, tmp
);
1320 else if (result
&& len
)
1321 printf ("%s%s", result
, result
[len
- 1] != '\n' ? "\n" : "");
1335 #ifdef HAVE_LIBREADLINE
1342 fprintf (stderr
, "\n");
1350 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1351 p
= fgets (buf
, sizeof (buf
), stdin
);
1365 return GPG_ERR_CANCELED
;
1369 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1370 "CLEARCACHE %s", filename
);
1374 interactive_hook ();
1390 if (save
&& !filename
)
1394 ("No filename was specified on the command line. Aborting.\n"));
1395 return GPG_ERR_CANCELED
;
1398 if (save
&& filename
)
1401 pwmd_strdup_printf ("%s%s %s%s %s",
1402 keyid
? "--keyid=" : "",
1404 sign_keyid
? "--sign-keyid=" : "",
1405 sign_keyid
? sign_keyid
: "",
1406 keyparams
? "--inquire-keyparam" : "");
1408 #ifdef HAVE_LIBREADLINE
1409 if (!quiet
|| interactive
)
1415 fprintf (stderr
, "\n");
1416 fprintf (stderr
, N_("Saving changes ...\n"));
1419 rc
= save_command (args
);
1423 #ifdef HAVE_LIBREADLINE
1425 return rc
? rc
: quit
? 0 : GPG_ERR_CANCELED
;
1432 parse_status_ignore (char *str
)
1437 for (p
= status_ignore
; p
&& *p
; p
++)
1440 pwmd_free (status_ignore
);
1441 status_ignore
= NULL
;
1445 while ((s
= strsep (&str
, ",")))
1447 p
= pwmd_realloc (status_ignore
, (n
+ 2) * sizeof (char **));
1448 p
[n
++] = pwmd_strdup (s
);
1455 main (int argc
, char *argv
[])
1460 char command
[ASSUAN_LINELENGTH
], *p
= NULL
;
1461 char *result
= NULL
;
1463 char *pinentry_path
= NULL
;
1464 char *display
= NULL
, *tty
= NULL
, *ttytype
= NULL
;
1465 char *lcctype
= NULL
, *lcmessages
= NULL
;
1466 int outfd
= STDOUT_FILENO
;
1467 FILE *outfp
= stdout
;
1468 FILE *inquirefp
= stdin
;
1469 int show_status
= 1;
1470 char *clientname
= "pwmc";
1471 char *inquire
= NULL
;
1472 char *inquire_line
= NULL
;
1475 int use_ssh_agent
= 1;
1476 char *knownhosts
= NULL
;
1477 char *identity
= NULL
;
1480 char *cacert
= NULL
;
1481 char *clientcert
= NULL
;
1482 char *clientkey
= NULL
;
1485 char *tls_fingerprint
= NULL
;
1487 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1488 pwmd_socket_t socktype
;
1489 long socket_timeout
= 300;
1490 int connect_timeout
= 120;
1492 int lock_on_open
= 1;
1493 long lock_timeout
= 50;
1496 /* The order is important. */
1499 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1500 OPT_SOCKET_TIMEOUT
, OPT_CONNECT_TIMEOUT
,
1503 OPT_USE_SSH_AGENT
, OPT_IDENTITY
, OPT_KNOWNHOSTS
,
1506 OPT_CACERT
, OPT_CLIENTCERT
, OPT_CLIENTKEY
, OPT_PRIORITY
, OPT_VERIFY
,
1509 OPT_URL
, OPT_LOCAL
, OPT_TTYNAME
, OPT_TTYTYPE
,
1510 OPT_DISPLAY
, OPT_LC_CTYPE
, OPT_LC_MESSAGES
, OPT_TIMEOUT
, OPT_TRIES
,
1511 OPT_PINENTRY
, OPT_KEYFILE
, OPT_NEW_KEYFILE
, OPT_NOLOCK
,
1512 OPT_LOCK_TIMEOUT
, OPT_SAVE
, OPT_OUTPUT_FD
, OPT_INQUIRE
,
1513 OPT_INQUIRE_FD
, OPT_INQUIRE_FILE
, OPT_INQUIRE_LINE
, OPT_NO_STATUS
,
1515 OPT_STATUSFD
, OPT_NAME
, OPT_VERSION
, OPT_HELP
, OPT_KEYID
, OPT_SIGN_KEYID
,
1516 OPT_KEYPARAMS
, OPT_NO_PINENTRY
, OPT_QUIET
,
1517 #ifdef HAVE_LIBREADLINE
1521 const struct option long_opts
[] = {
1522 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1523 {"socket-timeout", 1, 0, 0},
1524 {"connect-timeout", 1, 0, 0},
1528 {"no-ssh-agent", 0, 0, 0},
1529 {"identity", 1, 0, 'i'},
1530 {"knownhosts", 1, 0, 'k'},
1533 {"ca-cert", 1, 0, 0},
1534 {"client-cert", 1, 0, 0},
1535 {"client-key", 1, 0, 0},
1536 {"tls-priority", 1, 0, 0},
1537 {"tls-verify", 0, 0, 0},
1538 {"tls-fingerprint", 1, 0, 0},
1541 {"local-pinentry", 0, 0},
1542 {"ttyname", 1, 0, 'y'},
1543 {"ttytype", 1, 0, 't'},
1544 {"display", 1, 0, 'd'},
1545 {"lc-ctype", 1, 0, 0},
1546 {"lc-messages", 1, 0, 0},
1547 {"timeout", 1, 0, 0},
1549 {"pinentry", 1, 0, 0},
1550 {"key-file", 1, 0, 0},
1551 {"new-key-file", 1, 0, 0},
1552 {"no-lock", 0, 0, 0},
1553 {"lock-timeout", 1, 0, 0},
1554 {"save", 0, 0, 'S'},
1555 {"output-fd", 1, 0, 0},
1556 {"inquire", 1, 0, 0},
1557 {"inquire-fd", 1, 0, 0},
1558 {"inquire-file", 1, 0, 0},
1559 {"inquire-line", 1, 0, 'L'},
1560 {"no-status", 0, 0, 0},
1561 {"status-ignore", 1, 0, 0},
1562 {"status-fd", 1, 0, 0},
1563 {"name", 1, 0, 'n'},
1564 {"version", 0, 0, 0},
1567 {"sign-keyid", 1, 0, 0},
1568 {"key-params", 1, 0, 0},
1569 {"no-pinentry", 0, 0, 0},
1571 #ifdef HAVE_LIBREADLINE
1572 {"interactive", 0, 0},
1577 const char *optstring
= "L:y:t:d:P:I:Sn:i:k:";
1579 const char *optstring
= "L:y:t:d:P:I:Sn:";
1584 setlocale (LC_ALL
, "");
1585 bindtextdomain ("libpwmd", LOCALEDIR
);
1588 tries
= DEFAULT_PIN_TRIES
;
1589 inquirefd
= STDIN_FILENO
;
1590 statusfd
= STDERR_FILENO
;
1591 statusfp
= fdopen (statusfd
, "w");
1592 tmp
= pwmd_strdup (DEFAULT_STATUS_IGNORE
);
1593 parse_status_ignore (tmp
);
1597 getopt_long (argc
, argv
, optstring
, long_opts
, &opt_index
)) != -1)
1601 /* Handle long options without a short option part. */
1605 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1606 case OPT_SOCKET_TIMEOUT
:
1607 socket_timeout
= strtol (optarg
, &p
, 10);
1609 case OPT_CONNECT_TIMEOUT
:
1610 connect_timeout
= strtol (optarg
, &p
, 10);
1614 case OPT_USE_SSH_AGENT
:
1622 case OPT_CLIENTCERT
:
1623 clientcert
= optarg
;
1635 tls_fingerprint
= optarg
;
1642 keyfile
= pwmd_strdup (optarg
);
1644 case OPT_NEW_KEYFILE
:
1645 new_keyfile
= pwmd_strdup (optarg
);
1650 case OPT_LOCK_TIMEOUT
:
1651 lock_timeout
= strtol (optarg
, &p
, 10);
1660 lcctype
= pwmd_strdup (optarg
);
1662 case OPT_LC_MESSAGES
:
1663 lcmessages
= pwmd_strdup (optarg
);
1666 timeout
= strtol (optarg
, &p
, 10);
1669 tries
= strtol (optarg
, &p
, 10);
1672 inquire
= escape (optarg
);
1674 case OPT_INQUIRE_FD
:
1675 inquirefd
= strtol (optarg
, &p
, 10);
1678 inquirefp
= fdopen (inquirefd
, "r");
1680 err (EXIT_FAILURE
, "%i", inquirefd
);
1683 case OPT_INQUIRE_FILE
:
1684 inquirefd
= open (optarg
, O_RDONLY
);
1685 if (inquirefd
== -1)
1686 err (EXIT_FAILURE
, "%s", optarg
);
1687 inquirefp
= fdopen (inquirefd
, "r");
1690 outfd
= strtol (optarg
, &p
, 10);
1693 outfp
= fdopen (outfd
, "w");
1695 err (EXIT_FAILURE
, "%i", outfd
);
1702 statusfd
= strtol (optarg
, &p
, 10);
1705 statusfp
= fdopen (statusfd
, "w");
1707 err (EXIT_FAILURE
, "%i", statusfd
);
1710 case OPT_STATUS_IGNORE
:
1711 parse_status_ignore (optarg
);
1714 printf ("%s (pwmc)\n\n"
1715 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015\n"
1717 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1718 "Compile-time features:\n"
1719 #ifdef HAVE_LIBREADLINE
1734 #ifdef WITH_PINENTRY
1749 "\n", PACKAGE_STRING
, PACKAGE_BUGREPORT
);
1750 exit (EXIT_SUCCESS
);
1752 pinentry_path
= optarg
;
1755 usage (argv
[0], EXIT_SUCCESS
);
1759 case OPT_SIGN_KEYID
:
1760 sign_keyid
= optarg
;
1766 case OPT_NO_PINENTRY
:
1769 #ifdef HAVE_LIBREADLINE
1770 case OPT_INTERACTIVE
:
1775 usage (argv
[0], EXIT_FAILURE
);
1780 fprintf (stderr
, N_("%s: invalid argument for option '--%s'\n"),
1781 argv
[0], long_opts
[opt_index
].name
);
1782 usage (argv
[0], EXIT_FAILURE
);
1791 knownhosts
= optarg
;
1795 inquire_line
= optarg
;
1810 clientname
= optarg
;
1813 usage (argv
[0], EXIT_FAILURE
);
1817 #ifdef HAVE_LIBREADLINE
1818 if (interactive
&& !isatty (STDIN_FILENO
))
1819 usage (argv
[0], EXIT_FAILURE
);
1820 else if (isatty (STDIN_FILENO
) && !inquire
&& !inquire_line
)
1824 filename
= argv
[optind
];
1826 gnutls_global_set_mem_functions (pwmd_malloc
, pwmd_malloc
, NULL
,
1827 pwmd_realloc
, pwmd_free
);
1830 rc
= pwmd_new (clientname
, &pwm
);
1834 pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TRIES
, tries
);
1836 fprintf (stderr
, N_("Connecting ...\n"));
1838 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1839 socktype
= is_remote_url (url
);
1840 if (socktype
!= PWMD_SOCKET_LOCAL
)
1843 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1844 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, connect_timeout
);
1849 if (socktype
== PWMD_SOCKET_SSH
)
1852 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_CB
, knownhost_cb
);
1856 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_DATA
, clientname
);
1860 if (!getenv ("SSH_AUTH_SOCK") || identity
)
1863 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_AGENT
, use_ssh_agent
);
1867 rc
= pwmd_connect (pwm
, url
, identity
, knownhosts
);
1873 rc
= pwmd_setopt (pwm
, PWMD_OPTION_TLS_VERIFY
, tls_verify
);
1877 rc
= pwmd_connect (pwm
, url
, clientcert
, clientkey
, cacert
, prio
,
1883 rc
= pwmd_connect (pwm
, url
);
1885 rc
= pwmd_connect (pwm
, url
);
1891 fprintf (stderr
, N_("Connected.\n"));
1894 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1895 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, socket_timeout
);
1902 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1903 "OPTION LOCK-TIMEOUT=%li", lock_timeout
);
1910 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCK_ON_OPEN
, 1);
1915 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, NULL
, NULL
);
1921 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, timeout
);
1926 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
1930 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
,
1931 (local_pin
|| keyfile
|| new_keyfile
));
1937 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_PATH
, pinentry_path
);
1944 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DISPLAY
, display
);
1951 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TTY
, tty
);
1958 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TERM
, ttytype
);
1965 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_CTYPE
, lcctype
);
1972 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_MESSAGES
, lcmessages
);
1979 rc
= pwmd_setopt (pwm
, PWMD_OPTION_STATUS_CB
, status_msg_cb
);
1986 rc
= open_command (filename
);
1991 #ifdef HAVE_LIBREADLINE
1994 rc
= do_interactive ();
2002 struct inquire_s
*inq
= NULL
;
2004 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2006 rc
= pwmd_command (pwm
, &result
, &len
, inquire_cb
, inq
, inquire
);
2012 if (fcntl (STDIN_FILENO
, F_SETFL
, O_NONBLOCK
) == -1)
2014 rc
= gpg_error_from_errno (errno
);
2022 rc
= process_cmd ();
2027 n
= read (STDIN_FILENO
, command
, sizeof (command
)-1);
2030 if (errno
== EAGAIN
)
2036 rc
= gpg_error_from_errno (errno
);
2047 if (!p
|| !*p
|| !strcasecmp (p
, "BYE"))
2051 struct inquire_s
*inq
= NULL
;
2052 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2055 rc
= parse_dotcommand (command
, &result
, &len
, inq
);
2065 fwrite (result
, 1, result
[len
- 1] == 0 ? len
- 1 : len
, outfp
);
2073 else if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
2074 (void) pwmd_command (pwm
, &result
, NULL
, NULL
, NULL
,
2075 "GETINFO last_error");
2077 #ifdef HAVE_LIBREADLINE
2080 memset (command
, 0, sizeof (command
));
2083 show_error (pwm
, rc
, result
);
2086 pwmd_free (keyfile
);
2087 pwmd_free (new_keyfile
);
2090 parse_status_ignore (NULL
);
2091 if (connected
&& !quiet
)
2092 fprintf (stderr
, N_("Connection closed.\n"));
2094 exit (rc
? EXIT_FAILURE
: EXIT_SUCCESS
);