2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015
3 Ben Kibbey <bjk@luxsci.net>
5 This file is part of libpwmd.
7 Libpwmd is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 2 of the License, or
10 (at your option) any later version.
12 Libpwmd is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Libpwmd. If not, see <http://www.gnu.org/licenses/>.
33 #include <sys/select.h>
35 #include <sys/types.h>
43 #include <gnutls/gnutls.h>
50 #ifdef HAVE_GETOPT_LONG
55 #include "getopt_long.h"
58 #ifdef HAVE_LIBREADLINE
59 #if defined(HAVE_READLINE_READLINE_H)
60 #include <readline/readline.h>
61 #elif defined(HAVE_READLINE_H)
63 #endif /* !defined(HAVE_READLINE_H) */
64 static int interactive_error
;
65 static int interactive
;
66 #endif /* HAVE_LIBREADLINE */
68 #ifdef HAVE_READLINE_HISTORY
69 #if defined(HAVE_READLINE_HISTORY_H)
70 #include <readline/history.h>
71 #elif defined(HAVE_HISTORY_H)
74 #endif /* HAVE_READLINE_HISTORY */
81 #define N_(msgid) gettext(msgid)
86 #define DEFAULT_STATUS_IGNORE "KEEPALIVE,STATE,GPGME,PASSPHRASE_INFO,PASSPHRASE_HINT"
87 #define DEFAULT_PIN_TIMEOUT 30
88 #define DEFAULT_PIN_TRIES 3
89 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
92 static int no_pinentry
;
94 static char *filename
;
97 static char *sign_keyid
;
99 static char *keyparams
;
100 static char *keyfile
;
101 static char *new_keyfile
;
102 static char *sign_keyfile
;
104 static int local_pin
;
105 static int inquirefd
;
109 static char **status_ignore
;
116 size_t size
; // from stat(2).
120 static gpg_error_t
finalize ();
121 static gpg_error_t
set_inquire (int fd
, const char *line
,
122 struct inquire_s
**result
);
123 static gpg_error_t
parse_dotcommand (const char *line
, char **result
,
124 size_t * len
, struct inquire_s
*inq
);
125 static gpg_error_t
open_command (const char *line
);
127 static gpg_error_t
get_password (char **result
, pwmd_pinentry_t w
, int echo
);
131 show_error (pwm_t
*pwm
, gpg_error_t rc
, const char *str
)
134 if (pwmd_tls_error (pwm
))
135 fprintf(stderr
, "TLS: %s\n", gnutls_strerror(pwmd_tls_error(pwm
)));
137 fprintf (stderr
, "ERR %i: %s%s%s%s", rc
, gpg_strerror (rc
),
138 str
? ": " : "", str
? str
: "", str
? "" : "\n");
145 pwmd_free (new_keyfile
);
146 pwmd_free (sign_keyfile
);
147 keyfile
= new_keyfile
= sign_keyfile
= NULL
;
151 usage (const char *pn
, int status
)
153 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
154 N_("Usage: pwmc [options] [file]\n"
156 " a url string to connect to (%s, see below)\n"
157 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
158 " --connect-timeout <seconds>\n"
159 " seconds before connecting to a remote host fails (0=disabled, 120)\n"
160 " --socket-timeout <seconds>\n"
161 " seconds before a remote command fails (0=disabled, 300)\n"
164 " --ca-cert <filename>\n"
165 " certificate authority (CA) used to sign the server cert\n"
166 " --client-cert <filename>\n"
167 " client certificate to use for authentication\n"
168 " --client-key <filename>\n"
169 " key file used to protect the client certificate\n"
170 " --tls-priority <string>\n"
171 " compression, cipher and hash algorithm string\n"
172 " (SECURE256:SECURE192:SECURE128:-VERS-SSL3.0)\n"
174 " verify the hostname against the server certificate\n"
175 " --tls-fingerprint <string>\n"
176 " a SHA-256 hash of the server fingerprint to verify against\n"
180 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
181 " --identity, -i <filename>\n"
182 " the ssh identity file to use for authentication\n"
183 " --knownhosts, -k <filename>\n"
184 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
187 " do not lock the data file upon opening it\n"
188 " --lock-timeout <N>\n"
189 " time in tenths of a second to wait for a locked data file (50)\n"
190 " --name, -n <string>\n"
191 " set the client name\n"
192 " --pinentry <path>\n"
193 " the full path to the pinentry binary\n"
194 " --local-pinentry\n"
195 " force using a local pinentry\n"
197 " disable pinentry both remotely and locally\n"
198 " --ttyname, -y <path>\n"
199 " tty that pinentry will use\n"
200 " --ttytype, -t <string>\n"
201 " pinentry terminal type (default is $TERM)\n"
203 " pinentry display (default is $DISPLAY)\n"
204 " --lc-ctype <string>\n"
205 " locale setting for pinentry\n"
206 " --lc-messages <string>\n"
207 " locale setting for pinentry\n"
209 " number of pinentry tries before failing (3)\n"
210 " --timeout <seconds>\n"
211 " pinentry timeout\n"
212 " --inquire <COMMAND>\n"
213 " the specified command (with any options) uses a server inquire while\n"
214 " command data is read via the inquire file descriptor (stdin)\n"
215 " --inquire-line, -L <STRING>\n"
216 " the initial line to send (i.e., element path) before the inquire data\n"
217 " --inquire-fd <FD>\n"
218 " read inquire data from the specified file descriptor (stdin)\n"
219 " --inquire-file <filename>\n"
220 " read inquire data from the specified filename\n"
221 " --output-fd <FD>\n"
222 " redirect command output to the specified file descriptor\n"
224 " send the SAVE command before exiting\n"
225 " --key-file <filename>\n"
226 " obtain the passphrase from the specified filename\n"
227 " --new-key-file <filename>\n"
228 " obtain the passphrase to save with from the specified filename\n"
229 " --sign-key-file <filename>\n"
230 " obtain the passphrase to sign (symmetric) with from the specified filename\n"
231 " --key-params <filename>\n"
232 " key parameters to use for key generation (pwmd default)\n"
233 " --keyid <recipient>[,<recipient>]\n"
234 " the public key ID to u\n"
235 " --sign-keyid <string>\n"
236 " the key ID to sign the data file with\n"
238 " use conventional encryption with optional signer(s) for new files\n"
240 " disable showing of status messages from the server\n"
241 " --status-ignore <string[,...]>\n"
242 " prevent parsing of the specified status message keywords\n"
244 " disable showing of extra messages (implies --no-status)\n"
245 " --status-fd <FD>\n"
246 " redirect status messages to the specified file descriptor\n"
247 #ifdef HAVE_LIBREADLINE
249 " use a shell like interface to pwmd (allows more than one command)\n"
253 #ifdef DEFAULT_PWMD_SOCKET
259 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
261 "An optional url may be in the form of:\n"
262 " --url /path/to/socket\n"
263 " --url file://[path/to/socket]\n"
266 " --url ssh[46]://[username@]hostname[:port]\n"
267 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
271 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
272 " --client-key filename\n"
274 #ifdef HAVE_LIBREADLINE
276 "Interactive mode is used when input is from a terminal.\n"
283 inquire_cb (void *user
, const char *keyword
, gpg_error_t rc
,
284 char **data
, size_t * size
)
286 struct inquire_s
*inq
= user
;
288 int is_newpassword
= 0;
298 if (!strcmp (keyword
, "PASSPHRASE"))
300 else if (!strcmp (keyword
, "SIGN_PASSPHRASE"))
301 is_password
= sign
= 1;
302 else if (!strcmp (keyword
, "NEW_PASSPHRASE"))
304 #ifdef HAVE_LIBREADLINE
305 else if (!strcmp (keyword
, "KEYPARAM") && !interactive
)
308 else if (!strcmp (keyword
, "KEYPARAM"))
312 if (!keyparams
|| !*keyparams
)
313 return gpg_error (GPG_ERR_INV_PARAMETER
);
315 fd
= open (keyparams
, O_RDONLY
);
318 fprintf (stderr
, "%s: %s\n", keyparams
, strerror (errno
));
319 return gpg_error_from_syserror ();
322 rc
= set_inquire (fd
, NULL
, &inq
);
330 fprintf (stderr
, N_("Using file '%s' as %s.\n"), keyparams
, keyword
);
335 if ((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
)
336 || (sign
&& sign_keyfile
))
341 fd
= open (sign_keyfile
, O_RDONLY
);
343 fd
= open (is_password
? keyfile
: new_keyfile
, O_RDONLY
);
348 fprintf (stderr
, "%s: %s\n", sign_keyfile
, strerror (errno
));
350 fprintf (stderr
, "%s: %s\n", is_newpassword
? new_keyfile
351 : keyfile
, strerror (errno
));
352 return gpg_error_from_syserror ();
355 rc
= set_inquire (fd
, NULL
, &inq
);
363 fprintf (stderr
, N_("Using keyfile '%s' as %s.\n"),
364 sign
? sign_keyfile
: is_newpassword
? new_keyfile
367 else if ((is_password
&& !keyfile
) || (is_newpassword
&& !new_keyfile
)
368 || (sign
&& !sign_keyfile
))
372 rc
= pwmd_password (pwm
, keyword
, &tmp
, &inq
->len
);
373 if (rc
&& gpg_err_code (rc
) != GPG_ERR_EOF
)
376 pwmd_free (inq
->line
);
380 return gpg_error (GPG_ERR_EOF
);
382 #ifdef HAVE_LIBREADLINE
383 else if ((!inq
->last_keyword
|| strcmp (keyword
, inq
->last_keyword
))
388 ("%sPress CTRL-D to send the current line. Press twice to end. %s:\n"),
389 inq
->last_keyword
? "\n" : "", keyword
);
390 pwmd_free (inq
->last_keyword
);
391 inq
->last_keyword
= pwmd_strdup (keyword
);
395 /* The first part of the command data. */
401 return inq
->fd
== -1 ? gpg_error (GPG_ERR_EOF
) : 0;
404 *size
= read (inq
->fd
, inq
->line
, ASSUAN_LINELENGTH
);
408 return gpg_error (gpg_error_from_syserror ());
412 else if (inq
->fd
!= STDIN_FILENO
&&
413 (is_newpassword
|| is_password
|| is_keyparam
))
421 if (((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
)
422 || (sign
&& sign_keyfile
) || (keyparams
&& is_keyparam
))
423 && *size
== inq
->size
)
424 return gpg_error (GPG_ERR_EOF
);
426 return *size
? 0 : gpg_error (GPG_ERR_EOF
);
430 status_msg_cb (void *data
, const char *line
)
432 char *p
= strchr (line
, ' ');
435 /* Ignore status messages specified by the client via --status-ignore. */
436 for (s
= status_ignore
; s
&& *s
; s
++)
438 char *tmp
= strchr (line
, ' ');
439 size_t len
= tmp
? strlen (line
) - strlen (tmp
) : strlen (line
);
441 if (!strncmp (line
, *s
, len
) && len
== strlen (*s
))
445 if (statusfd
!= STDERR_FILENO
&& strncmp (line
, "STATE ", 6) && *line
!= '#'
446 && p
&& strchr (p
, ' ') && *++p
)
448 char *p1
= strchr (p
, ' ');
449 int a
= strtol (p
, NULL
, 10);
451 if (isdigit (*p
) && p1
)
453 int b
= strtol (p1
, NULL
, 10);
455 int t
= a
&& b
? a
* 100 / b
: 0;
457 strncpy (l
, line
, strlen (line
) - strlen (p
) - 1);
458 fprintf (statusfp
, "\r%s %i/%i %i%%%s", l
, a
, b
, t
,
465 fprintf (statusfp
, "%s\n", line
);
467 #ifdef HAVE_LIBREADLINE
476 return pwmd_process (pwm
);
481 get_password (char **result
, pwmd_pinentry_t w
, int echo
)
483 char buf
[LINE_MAX
] = { 0 }, *p
;
484 struct termios told
, tnew
;
489 if (!isatty (STDIN_FILENO
))
491 fprintf (stderr
, N_("Input is not from a terminal! Failing.\n"));
492 return GPG_ERR_ENOTTY
;
497 if (tcgetattr (STDIN_FILENO
, &told
) == -1)
498 return gpg_error_from_syserror ();
500 memcpy (&tnew
, &told
, sizeof (struct termios
));
501 tnew
.c_lflag
&= ~(ECHO
);
502 tnew
.c_lflag
|= ICANON
| ECHONL
;
504 if (tcsetattr (STDIN_FILENO
, TCSANOW
, &tnew
) == -1)
508 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
509 return gpg_error_from_errno (n
);
515 case PWMD_PINENTRY_OPEN
:
516 fprintf (stderr
, N_("Password for %s: "), filename
);
518 case PWMD_PINENTRY_OPEN_FAILED
:
519 fprintf (stderr
, N_("Invalid password. Password for %s: "), filename
);
521 case PWMD_PINENTRY_SAVE
:
522 fprintf (stderr
, N_("New password for %s: "), filename
);
524 case PWMD_PINENTRY_SAVE_CONFIRM
:
525 fprintf (stderr
, N_("Confirm password: "));
531 if ((p
= fgets (buf
, sizeof (buf
), stdin
)) == NULL
)
534 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
540 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
545 return GPG_ERR_CANCELED
;
548 p
[strlen (p
) - 1] = 0;
552 key
= pwmd_strdup_printf ("%s", p
);
553 memset (&buf
, 0, sizeof (buf
));
556 return GPG_ERR_ENOMEM
;
564 knownhost_cb (void *data
, const char *host
, const char *key
, size_t len
)
568 pwmd_strdup_printf (N_
569 ("Password Manager Daemon: %s\n\nWhile attempting an SSH connection to %s there was a problem verifying it's hostkey against the known and trusted hosts file because it's hostkey was not found.\n\nWould you like to treat this connection as trusted for this and future connections by adding %s's hostkey to the known hosts file?"),
570 (char *) data
, host
, host
);
572 if (no_pinentry
&& !isatty (STDIN_FILENO
))
574 fprintf (stderr
, N_("Input is not from a terminal! Failing.\n"));
576 return GPG_ERR_ENOTTY
;
578 else if (no_pinentry
)
580 for (char *p
= buf
, len
= 0; *p
; p
++, len
++)
589 while (!isspace (*(--p
)));
596 fprintf (stderr
, "%s\n\n", buf
);
603 fprintf (stderr
, N_("Trust this connection [y/N]: "));
605 rc
= get_password (&result
, PWMD_PINENTRY_CONFIRM
, 1);
610 if (!result
|| !*result
|| *result
== 'n' || *result
== 'N')
612 if (result
&& *result
)
615 return GPG_ERR_NOT_CONFIRMED
;
618 if ((*result
== 'y' || *result
== 'Y') && *(result
+ 1) == 0)
627 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, buf
);
633 return pwmd_getpin (pwm
, NULL
, NULL
, NULL
, PWMD_PINENTRY_CONFIRM
);
637 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
639 is_remote_url (const char *str
)
642 return PWMD_SOCKET_LOCAL
;
645 if (strstr (str
, "ssh://") || strstr (str
, "ssh4://")
646 || strstr (str
, "ssh6://"))
647 return PWMD_SOCKET_SSH
;
651 if (strstr (str
, "tls://") || strstr (str
, "tls4://")
652 || strstr (str
, "tls6://"))
653 return PWMD_SOCKET_TLS
;
656 return PWMD_SOCKET_LOCAL
;
661 escape (const char *str
)
664 char *buf
= pwmd_malloc (ASSUAN_LINELENGTH
+ 1), *b
= buf
;
667 for (p
= str
; *p
; p
++, len
++)
669 if (len
== ASSUAN_LINELENGTH
)
713 free_inquire (struct inquire_s
*inq
)
718 pwmd_free (inq
->line
);
720 if (inq
->fd
!= -1 && inq
->fd
!= STDIN_FILENO
)
723 pwmd_free (inq
->last_keyword
);
727 /* When *result is not NULL it is updated to the new values and not
730 set_inquire (int fd
, const char *line
, struct inquire_s
**result
)
732 struct inquire_s inq
= { 0 };
733 struct stat st
= { 0 };
738 if (fstat (fd
, &st
) == -1)
739 return gpg_error_from_syserror ();
741 inq
.size
= st
.st_size
;
745 inq
.line
= pwmd_calloc (1, ASSUAN_LINELENGTH
);
747 return GPG_ERR_ENOMEM
;
751 char *s
= escape (line
);
755 pwmd_free (inq
.line
);
756 return GPG_ERR_ENOMEM
;
759 if (strlen (s
) >= ASSUAN_LINELENGTH
)
761 pwmd_free (inq
.line
);
763 return GPG_ERR_LINE_TOO_LONG
;
766 strncpy (inq
.line
, s
, ASSUAN_LINELENGTH
- 1);
767 inq
.len
= strlen (s
);
771 rc
= pwmd_setopt (pwm
, PWMD_OPTION_INQUIRE_TOTAL
,
772 st
.st_size
? st
.st_size
+ strlen (inq
.line
) : 0);
775 pwmd_free (inq
.line
);
780 *result
= pwmd_malloc (sizeof (struct inquire_s
));
783 if ((*result
)->fd
!= -1 && (*result
)->fd
!= STDIN_FILENO
)
784 close ((*result
)->fd
);
786 pwmd_free ((*result
)->line
);
787 (*result
)->line
= NULL
;
792 memcpy (*result
, &inq
, sizeof (struct inquire_s
));
793 memset (&inq
, 0, sizeof (struct inquire_s
));
797 #ifdef HAVE_LIBREADLINE
799 interactive_hook (void)
801 interactive_error
= process_cmd ();
803 if (interactive_error
)
804 rl_event_hook
= NULL
;
814 ("------------------------------------------------------------------------------\n"
815 "Elements are TAB delimited. Press CTRL-V then TAB to insert from the prompt.\n"
817 "Type HELP for protocol commands. Type .help for pwmc commands. Press CTRL-D\n"
819 "------------------------------------------------------------------------------\n"));
824 parse_arg (const char *src
, char *dst
, size_t len
)
830 for (; s
&& *s
&& *s
!= ' ' && n
< len
; s
++, n
++)
838 parse_opt (char **line
, const char *opt
, gpg_error_t
* rc
)
840 static char result
[ASSUAN_LINELENGTH
] = { 0 }, *r
= result
;
841 char *s
= strstr (*line
, opt
);
851 size_t rlen
= strlen (opt
);
855 while (*p
&& *p
== ' ')
861 for (; *p
&& len
< sizeof (result
) - 1; p
++, rlen
++)
863 if (isspace (*p
) && !quote
)
866 if (*p
== '\"' && lastc
!= '\\')
879 if (len
>= sizeof (result
) - 1)
880 *rc
= GPG_ERR_LINE_TOO_LONG
;
885 while (*p
&& *p
== ' ')
896 read_command (const char *line
, char **result
, size_t * len
)
900 char *filename
= NULL
;
901 struct inquire_s
*inq
= NULL
;
902 char *p
= (char *) line
;
903 const char *prefix
= parse_opt (&p
, "--prefix", &rc
);
904 char filebuf
[ASSUAN_LINELENGTH
];
913 while (*p
&& isspace (*p
))
916 filename
= parse_arg (p
, filebuf
, sizeof (filebuf
));
917 if (filename
&& *filename
)
919 p
+= strlen (filename
) + 1;
921 while (*p
&& isspace (*p
))
933 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
936 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\" = \")\n"));
940 fd
= open (filename
, O_RDONLY
);
942 return gpg_error_from_syserror ();
944 rc
= set_inquire (fd
, prefix
&& *prefix
? prefix
: NULL
, &inq
);
951 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, "%s", p
);
957 redir_command (const char *line
)
959 const char *p
= line
;
961 gpg_error_t rc
= GPG_ERR_SYNTAX
;
962 char *filename
= NULL
;
963 struct inquire_s
*inq
= NULL
;
966 char filebuf
[ASSUAN_LINELENGTH
];
970 filename
= parse_arg (p
, filebuf
, sizeof (filebuf
));
971 if (filename
&& *filename
)
973 p
+= strlen (filename
) + 1;
975 while (*p
&& isspace (*p
))
985 fprintf (stderr
, N_("Usage: .redir <filename> <command> [args]\n"));
989 fd
= open (filename
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600);
991 return gpg_error_from_syserror ();
993 #ifdef HAVE_LIBREADLINE
994 rc
= set_inquire (interactive
? STDIN_FILENO
: inquirefd
, NULL
, &inq
);
996 rc
= set_inquire (inquirefd
, NULL
, &inq
);
1004 rc
= parse_dotcommand (p
, &result
, &len
, inq
);
1005 if (!rc
&& result
&& len
--)
1006 { // null byte which is always appended
1007 if (write (fd
, result
, len
) != len
)
1008 rc
= GPG_ERR_TOO_SHORT
;
1018 help_command (const char *line
)
1021 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
1022 " .redir <filename> <command>\n"
1023 " redirect the output of a command to the specified file\n"
1025 " .open <filename>\n"
1026 " open the specified filename losing any changes to the current one\n"
1028 " .read [--prefix <string>] <filename> <command> [args]\n"
1029 " obtain data from the specified filename for an inquire command\n"
1031 " .set help | <name> [<value>]\n"
1032 " set option <name> to <value>\n"
1035 " write changes of the file to disk\n"
1038 " change the passphrase of a data file\n"
1041 " this help text\n"));
1046 open_command (const char *line
)
1048 struct inquire_s
*inq
= NULL
;
1049 const char *filename
= line
;
1052 while (filename
&& isspace (*filename
))
1055 if (!filename
|| !*filename
)
1057 fprintf (stderr
, N_("Usage: .open <filename>\n"));
1058 return GPG_ERR_SYNTAX
;
1061 #ifdef HAVE_LIBREADLINE
1062 if (interactive
|| !quiet
)
1066 fprintf (stderr
, N_("Opening data file \"%s\" ...\n"), filename
);
1068 #ifdef HAVE_LIBREADLINE
1069 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1071 rc
= set_inquire (-1, NULL
, &inq
);
1078 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1080 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 1);
1084 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1086 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
1090 rc
= pwmd_open (pwm
, filename
, inquire_cb
, inq
);
1098 set_command (const char *line
)
1101 char name
[256] = { 0 };
1102 char value
[512] = { 0 };
1105 const char *p
= line
;
1107 while (p
&& *p
&& isspace (*p
))
1110 namep
= parse_arg (p
, name
, sizeof (name
));
1111 if (!namep
|| !*namep
)
1113 fprintf (stderr
, N_("Usage: .set help | <name> [<value>]\n"));
1114 return GPG_ERR_SYNTAX
;
1117 p
+= strlen (namep
);
1118 while (p
&& *p
&& isspace (*p
))
1121 valuep
= parse_arg (p
, value
, sizeof (value
));
1123 if (!strcmp (name
, "keyfile") || !strcmp (name
, "new-keyfile")
1124 || !strcmp (name
, "sign-keyfile"))
1126 int is_newkeyfile
= 1;
1127 int sign
= !strcmp (name
, "sign-keyfile");
1129 if (!strcmp (name
, "keyfile") || sign
)
1134 pwmd_free (new_keyfile
);
1139 pwmd_free (sign_keyfile
);
1140 sign_keyfile
= NULL
;
1144 pwmd_free (keyfile
);
1151 new_keyfile
= pwmd_strdup (value
);
1153 sign_keyfile
= pwmd_strdup (value
);
1155 keyfile
= pwmd_strdup (value
);
1159 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 1);
1161 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1164 else if (!local_pin
&& !no_pinentry
)
1168 pwmd_socket_type (pwm
, &t
);
1169 if (t
== PWMD_SOCKET_LOCAL
)
1171 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 0);
1173 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1177 else if (!strcmp(name
, "pinentry-timeout"))
1180 int n
= strtol(valuep
, &e
, 10);
1183 return gpg_error (GPG_ERR_INV_VALUE
);
1186 n
= DEFAULT_PIN_TIMEOUT
;
1188 rc
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, n
);
1190 else if (!strcmp (name
, "help"))
1194 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1195 "delimited. When no value is specified the option is unset.\n\n"
1196 "keyfile [<filename>]\n"
1197 " set or unset the keyfile to be used when a passphrase is required (*)\n"
1199 "new-keyfile [<filename>]\n"
1200 " set or unset the keyfile to be used when a new passphrase is required (*)\n"
1202 "sign-keyfile [<filename>]\n"
1203 " set or unset the keyfile to be used when a passphrase is required for\n"
1204 " signing (symmetric) (*)\n"
1206 "pinentry-timeout <seconds>\n"
1207 " the amount of seconds before pinentry gives up waiting for input\n"
1209 "* = the next protocol command will unset this value\n"
1213 rc
= GPG_ERR_UNKNOWN_OPTION
;
1219 save_command (const char *line
)
1221 struct inquire_s
*inq
= NULL
;
1224 #ifdef HAVE_LIBREADLINE
1225 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1227 rc
= set_inquire (-1, NULL
, &inq
);
1232 if (new_keyfile
|| keyfile
|| sign_keyfile
)
1234 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1236 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 1);
1240 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1242 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
1246 rc
= pwmd_save (pwm
, line
, inquire_cb
, inq
);
1254 do_save_passwd_command (const char *line
, int save
)
1256 struct inquire_s
*inq
= NULL
;
1259 #ifdef HAVE_LIBREADLINE
1260 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1262 rc
= set_inquire (-1, NULL
, &inq
);
1267 if (new_keyfile
|| keyfile
|| sign_keyfile
)
1269 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1271 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 1);
1275 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1277 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
1283 rc
= pwmd_save (pwm
, line
, inquire_cb
, inq
);
1285 rc
= pwmd_passwd (pwm
, line
, inquire_cb
, inq
);
1294 parse_dotcommand (const char *line
, char **result
,
1295 size_t * len
, struct inquire_s
*inq
)
1297 const char *p
= line
;
1300 if (!strncmp (p
, ".read", 5))
1301 rc
= read_command (p
+ 5, result
, len
);
1302 else if (!strncmp (p
, ".redir", 6))
1303 rc
= redir_command (p
+ 6);
1304 else if (!strncmp (p
, ".help", 5))
1305 rc
= help_command (p
+ 5);
1306 else if (!strncmp (p
, ".open", 5))
1307 rc
= open_command (p
+ 5);
1308 else if (!strncmp (p
, ".set", 4))
1309 rc
= set_command (p
+ 4);
1310 else if (!strncmp (p
, ".save", 5))
1311 rc
= do_save_passwd_command (p
+ 5, 1);
1312 else if (!strncmp (p
, ".passwd", 7))
1313 rc
= do_save_passwd_command (p
+ 7, 0);
1316 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, "%s", line
);
1317 #ifdef HAVE_LIBREADLINE
1322 #ifdef HAVE_LIBREADLINE
1330 #ifdef HAVE_LIBREADLINE
1335 struct inquire_s
*inq
= NULL
;
1338 rc
= process_cmd ();
1342 rc
= set_inquire (STDIN_FILENO
, NULL
, &inq
);
1347 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1349 rl_event_hook
= &interactive_hook
;
1350 rl_set_keyboard_input_timeout (100000);
1355 char *result
= NULL
;
1359 line
= readline ("pwm> ");
1360 if (interactive_error
)
1363 rc
= interactive_error
;
1373 if (gpg_err_code (rc
) != GPG_ERR_CANCELED
&&
1374 gpg_err_code (rc
) != GPG_ERR_EOF
)
1375 fprintf (stderr
, "ERR %i: %s\n", rc
, gpg_strerror (rc
));
1385 #ifdef HAVE_READLINE_HISTORY
1388 rc
= parse_dotcommand (line
, &result
, &len
, inq
);
1394 if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
1395 (void) pwmd_command (pwm
, &tmp
, NULL
, NULL
, NULL
,
1396 "GETINFO last_error");
1398 show_error (pwm
, rc
, tmp
);
1401 else if (result
&& len
)
1402 printf ("%s%s", result
, result
[len
- 1] != '\n' ? "\n" : "");
1416 #ifdef HAVE_LIBREADLINE
1423 fprintf (stderr
, "\n");
1431 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1432 p
= fgets (buf
, sizeof (buf
), stdin
);
1446 return GPG_ERR_CANCELED
;
1450 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1451 "CLEARCACHE %s", filename
);
1455 interactive_hook ();
1471 if (save
&& !filename
)
1475 ("No filename was specified on the command line. Aborting.\n"));
1476 return GPG_ERR_CANCELED
;
1479 if (save
&& filename
)
1482 pwmd_strdup_printf ("%s %s%s %s%s %s",
1483 symmetric
? "--symmetric" : "",
1484 keyid
? "--keyid=" : "",
1486 sign_keyid
? "--sign-keyid=" : "",
1487 sign_keyid
? sign_keyid
: "",
1488 keyparams
? "--inquire-keyparam" : "");
1490 #ifdef HAVE_LIBREADLINE
1491 if (!quiet
|| interactive
)
1497 fprintf (stderr
, "\n");
1498 fprintf (stderr
, N_("Saving changes ...\n"));
1501 rc
= save_command (args
);
1505 #ifdef HAVE_LIBREADLINE
1507 return rc
? rc
: quit
? 0 : GPG_ERR_CANCELED
;
1514 parse_status_ignore (char *str
)
1519 for (p
= status_ignore
; p
&& *p
; p
++)
1522 pwmd_free (status_ignore
);
1523 status_ignore
= NULL
;
1527 while ((s
= strsep (&str
, ",")))
1529 p
= pwmd_realloc (status_ignore
, (n
+ 2) * sizeof (char *));
1530 p
[n
++] = pwmd_strdup (s
);
1537 main (int argc
, char *argv
[])
1542 char command
[ASSUAN_LINELENGTH
], *p
= NULL
;
1543 char *result
= NULL
;
1545 char *pinentry_path
= NULL
;
1546 char *display
= NULL
, *tty
= NULL
, *ttytype
= NULL
;
1547 char *lcctype
= NULL
, *lcmessages
= NULL
;
1548 int outfd
= STDOUT_FILENO
;
1549 FILE *outfp
= stdout
;
1550 FILE *inquirefp
= stdin
;
1551 int show_status
= 1;
1552 char *clientname
= "pwmc";
1553 char *inquire
= NULL
;
1554 char *inquire_line
= NULL
;
1557 int use_ssh_agent
= 1;
1558 char *knownhosts
= NULL
;
1559 char *identity
= NULL
;
1562 char *cacert
= NULL
;
1563 char *clientcert
= NULL
;
1564 char *clientkey
= NULL
;
1567 char *tls_fingerprint
= NULL
;
1569 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1570 pwmd_socket_t socktype
;
1571 long socket_timeout
= 300;
1572 int connect_timeout
= 120;
1574 int lock_on_open
= 1;
1575 long lock_timeout
= 50;
1578 /* The order is important. */
1581 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1582 OPT_SOCKET_TIMEOUT
, OPT_CONNECT_TIMEOUT
,
1585 OPT_USE_SSH_AGENT
, OPT_IDENTITY
, OPT_KNOWNHOSTS
,
1588 OPT_CACERT
, OPT_CLIENTCERT
, OPT_CLIENTKEY
, OPT_PRIORITY
, OPT_VERIFY
,
1591 OPT_URL
, OPT_LOCAL
, OPT_TTYNAME
, OPT_TTYTYPE
,
1592 OPT_DISPLAY
, OPT_LC_CTYPE
, OPT_LC_MESSAGES
, OPT_TIMEOUT
, OPT_TRIES
,
1593 OPT_PINENTRY
, OPT_KEYFILE
, OPT_NEW_KEYFILE
, OPT_SIGN_KEYFILE
, OPT_NOLOCK
,
1594 OPT_LOCK_TIMEOUT
, OPT_SAVE
, OPT_OUTPUT_FD
, OPT_INQUIRE
,
1595 OPT_INQUIRE_FD
, OPT_INQUIRE_FILE
, OPT_INQUIRE_LINE
, OPT_NO_STATUS
,
1597 OPT_STATUSFD
, OPT_NAME
, OPT_VERSION
, OPT_HELP
, OPT_KEYID
, OPT_SIGN_KEYID
,
1598 OPT_SYMMETRIC
, OPT_KEYPARAMS
, OPT_NO_PINENTRY
, OPT_QUIET
,
1599 #ifdef HAVE_LIBREADLINE
1603 const struct option long_opts
[] = {
1604 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1605 {"socket-timeout", 1, 0, 0},
1606 {"connect-timeout", 1, 0, 0},
1610 {"no-ssh-agent", 0, 0, 0},
1611 {"identity", 1, 0, 'i'},
1612 {"knownhosts", 1, 0, 'k'},
1615 {"ca-cert", 1, 0, 0},
1616 {"client-cert", 1, 0, 0},
1617 {"client-key", 1, 0, 0},
1618 {"tls-priority", 1, 0, 0},
1619 {"tls-verify", 0, 0, 0},
1620 {"tls-fingerprint", 1, 0, 0},
1623 {"local-pinentry", 0, 0},
1624 {"ttyname", 1, 0, 'y'},
1625 {"ttytype", 1, 0, 't'},
1626 {"display", 1, 0, 'd'},
1627 {"lc-ctype", 1, 0, 0},
1628 {"lc-messages", 1, 0, 0},
1629 {"timeout", 1, 0, 0},
1631 {"pinentry", 1, 0, 0},
1632 {"key-file", 1, 0, 0},
1633 {"new-key-file", 1, 0, 0},
1634 {"sign-key-file", 1, 0, 0},
1635 {"no-lock", 0, 0, 0},
1636 {"lock-timeout", 1, 0, 0},
1637 {"save", 0, 0, 'S'},
1638 {"output-fd", 1, 0, 0},
1639 {"inquire", 1, 0, 0},
1640 {"inquire-fd", 1, 0, 0},
1641 {"inquire-file", 1, 0, 0},
1642 {"inquire-line", 1, 0, 'L'},
1643 {"no-status", 0, 0, 0},
1644 {"status-ignore", 1, 0, 0},
1645 {"status-fd", 1, 0, 0},
1646 {"name", 1, 0, 'n'},
1647 {"version", 0, 0, 0},
1650 {"sign-keyid", 1, 0, 0},
1651 {"symmetric", 0, 0, 0},
1652 {"key-params", 1, 0, 0},
1653 {"no-pinentry", 0, 0, 0},
1655 #ifdef HAVE_LIBREADLINE
1656 {"interactive", 0, 0},
1661 const char *optstring
= "L:y:t:d:P:I:Sn:i:k:s";
1663 const char *optstring
= "L:y:t:d:P:I:Sn:s";
1668 setlocale (LC_ALL
, "");
1669 bindtextdomain ("libpwmd", LOCALEDIR
);
1672 tries
= DEFAULT_PIN_TRIES
;
1673 inquirefd
= STDIN_FILENO
;
1674 statusfd
= STDERR_FILENO
;
1675 statusfp
= fdopen (statusfd
, "w");
1676 tmp
= pwmd_strdup (DEFAULT_STATUS_IGNORE
);
1677 parse_status_ignore (tmp
);
1681 getopt_long (argc
, argv
, optstring
, long_opts
, &opt_index
)) != -1)
1685 /* Handle long options without a short option part. */
1689 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1690 case OPT_SOCKET_TIMEOUT
:
1691 socket_timeout
= strtol (optarg
, &p
, 10);
1693 case OPT_CONNECT_TIMEOUT
:
1694 connect_timeout
= strtol (optarg
, &p
, 10);
1698 case OPT_USE_SSH_AGENT
:
1706 case OPT_CLIENTCERT
:
1707 clientcert
= optarg
;
1719 tls_fingerprint
= optarg
;
1729 keyfile
= pwmd_strdup (optarg
);
1731 case OPT_NEW_KEYFILE
:
1732 new_keyfile
= pwmd_strdup (optarg
);
1734 case OPT_SIGN_KEYFILE
:
1735 sign_keyfile
= pwmd_strdup (optarg
);
1740 case OPT_LOCK_TIMEOUT
:
1741 lock_timeout
= strtol (optarg
, &p
, 10);
1750 lcctype
= pwmd_strdup (optarg
);
1752 case OPT_LC_MESSAGES
:
1753 lcmessages
= pwmd_strdup (optarg
);
1756 timeout
= strtol (optarg
, &p
, 10);
1759 tries
= strtol (optarg
, &p
, 10);
1762 inquire
= escape (optarg
);
1764 case OPT_INQUIRE_FD
:
1765 inquirefd
= strtol (optarg
, &p
, 10);
1768 inquirefp
= fdopen (inquirefd
, "r");
1770 err (EXIT_FAILURE
, "%i", inquirefd
);
1773 case OPT_INQUIRE_FILE
:
1774 inquirefd
= open (optarg
, O_RDONLY
);
1775 if (inquirefd
== -1)
1776 err (EXIT_FAILURE
, "%s", optarg
);
1777 inquirefp
= fdopen (inquirefd
, "r");
1780 outfd
= strtol (optarg
, &p
, 10);
1783 outfp
= fdopen (outfd
, "w");
1785 err (EXIT_FAILURE
, "%i", outfd
);
1792 statusfd
= strtol (optarg
, &p
, 10);
1795 statusfp
= fdopen (statusfd
, "w");
1797 err (EXIT_FAILURE
, "%i", statusfd
);
1800 case OPT_STATUS_IGNORE
:
1801 parse_status_ignore (optarg
);
1804 printf ("%s (pwmc)\n\n"
1805 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015\n"
1807 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1808 "Compile-time features:\n"
1809 #ifdef HAVE_LIBREADLINE
1824 #ifdef WITH_PINENTRY
1839 "\n", PACKAGE_STRING
, PACKAGE_BUGREPORT
);
1840 exit (EXIT_SUCCESS
);
1842 pinentry_path
= optarg
;
1845 usage (argv
[0], EXIT_SUCCESS
);
1849 case OPT_SIGN_KEYID
:
1850 sign_keyid
= optarg
;
1856 case OPT_NO_PINENTRY
:
1859 #ifdef HAVE_LIBREADLINE
1860 case OPT_INTERACTIVE
:
1865 usage (argv
[0], EXIT_FAILURE
);
1870 fprintf (stderr
, N_("%s: invalid argument for option '--%s'\n"),
1871 argv
[0], long_opts
[opt_index
].name
);
1872 usage (argv
[0], EXIT_FAILURE
);
1881 knownhosts
= optarg
;
1885 inquire_line
= optarg
;
1900 clientname
= optarg
;
1903 usage (argv
[0], EXIT_FAILURE
);
1907 #ifdef HAVE_LIBREADLINE
1908 if (interactive
&& !isatty (STDIN_FILENO
))
1909 usage (argv
[0], EXIT_FAILURE
);
1910 else if (isatty (STDIN_FILENO
) && !inquire
&& !inquire_line
)
1914 filename
= argv
[optind
];
1916 rc
= pwmd_new (clientname
, &pwm
);
1920 pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TRIES
, tries
);
1922 fprintf (stderr
, N_("Connecting ...\n"));
1924 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1925 socktype
= is_remote_url (url
);
1926 if (socktype
!= PWMD_SOCKET_LOCAL
)
1929 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1930 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, connect_timeout
);
1935 if (socktype
== PWMD_SOCKET_SSH
)
1938 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_CB
, knownhost_cb
);
1942 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_DATA
, clientname
);
1946 if (!getenv ("SSH_AUTH_SOCK") || identity
)
1949 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_AGENT
, use_ssh_agent
);
1953 rc
= pwmd_connect (pwm
, url
, identity
, knownhosts
);
1959 rc
= pwmd_setopt (pwm
, PWMD_OPTION_TLS_VERIFY
, tls_verify
);
1963 rc
= pwmd_connect (pwm
, url
, clientcert
, clientkey
, cacert
, prio
,
1969 rc
= pwmd_connect (pwm
, url
);
1971 rc
= pwmd_connect (pwm
, url
);
1977 fprintf (stderr
, N_("Connected.\n"));
1980 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1981 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, socket_timeout
);
1988 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1989 "OPTION LOCK-TIMEOUT=%li", lock_timeout
);
1996 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCK_ON_OPEN
, 1);
2001 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, NULL
, NULL
);
2007 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, timeout
);
2012 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
2016 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
,
2017 (local_pin
|| keyfile
|| new_keyfile
|| sign_keyfile
));
2023 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_PATH
, pinentry_path
);
2030 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DISPLAY
, display
);
2037 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TTY
, tty
);
2044 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TERM
, ttytype
);
2051 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_CTYPE
, lcctype
);
2058 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_MESSAGES
, lcmessages
);
2065 rc
= pwmd_setopt (pwm
, PWMD_OPTION_STATUS_CB
, status_msg_cb
);
2072 rc
= open_command (filename
);
2077 #ifdef HAVE_LIBREADLINE
2080 rc
= do_interactive ();
2088 struct inquire_s
*inq
= NULL
;
2090 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2092 rc
= pwmd_command (pwm
, &result
, &len
, inquire_cb
, inq
, "%s", inquire
);
2098 if (fcntl (STDIN_FILENO
, F_SETFL
, O_NONBLOCK
) == -1)
2100 rc
= gpg_error_from_errno (errno
);
2108 rc
= process_cmd ();
2113 n
= read (STDIN_FILENO
, command
, sizeof (command
)-1);
2116 if (errno
== EAGAIN
)
2122 rc
= gpg_error_from_errno (errno
);
2133 if (!p
|| !*p
|| !strcasecmp (p
, "BYE"))
2137 struct inquire_s
*inq
= NULL
;
2138 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2141 rc
= parse_dotcommand (command
, &result
, &len
, inq
);
2151 fwrite (result
, 1, result
[len
- 1] == 0 ? len
- 1 : len
, outfp
);
2159 else if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
2160 (void) pwmd_command (pwm
, &result
, NULL
, NULL
, NULL
,
2161 "GETINFO last_error");
2163 #ifdef HAVE_LIBREADLINE
2166 memset (command
, 0, sizeof (command
));
2169 show_error (pwm
, rc
, result
);
2175 parse_status_ignore (NULL
);
2176 if (connected
&& !quiet
)
2177 fprintf (stderr
, N_("Connection closed.\n"));
2179 exit (rc
? EXIT_FAILURE
: EXIT_SUCCESS
);