2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
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>
46 #ifdef HAVE_GETOPT_LONG
51 #include "getopt_long.h"
54 #ifdef HAVE_LIBREADLINE
55 #if defined(HAVE_READLINE_READLINE_H)
56 #include <readline/readline.h>
57 #elif defined(HAVE_READLINE_H)
59 #endif /* !defined(HAVE_READLINE_H) */
60 static int interactive_error
;
61 static int interactive
;
62 #endif /* HAVE_LIBREADLINE */
64 #ifdef HAVE_READLINE_HISTORY
65 #if defined(HAVE_READLINE_HISTORY_H)
66 #include <readline/history.h>
67 #elif defined(HAVE_HISTORY_H)
70 #endif /* HAVE_READLINE_HISTORY */
77 #define N_(msgid) gettext(msgid)
81 #define DEFAULT_PIN_TRIES 3
82 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
85 static int no_pinentry
;
87 static char *filename
;
89 static int force_save
;
90 static int no_passphrase
;
93 static char *sign_keygrip
;
94 static char *keyparams
;
96 static char *new_keyfile
;
97 static unsigned long s2k_count
;
98 static uint64_t iterations
;
99 static int iterations_arg
;
101 static int local_pin
;
102 static int inquirefd
;
104 static int no_gpg_agent
;
111 size_t size
; // from stat(2).
115 static gpg_error_t
finalize ();
116 static gpg_error_t
set_inquire (int fd
, const char *line
,
117 struct inquire_s
**result
);
118 static gpg_error_t
parse_dotcommand (const char *line
, char **result
,
119 size_t * len
, struct inquire_s
*inq
);
120 static gpg_error_t
open_command (const char *line
);
122 static gpg_error_t
get_password (char **result
, pwmd_pinentry_t w
, int echo
);
126 show_error (gpg_error_t rc
, const char *str
)
128 fprintf (stderr
, "ERR %i: %s%s%s%s", rc
, gpg_strerror (rc
),
129 str
? ": " : "", str
? str
: "", str
? "" : "\n");
133 usage (const char *pn
, int status
)
135 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
136 N_("Usage: pwmc [options] [file]\n"
138 " a url string to connect to (~/.pwmd/socket, see below)\n"
139 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
140 " --connect-timeout <seconds>\n"
141 " seconds before connecting to a remote host fails (0=disabled, 120)\n"
142 " --socket-timeout <seconds>\n"
143 " seconds before a remote command fails (0=disabled, 300)\n"
146 " --ca-cert <filename>\n"
147 " certificate authority (CA) used to sign the server cert\n"
148 " --client-cert <filename>\n"
149 " client certificate to use for authentication\n"
150 " --client-key <filename>\n"
151 " key file used to protect the client certificate\n"
152 " --tls-priority <string>\n"
153 " compression, cipher and hash algorithm string (SECURE256)\n"
155 " verify the hostname against the server certificate\n"
156 " --tls-fingerprint <string>\n"
157 " a SHA-1 hash of the server fingerprint to verify against\n"
161 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
162 " --identity, -i <filename>\n"
163 " the ssh identity file to use for authentication\n"
164 " --knownhosts, -k <filename>\n"
165 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
168 " do not lock the data file upon opening it\n"
169 " --lock-timeout <N>\n"
170 " time in tenths of a second to wait for a locked data file (50)\n"
171 " --name, -n <string>\n"
172 " set the client name\n"
173 " --pinentry <path>\n"
174 " the full path to the pinentry binary (server default)\n"
175 " --local-pinentry\n"
176 " force using a local pinentry\n"
178 " disable pinentry both remotely and locally\n"
179 " --ttyname, -y <path>\n"
180 " tty that pinentry will use\n"
181 " --ttytype, -t <string>\n"
182 " pinentry terminal type (default is $TERM)\n"
184 " pinentry display (default is $DISPLAY)\n"
185 " --lc-ctype <string>\n"
186 " locale setting for pinentry\n"
187 " --lc-messages <string>\n"
188 " locale setting for pinentry\n"
190 " number of pinentry tries before failing (3)\n"
191 " --timeout <seconds>\n"
192 " pinentry timeout\n"
193 " --inquire <COMMAND>\n"
194 " the specified command (with any options) uses a server inquire while\n"
195 " command data is read via the inquire file descriptor (stdin)\n"
196 " --inquire-line, -L <STRING>\n"
197 " the initial line to send (i.e., element path) before the inquire data\n"
198 " --inquire-fd <FD>\n"
199 " read inquire data from the specified file descriptor (stdin)\n"
200 " --inquire-file <filename>\n"
201 " read inquire data from the specified filename\n"
202 " --output-fd <FD>\n"
203 " redirect command output to the specified file descriptor\n"
205 " send the SAVE command before exiting\n"
207 " like --save but always ask for a passphrase\n"
209 " do not require a passphrase when saving a new file\n"
211 " disable use of gpg-agent when saving to a new file\n"
212 " --key-file <filename>\n"
213 " obtain the passphrase from the specified filename\n"
214 " --new-key-file <filename>\n"
215 " obtain the passphrase to save with from the specified filename\n"
216 " --cipher <string>\n"
217 " the cipher to use when saving (see pwmd(1))\n"
218 " --cipher-iterations <N>\n"
219 " the number of times to encrypt the XML data (N+1)\n"
220 " --key-params <string>\n"
221 " the key parameters to use when saving a new file (pwmd default)\n"
222 " --keygrip <string>\n"
223 " the hex string of the keygrip to save to\n"
224 " --sign-keygrip <string>\n"
225 " the hex string of the keygrip to sign with\n"
227 " the number of times to hash the passphrase for a new file\n"
229 " disable showing of status messages from the server\n"
231 " disable showing of extra messages (implies --no-status)\n"
232 #ifdef HAVE_LIBREADLINE
234 " use a shell like interface to pwmd (allows more than one command)\n"
238 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
240 "An optional url may be in the form of:\n"
241 " --url /path/to/socket\n"
242 " --url file://[path/to/socket]\n"
245 " --url ssh[46]://[username@]hostname[:port]\n"
246 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
250 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
251 " --client-key filename\n"
253 #ifdef HAVE_LIBREADLINE
255 "Interactive mode is used when input is from a terminal.\n"
262 inquire_cb (void *user
, const char *keyword
, gpg_error_t rc
,
263 char **data
, size_t * size
)
265 struct inquire_s
*inq
= user
;
267 int is_newpassword
= 0;
275 if (!strcmp (keyword
, "PASSPHRASE"))
277 else if (!strcmp (keyword
, "NEW_PASSPHRASE"))
279 #ifdef HAVE_LIBREADLINE
280 else if (!strcmp (keyword
, "KEYPARAM") && !interactive
)
283 else if (!strcmp (keyword
, "KEYPARAM"))
286 if (!keyparams
|| !*keyparams
)
287 return gpg_error (GPG_ERR_INV_PARAMETER
);
290 *size
= strlen (keyparams
);
291 return gpg_error (GPG_ERR_EOF
);
294 if ((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
))
296 int fd
= open (is_password
? keyfile
: new_keyfile
, O_RDONLY
);
300 fprintf (stderr
, "%s: %s\n", is_newpassword
? new_keyfile
: keyfile
,
302 return gpg_error_from_syserror ();
305 rc
= set_inquire (fd
, NULL
, &inq
);
313 fprintf (stderr
, N_("Using keyfile '%s' as %s.\n"),
314 is_newpassword
? new_keyfile
: keyfile
, keyword
);
316 if (!new_keyfile
|| is_newpassword
)
320 pwmd_socket_type (pwm
, &t
);
321 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
322 if (!no_pinentry
&& t
== PWMD_SOCKET_LOCAL
)
323 pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 0);
326 else if ((is_password
&& !keyfile
) || (is_newpassword
&& !new_keyfile
))
330 rc
= pwmd_password (pwm
, keyword
, &tmp
, &inq
->len
);
331 if (rc
&& gpg_err_code (rc
) != GPG_ERR_EOF
)
334 pwmd_free (inq
->line
);
338 return gpg_error (GPG_ERR_EOF
);
340 #ifdef HAVE_LIBREADLINE
341 else if (!inq
->header
&& interactive
)
345 ("Press CTRL-D to send the current line. Press twice to end. %s:\n"),
351 /* The first part of the command data. */
357 return inq
->fd
== -1 ? gpg_error (GPG_ERR_EOF
) : 0;
360 *size
= read (inq
->fd
, inq
->line
, ASSUAN_LINELENGTH
);
364 return gpg_error (gpg_error_from_syserror ());
368 else if (inq
->fd
!= STDIN_FILENO
&& (is_newpassword
|| is_password
))
376 if (((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
))
377 && *size
== inq
->size
)
378 return gpg_error (GPG_ERR_EOF
);
380 return *size
? 0 : gpg_error (GPG_ERR_EOF
);
384 status_msg_cb (void *data
, const char *line
)
386 char *p
= strchr (line
, ' ');
388 if (!strcmp (line
, "KEEPALIVE"))
391 if (*line
!= '#' && p
&& strchr (p
, ' ') && *++p
)
393 char *p1
= strchr (p
, ' ');
394 int a
= strtol (p
, NULL
, 10);
396 if (isdigit (*p
) && p1
)
398 int b
= strtol (p1
, NULL
, 10);
400 int t
= a
&& b
? a
* 100 / b
: 0;
402 strncpy (l
, line
, strlen (line
) - strlen (p
) - 1);
403 fprintf (stderr
, "\r%s %i/%i %i%%%s", l
, a
, b
, t
,
410 fprintf (stderr
, "%s\n", line
);
412 #ifdef HAVE_LIBREADLINE
421 return pwmd_process (pwm
);
426 get_password (char **result
, pwmd_pinentry_t w
, int echo
)
428 char buf
[LINE_MAX
] = { 0 }, *p
;
429 struct termios told
, tnew
;
434 if (!isatty (STDIN_FILENO
))
436 fprintf (stderr
, N_("Input is not from a terminal! Failing.\n"));
437 return GPG_ERR_ENOTTY
;
442 if (tcgetattr (STDIN_FILENO
, &told
) == -1)
443 return gpg_error_from_syserror ();
445 memcpy (&tnew
, &told
, sizeof (struct termios
));
446 tnew
.c_lflag
&= ~(ECHO
);
447 tnew
.c_lflag
|= ICANON
| ECHONL
;
449 if (tcsetattr (STDIN_FILENO
, TCSANOW
, &tnew
) == -1)
453 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
454 return gpg_error_from_errno (n
);
460 case PWMD_PINENTRY_OPEN
:
461 fprintf (stderr
, N_("Password for %s: "), filename
);
463 case PWMD_PINENTRY_OPEN_FAILED
:
464 fprintf (stderr
, N_("Invalid password. Password for %s: "), filename
);
466 case PWMD_PINENTRY_SAVE
:
467 fprintf (stderr
, N_("New password for %s: "), filename
);
469 case PWMD_PINENTRY_SAVE_CONFIRM
:
470 fprintf (stderr
, N_("Confirm password: "));
476 if ((p
= fgets (buf
, sizeof (buf
), stdin
)) == NULL
)
478 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
483 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
488 return GPG_ERR_CANCELED
;
491 p
[strlen (p
) - 1] = 0;
495 key
= pwmd_strdup_printf ("%s", p
);
496 memset (&buf
, 0, sizeof (buf
));
499 return GPG_ERR_ENOMEM
;
507 knownhost_cb (void *data
, const char *host
, const char *key
, size_t len
)
511 pwmd_strdup_printf (N_
512 ("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?"),
513 (char *) data
, host
, host
);
515 if (no_pinentry
&& !isatty (STDIN_FILENO
))
517 fprintf (stderr
, N_("Input is not from a terminal! Failing.\n"));
519 return GPG_ERR_ENOTTY
;
521 else if (no_pinentry
)
523 for (char *p
= buf
, len
= 0; *p
; p
++, len
++)
532 while (!isspace (*(--p
)));
539 fprintf (stderr
, "%s\n\n", buf
);
546 fprintf (stderr
, N_("Trust this connection [y/N]: "));
548 rc
= get_password (&result
, PWMD_PINENTRY_CONFIRM
, 1);
553 if (!result
|| !*result
|| *result
== 'n' || *result
== 'N')
555 if (result
&& *result
)
558 return GPG_ERR_NOT_CONFIRMED
;
561 if ((*result
== 'y' || *result
== 'Y') && *(result
+ 1) == 0)
570 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, buf
);
576 return pwmd_getpin (pwm
, NULL
, NULL
, NULL
, PWMD_PINENTRY_CONFIRM
);
580 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
582 is_remote_url (const char *str
)
585 return PWMD_SOCKET_LOCAL
;
588 if (strstr (str
, "ssh://") || strstr (str
, "ssh4://")
589 || strstr (str
, "ssh6://"))
590 return PWMD_SOCKET_SSH
;
594 if (strstr (str
, "tls://") || strstr (str
, "tls4://")
595 || strstr (str
, "tls6://"))
596 return PWMD_SOCKET_TLS
;
599 return PWMD_SOCKET_LOCAL
;
604 escape (const char *str
)
607 char *buf
= pwmd_malloc (ASSUAN_LINELENGTH
+ 1), *b
= buf
;
610 for (p
= str
; *p
; p
++, len
++)
612 if (len
== ASSUAN_LINELENGTH
)
656 free_inquire (struct inquire_s
*inq
)
661 pwmd_free (inq
->line
);
663 if (inq
->fd
!= -1 && inq
->fd
!= STDIN_FILENO
)
669 /* When *result is not NULL it is updated to the new values and not
672 set_inquire (int fd
, const char *line
, struct inquire_s
**result
)
674 struct inquire_s inq
= { 0 };
675 struct stat st
= { 0 };
680 if (fstat (fd
, &st
) == -1)
681 return gpg_error_from_syserror ();
683 inq
.size
= st
.st_size
;
687 inq
.line
= pwmd_calloc (1, ASSUAN_LINELENGTH
);
689 return GPG_ERR_ENOMEM
;
693 char *s
= escape (line
);
697 pwmd_free (inq
.line
);
698 return GPG_ERR_ENOMEM
;
701 if (strlen (s
) >= ASSUAN_LINELENGTH
)
703 pwmd_free (inq
.line
);
705 return GPG_ERR_LINE_TOO_LONG
;
708 strncpy (inq
.line
, s
, ASSUAN_LINELENGTH
- 1);
709 inq
.len
= strlen (s
);
713 rc
= pwmd_setopt (pwm
, PWMD_OPTION_INQUIRE_TOTAL
,
714 st
.st_size
? st
.st_size
+ strlen (inq
.line
) : 0);
717 pwmd_free (inq
.line
);
722 *result
= pwmd_malloc (sizeof (struct inquire_s
));
725 if ((*result
)->fd
!= -1 && (*result
)->fd
!= STDIN_FILENO
)
726 close ((*result
)->fd
);
728 pwmd_free ((*result
)->line
);
729 (*result
)->line
= NULL
;
734 memcpy (*result
, &inq
, sizeof (struct inquire_s
));
735 memset (&inq
, 0, sizeof (struct inquire_s
));
739 #ifdef HAVE_LIBREADLINE
741 interactive_hook (void)
743 interactive_error
= process_cmd ();
745 if (interactive_error
)
746 rl_event_hook
= NULL
;
756 ("------------------------------------------------------------------------------\n"
757 "Elements are TAB delimited. Press CTRL-V then TAB to insert from the prompt.\n"
759 "Type HELP for protocol commands. Type .help for pwmc commands. Press CTRL-D\n"
761 "------------------------------------------------------------------------------\n"));
766 parse_arg (const char *src
, char *dst
, size_t len
)
772 for (; s
&& *s
&& *s
!= ' ' && n
< len
; s
++, n
++)
780 parse_opt (char **line
, const char *opt
, gpg_error_t
* rc
)
782 static char result
[ASSUAN_LINELENGTH
] = { 0 }, *r
= result
;
784 char *s
= strstr (*line
, opt
);
793 size_t rlen
= strlen (opt
);
797 while (*p
&& *p
== ' ')
803 for (; *p
&& len
< sizeof (result
) - 1; p
++, rlen
++)
805 if (isspace (*p
) && !quote
)
808 if (*p
== '\"' && lastc
!= '\\')
821 if (len
>= sizeof (result
) - 1)
822 *rc
= GPG_ERR_LINE_TOO_LONG
;
827 while (*p
&& *p
== ' ')
838 read_command (const char *line
, char **result
, size_t * len
)
842 char filebuf
[ASSUAN_LINELENGTH
];
843 char *filename
= NULL
;
844 struct inquire_s
*inq
= NULL
;
845 char *p
= (char *) line
;
846 const char *prefix
= parse_opt (&p
, "--prefix", &rc
);
855 while (*p
&& isspace (*p
))
858 filename
= parse_arg (p
, filebuf
, sizeof (filebuf
));
859 if (filename
&& *filename
)
861 p
+= strlen (filename
) + 1;
863 while (*p
&& isspace (*p
))
875 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
878 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\" = \")\n"));
882 fd
= open (filename
, O_RDONLY
);
884 return gpg_error_from_syserror ();
886 rc
= set_inquire (fd
, prefix
&& *prefix
? prefix
: NULL
, &inq
);
894 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, p
);
900 redir_command (const char *line
)
902 const char *p
= line
;
904 gpg_error_t rc
= GPG_ERR_SYNTAX
;
905 char filebuf
[ASSUAN_LINELENGTH
];
906 char *filename
= NULL
;
907 struct inquire_s
*inq
= NULL
;
913 filename
= parse_arg (p
, filebuf
, sizeof (filebuf
));
914 if (filename
&& *filename
)
916 p
+= strlen (filename
) + 1;
918 while (*p
&& isspace (*p
))
928 fprintf (stderr
, N_("Usage: .redir <filename> <command> [args]\n"));
932 fd
= open (filename
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600);
934 return gpg_error_from_syserror ();
936 #ifdef HAVE_LIBREADLINE
937 rc
= set_inquire (interactive
? STDIN_FILENO
: inquirefd
, NULL
, &inq
);
939 rc
= set_inquire (inquirefd
, NULL
, &inq
);
947 rc
= parse_dotcommand (p
, &result
, &len
, inq
);
948 if (!rc
&& result
&& len
--)
949 { // null byte which is always appended
950 if (write (fd
, result
, len
) != len
)
951 rc
= GPG_ERR_TOO_SHORT
;
961 help_command (const char *line
)
964 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
965 " .redir <filename> <command>\n"
966 " redirect the output of a command to the specified file\n"
968 " .open <filename>\n"
969 " open the specified filename losing any changes to the current one\n"
971 " .read [--prefix <string>] <filename> <command> [args]\n"
972 " obtain data from the specified filename for an inquire command\n"
974 " .set help | <name> [<value>]\n"
975 " set option <name> to <value>\n"
978 " write changes of the file to disk\n"
981 " this help text\n"));
986 open_command (const char *line
)
988 struct inquire_s
*inq
= NULL
;
989 const char *filename
= line
;
992 while (filename
&& isspace (*filename
))
995 if (!filename
|| !*filename
)
997 fprintf (stderr
, N_("Usage: .open <filename>\n"));
998 return GPG_ERR_SYNTAX
;
1001 #ifdef HAVE_LIBREADLINE
1002 if (interactive
|| !quiet
)
1006 fprintf (stderr
, N_("Opening data file \"%s\" ...\n"), filename
);
1008 #ifdef HAVE_LIBREADLINE
1009 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1011 rc
= set_inquire (-1, NULL
, &inq
);
1017 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1019 rc
= pwmd_open (pwm
, filename
, inquire_cb
, inq
);
1025 set_command (const char *line
)
1028 char name
[256] = { 0 };
1029 char value
[512] = { 0 };
1032 const char *p
= line
;
1034 while (p
&& *p
&& isspace (*p
))
1037 namep
= parse_arg (p
, name
, sizeof (name
));
1038 if (!namep
|| !*namep
)
1040 fprintf (stderr
, N_("Usage: .set help | <name> [<value>]\n"));
1041 return GPG_ERR_SYNTAX
;
1044 p
+= strlen (namep
);
1045 while (p
&& *p
&& isspace (*p
))
1048 valuep
= parse_arg (p
, value
, sizeof (value
));
1050 if (!strcmp (name
, "keyfile") || !strcmp (name
, "new-keyfile"))
1052 int is_newkeyfile
= 1;
1056 if (!strcmp (name
, "keyfile"))
1061 pwmd_free (new_keyfile
);
1066 pwmd_free (keyfile
);
1070 p
+= strlen (valuep
);
1071 while (p
&& *p
&& isspace (*p
))
1074 valuep
= (char *) p
;
1077 memcpy (datafile
, value
, sizeof (datafile
));
1078 valuep
= parse_arg (p
, value
, sizeof (value
));
1079 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
, "KEYGRIP %s",
1081 if (gpg_err_code (rc
) == GPG_ERR_NOT_SUPPORTED
1082 || (gpg_err_source (rc
) == GPG_ERR_SOURCE_USER_1
1083 && gpg_err_code (rc
) == GPG_ERR_ENOENT
))
1095 new_keyfile
= pwmd_strdup (value
);
1097 keyfile
= pwmd_strdup (value
);
1102 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1103 "AGENT option pinentry-mode=loopback");
1107 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);
1119 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1123 else if (!strcmp (name
, "help"))
1127 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1128 "delimited. When no value is specified the option is unset.\n\n"
1129 "keyfile <datafile> [<filename>]\n"
1130 " set or unset the keyfile to be used when a passphrase is required (*)\n"
1132 "new-keyfile <datafile> [<filename>]\n"
1133 " set or unset the keyfile to be used when a new passphrase is required (*)\n"
1135 "* = the next protocol command will unset this value\n"
1139 rc
= GPG_ERR_UNKNOWN_OPTION
;
1145 save_command (const char *line
)
1147 struct inquire_s
*inq
= NULL
;
1150 #ifdef HAVE_LIBREADLINE
1151 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1153 rc
= set_inquire (-1, NULL
, &inq
);
1158 if (new_keyfile
|| keyfile
)
1159 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1161 rc
= pwmd_save (pwm
, line
, inquire_cb
, inq
);
1162 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1168 parse_dotcommand (const char *line
, char **result
,
1169 size_t * len
, struct inquire_s
*inq
)
1171 const char *p
= line
;
1174 if (!strncmp (p
, ".read", 5))
1175 rc
= read_command (p
+ 5, result
, len
);
1176 else if (!strncmp (p
, ".redir", 6))
1177 rc
= redir_command (p
+ 6);
1178 else if (!strncmp (p
, ".help", 5))
1179 rc
= help_command (p
+ 5);
1180 else if (!strncmp (p
, ".open", 5))
1181 rc
= open_command (p
+ 5);
1182 else if (!strncmp (p
, ".set", 4))
1183 rc
= set_command (p
+ 4);
1184 else if (!strncmp (p
, ".save", 5))
1185 rc
= save_command (p
+ 5);
1188 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, line
);
1189 #ifdef HAVE_LIBREADLINE
1193 pwmd_free (keyfile
);
1194 pwmd_free (new_keyfile
);
1195 keyfile
= new_keyfile
= NULL
;
1196 #ifdef HAVE_LIBREADLINE
1204 #ifdef HAVE_LIBREADLINE
1209 struct inquire_s
*inq
= NULL
;
1212 rc
= process_cmd ();
1216 rc
= set_inquire (STDIN_FILENO
, NULL
, &inq
);
1221 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1223 rl_event_hook
= &interactive_hook
;
1224 rl_set_keyboard_input_timeout (100000);
1229 char *result
= NULL
;
1233 line
= readline ("pwm> ");
1234 if (interactive_error
)
1236 rc
= interactive_error
;
1246 if (gpg_err_code (rc
) != GPG_ERR_CANCELED
&&
1247 gpg_err_code (rc
) != GPG_ERR_EOF
)
1248 fprintf (stderr
, "ERR %i: %s\n", rc
, gpg_strerror (rc
));
1258 #ifdef HAVE_READLINE_HISTORY
1262 rc
= parse_dotcommand (line
, &result
, &len
, inq
);
1268 if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
1269 (void) pwmd_command (pwm
, &tmp
, NULL
, NULL
, NULL
,
1270 "GETINFO last_error");
1272 show_error (rc
, tmp
);
1275 else if (result
&& len
)
1276 printf ("%s%s", result
, result
[len
- 1] != '\n' ? "\n" : "");
1287 itoa (long long int n
)
1289 static char buf
[64];
1291 snprintf (buf
, sizeof (buf
), "%llu", n
);
1299 #ifdef HAVE_LIBREADLINE
1302 if (!force_save
&& interactive
)
1307 fprintf (stderr
, "\n");
1313 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1314 p
= fgets (buf
, sizeof (buf
), stdin
);
1328 return GPG_ERR_CANCELED
;
1332 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1333 "CLEARCACHE %s", filename
);
1337 interactive_hook ();
1353 if (save
&& !filename
)
1357 ("No filename was specified on the command line. Aborting.\n"));
1358 return GPG_ERR_CANCELED
;
1361 if (save
&& filename
)
1364 pwmd_strdup_printf ("%s%s %s%s %s %s%s %s%s %s %s --s2k-count=%lu",
1365 keygrip
? "--keygrip=" : "",
1366 keygrip
? keygrip
: "",
1367 sign_keygrip
? "--sign-keygrip=" : "",
1368 sign_keygrip
? sign_keygrip
: "",
1369 no_passphrase
? "--no-passphrase" : "",
1370 cipher
? "--cipher=" : "", cipher
? cipher
: "",
1371 iterations_arg
? "--cipher-iterations=" : "",
1372 iterations_arg
? itoa (iterations
) : "",
1373 no_gpg_agent
? "--no-agent" : "",
1374 keyparams
? "--inquire-keyparam" : "",
1377 #ifdef HAVE_LIBREADLINE
1378 if (!quiet
|| interactive
)
1384 fprintf (stderr
, "\n");
1385 fprintf (stderr
, N_("Saving changes ...\n"));
1388 rc
= save_command (args
);
1391 no_passphrase
= 0; // reset to avoid usage error on the next SAVE
1394 #ifdef HAVE_LIBREADLINE
1396 return rc
? rc
: quit
? 0 : GPG_ERR_CANCELED
;
1403 main (int argc
, char *argv
[])
1408 char command
[ASSUAN_LINELENGTH
], *p
= NULL
;
1409 char *result
= NULL
;
1411 char *pinentry_path
= NULL
;
1412 char *display
= NULL
, *tty
= NULL
, *ttytype
= NULL
;
1413 char *lcctype
= NULL
, *lcmessages
= NULL
;
1414 int outfd
= STDOUT_FILENO
;
1415 FILE *outfp
= stdout
;
1416 FILE *inquirefp
= stdin
;
1417 int show_status
= 1;
1418 char *clientname
= "pwmc";
1419 char *inquire
= NULL
;
1420 char *inquire_line
= NULL
;
1423 int use_ssh_agent
= 1;
1424 char *knownhosts
= NULL
;
1425 char *identity
= NULL
;
1428 char *cacert
= NULL
;
1429 char *clientcert
= NULL
;
1430 char *clientkey
= NULL
;
1433 char *tls_fingerprint
= NULL
;
1435 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1436 pwmd_socket_t socktype
;
1437 long socket_timeout
= 300;
1438 int connect_timeout
= 120;
1440 int lock_on_open
= 1;
1441 long lock_timeout
= 50;
1443 /* The order is important. */
1446 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1447 OPT_SOCKET_TIMEOUT
, OPT_CONNECT_TIMEOUT
,
1450 OPT_USE_SSH_AGENT
, OPT_IDENTITY
, OPT_KNOWNHOSTS
,
1453 OPT_CACERT
, OPT_CLIENTCERT
, OPT_CLIENTKEY
, OPT_PRIORITY
, OPT_VERIFY
,
1456 OPT_URL
, OPT_LOCAL
, OPT_FORCE_SAVE
, OPT_TTYNAME
, OPT_TTYTYPE
,
1457 OPT_DISPLAY
, OPT_LC_CTYPE
, OPT_LC_MESSAGES
, OPT_TIMEOUT
, OPT_TRIES
,
1458 OPT_PINENTRY
, OPT_KEYFILE
, OPT_NEW_KEYFILE
, OPT_NOLOCK
,
1459 OPT_LOCK_TIMEOUT
, OPT_SAVE
, OPT_OUTPUT_FD
, OPT_INQUIRE
,
1460 OPT_INQUIRE_FD
, OPT_INQUIRE_FILE
, OPT_INQUIRE_LINE
, OPT_NO_STATUS
,
1461 OPT_NAME
, OPT_VERSION
, OPT_HELP
, OPT_KEYGRIP
, OPT_SIGN_KEYGRIP
,
1462 OPT_NOPASSPHRASE
, OPT_CIPHER
, OPT_KEYPARAMS
, OPT_NO_PINENTRY
,
1463 OPT_S2K_COUNT
, OPT_ITERATIONS
, OPT_QUIET
, OPT_NO_GPG_AGENT
,
1464 #ifdef HAVE_LIBREADLINE
1468 const struct option long_opts
[] = {
1469 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1470 {"socket-timeout", 1, 0, 0},
1471 {"connect-timeout", 1, 0, 0},
1475 {"no-ssh-agent", 0, 0, 0},
1476 {"identity", 1, 0, 'i'},
1477 {"knownhosts", 1, 0, 'k'},
1480 {"ca-cert", 1, 0, 0},
1481 {"client-cert", 1, 0, 0},
1482 {"client-key", 1, 0, 0},
1483 {"tls-priority", 1, 0, 0},
1484 {"tls-verify", 0, 0, 0},
1485 {"tls-fingerprint", 1, 0, 0},
1488 {"local-pinentry", 0, 0},
1489 {"force-save", 0, 0},
1490 {"ttyname", 1, 0, 'y'},
1491 {"ttytype", 1, 0, 't'},
1492 {"display", 1, 0, 'd'},
1493 {"lc-ctype", 1, 0, 0},
1494 {"lc-messages", 1, 0, 0},
1495 {"timeout", 1, 0, 0},
1497 {"pinentry", 1, 0, 0},
1498 {"key-file", 1, 0, 0},
1499 {"new-key-file", 1, 0, 0},
1500 {"no-lock", 0, 0, 0},
1501 {"lock-timeout", 1, 0, 0},
1502 {"save", 0, 0, 'S'},
1503 {"output-fd", 1, 0, 0},
1504 {"inquire", 1, 0, 0},
1505 {"inquire-fd", 1, 0, 0},
1506 {"inquire-file", 1, 0, 0},
1507 {"inquire-line", 1, 0, 'L'},
1508 {"no-status", 0, 0, 0},
1509 {"name", 1, 0, 'n'},
1510 {"version", 0, 0, 0},
1512 {"keygrip", 1, 0, 0},
1513 {"sign-keygrip", 1, 0, 0},
1514 {"no-passphrase", 0, 0, 0},
1515 {"cipher", 1, 0, 0},
1516 {"key-params", 1, 0, 0},
1517 {"no-pinentry", 0, 0, 0},
1518 {"s2k-count", 1, 0, 0},
1519 {"cipher-iterations", 1, 0, 0},
1521 {"no-gpg-agent", 0, 0, 0},
1522 #ifdef HAVE_LIBREADLINE
1523 {"interactive", 0, 0},
1528 const char *optstring
= "L:y:t:d:P:I:Sn:i:k:";
1530 const char *optstring
= "L:y:t:d:P:I:Sn:";
1535 setlocale (LC_ALL
, "");
1536 bindtextdomain ("libpwmd", LOCALEDIR
);
1539 tries
= DEFAULT_PIN_TRIES
;
1540 inquirefd
= STDIN_FILENO
;
1543 getopt_long (argc
, argv
, optstring
, long_opts
, &opt_index
)) != -1)
1547 /* Handle long options without a short option part. */
1551 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1552 case OPT_SOCKET_TIMEOUT
:
1553 socket_timeout
= strtol (optarg
, &p
, 10);
1555 case OPT_CONNECT_TIMEOUT
:
1556 connect_timeout
= strtol (optarg
, &p
, 10);
1560 case OPT_USE_SSH_AGENT
:
1568 case OPT_CLIENTCERT
:
1569 clientcert
= optarg
;
1581 tls_fingerprint
= optarg
;
1584 case OPT_NO_GPG_AGENT
:
1591 keyfile
= pwmd_strdup (optarg
);
1593 case OPT_NEW_KEYFILE
:
1594 new_keyfile
= pwmd_strdup (optarg
);
1599 case OPT_LOCK_TIMEOUT
:
1600 lock_timeout
= strtol (optarg
, &p
, 10);
1608 case OPT_FORCE_SAVE
:
1609 save
= force_save
= 1;
1612 lcctype
= pwmd_strdup (optarg
);
1614 case OPT_LC_MESSAGES
:
1615 lcmessages
= pwmd_strdup (optarg
);
1618 timeout
= strtol (optarg
, &p
, 10);
1621 tries
= strtol (optarg
, &p
, 10);
1624 inquire
= escape (optarg
);
1626 case OPT_INQUIRE_FD
:
1627 inquirefd
= strtol (optarg
, &p
, 10);
1630 inquirefp
= fdopen (inquirefd
, "r");
1632 err (EXIT_FAILURE
, "%i", inquirefd
);
1635 case OPT_INQUIRE_FILE
:
1636 inquirefd
= open (optarg
, O_RDONLY
);
1637 if (inquirefd
== -1)
1638 err (EXIT_FAILURE
, "%s", optarg
);
1639 inquirefp
= fdopen (inquirefd
, "r");
1642 outfd
= strtol (optarg
, &p
, 10);
1645 outfp
= fdopen (outfd
, "w");
1647 err (EXIT_FAILURE
, "%i", outfd
);
1654 printf ("%s (pwmc)\n\n"
1655 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013\n"
1657 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1658 "Compile-time features:\n"
1659 #ifdef HAVE_LIBREADLINE
1674 #ifdef WITH_PINENTRY
1689 "\n", PACKAGE_STRING
, PACKAGE_BUGREPORT
);
1690 exit (EXIT_SUCCESS
);
1692 pinentry_path
= optarg
;
1695 usage (argv
[0], EXIT_SUCCESS
);
1699 case OPT_SIGN_KEYGRIP
:
1700 sign_keygrip
= optarg
;
1703 s2k_count
= strtoul (optarg
, &p
, 10);
1705 case OPT_ITERATIONS
:
1706 iterations
= strtoull (optarg
, &p
, 10);
1713 case OPT_NOPASSPHRASE
:
1719 case OPT_NO_PINENTRY
:
1722 #ifdef HAVE_LIBREADLINE
1723 case OPT_INTERACTIVE
:
1728 usage (argv
[0], EXIT_FAILURE
);
1733 fprintf (stderr
, N_("%s: invalid argument for option '--%s'\n"),
1734 argv
[0], long_opts
[opt_index
].name
);
1735 usage (argv
[0], EXIT_FAILURE
);
1744 knownhosts
= optarg
;
1748 inquire_line
= optarg
;
1763 clientname
= optarg
;
1766 usage (argv
[0], EXIT_FAILURE
);
1770 #ifdef HAVE_LIBREADLINE
1771 if (interactive
&& !isatty (STDIN_FILENO
))
1772 usage (argv
[0], EXIT_FAILURE
);
1773 else if (isatty (STDIN_FILENO
) && !inquire
&& !inquire_line
)
1777 filename
= argv
[optind
];
1779 gnutls_global_set_mem_functions (pwmd_malloc
, pwmd_malloc
, NULL
,
1780 pwmd_realloc
, pwmd_free
);
1783 rc
= pwmd_new (clientname
, &pwm
);
1787 pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TRIES
, tries
);
1789 fprintf (stderr
, N_("Connecting ...\n"));
1791 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1792 socktype
= is_remote_url (url
);
1793 if (socktype
!= PWMD_SOCKET_LOCAL
)
1796 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1797 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, connect_timeout
);
1802 if (socktype
== PWMD_SOCKET_SSH
)
1805 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_CB
, knownhost_cb
);
1809 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_DATA
, clientname
);
1813 if (!getenv ("SSH_AUTH_SOCK") || identity
)
1816 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_AGENT
, use_ssh_agent
);
1820 rc
= pwmd_connect (pwm
, url
, identity
, knownhosts
);
1826 rc
= pwmd_setopt (pwm
, PWMD_OPTION_TLS_VERIFY
, tls_verify
);
1830 rc
= pwmd_connect (pwm
, url
, clientcert
, clientkey
, cacert
, prio
,
1836 rc
= pwmd_connect (pwm
, url
);
1838 rc
= pwmd_connect (pwm
, url
);
1844 fprintf (stderr
, N_("Connected.\n"));
1847 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1848 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, socket_timeout
);
1855 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1856 "OPTION LOCK-TIMEOUT=%li", lock_timeout
);
1863 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCK_ON_OPEN
, 1);
1868 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, NULL
);
1874 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, timeout
);
1879 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
1883 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
,
1884 (local_pin
|| keyfile
|| new_keyfile
));
1890 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_PATH
, pinentry_path
);
1897 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DISPLAY
, display
);
1904 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TTY
, tty
);
1911 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TERM
, ttytype
);
1918 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_CTYPE
, lcctype
);
1925 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_MESSAGES
, lcmessages
);
1932 rc
= pwmd_setopt (pwm
, PWMD_OPTION_STATUS_CB
, status_msg_cb
);
1939 rc
= open_command (filename
);
1944 #ifdef HAVE_LIBREADLINE
1950 rc
= do_interactive ();
1958 struct inquire_s
*inq
= NULL
;
1960 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
1962 rc
= pwmd_command (pwm
, &result
, &len
, inquire_cb
, inq
, inquire
);
1968 fcntl (STDIN_FILENO
, F_SETFL
, O_NONBLOCK
);
1973 rc
= process_cmd ();
1978 n
= read (STDIN_FILENO
, command
, sizeof (command
));
1981 if (errno
== EAGAIN
)
1987 rc
= gpg_error_from_errno (errno
);
1998 if (!p
|| !*p
|| !strcasecmp (p
, "BYE"))
2002 struct inquire_s
*inq
= NULL
;
2003 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2006 rc
= parse_dotcommand (command
, &result
, &len
, inq
);
2016 fwrite (result
, 1, result
[len
- 1] == 0 ? len
- 1 : len
, outfp
);
2024 else if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
2025 (void) pwmd_command (pwm
, &result
, NULL
, NULL
, NULL
,
2026 "GETINFO last_error");
2028 #ifdef HAVE_LIBREADLINE
2031 memset (command
, 0, sizeof (command
));
2033 pwmd_free (keyfile
);
2034 pwmd_free (new_keyfile
);
2038 show_error (rc
, result
);
2041 if (connected
&& !quiet
)
2042 fprintf (stderr
, N_("Connection closed.\n"));
2044 exit (rc
? EXIT_FAILURE
: EXIT_SUCCESS
);