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 " change the passphrase of a data file\n"
984 " this help text\n"));
989 open_command (const char *line
)
991 struct inquire_s
*inq
= NULL
;
992 const char *filename
= line
;
995 while (filename
&& isspace (*filename
))
998 if (!filename
|| !*filename
)
1000 fprintf (stderr
, N_("Usage: .open <filename>\n"));
1001 return GPG_ERR_SYNTAX
;
1004 #ifdef HAVE_LIBREADLINE
1005 if (interactive
|| !quiet
)
1009 fprintf (stderr
, N_("Opening data file \"%s\" ...\n"), filename
);
1011 #ifdef HAVE_LIBREADLINE
1012 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1014 rc
= set_inquire (-1, NULL
, &inq
);
1020 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1022 rc
= pwmd_open (pwm
, filename
, inquire_cb
, inq
);
1028 set_command (const char *line
)
1031 char name
[256] = { 0 };
1032 char value
[512] = { 0 };
1035 const char *p
= line
;
1037 while (p
&& *p
&& isspace (*p
))
1040 namep
= parse_arg (p
, name
, sizeof (name
));
1041 if (!namep
|| !*namep
)
1043 fprintf (stderr
, N_("Usage: .set help | <name> [<value>]\n"));
1044 return GPG_ERR_SYNTAX
;
1047 p
+= strlen (namep
);
1048 while (p
&& *p
&& isspace (*p
))
1051 valuep
= parse_arg (p
, value
, sizeof (value
));
1053 if (!strcmp (name
, "keyfile") || !strcmp (name
, "new-keyfile"))
1055 int is_newkeyfile
= 1;
1059 if (!strcmp (name
, "keyfile"))
1064 pwmd_free (new_keyfile
);
1069 pwmd_free (keyfile
);
1073 p
+= strlen (valuep
);
1074 while (p
&& *p
&& isspace (*p
))
1077 valuep
= (char *) p
;
1080 memcpy (datafile
, value
, sizeof (datafile
));
1081 valuep
= parse_arg (p
, value
, sizeof (value
));
1082 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
, "KEYGRIP %s",
1084 if (gpg_err_code (rc
) == GPG_ERR_NOT_SUPPORTED
1085 || (gpg_err_source (rc
) == GPG_ERR_SOURCE_USER_1
1086 && gpg_err_code (rc
) == GPG_ERR_ENOENT
))
1098 new_keyfile
= pwmd_strdup (value
);
1100 keyfile
= pwmd_strdup (value
);
1105 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1106 "AGENT option pinentry-mode=loopback");
1110 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 1);
1111 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1114 else if (!local_pin
&& !no_pinentry
)
1118 pwmd_socket_type (pwm
, &t
);
1119 if (t
== PWMD_SOCKET_LOCAL
)
1121 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 0);
1122 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1126 else if (!strcmp (name
, "help"))
1130 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1131 "delimited. When no value is specified the option is unset.\n\n"
1132 "keyfile <datafile> [<filename>]\n"
1133 " set or unset the keyfile to be used when a passphrase is required (*)\n"
1135 "new-keyfile <datafile> [<filename>]\n"
1136 " set or unset the keyfile to be used when a new passphrase is required (*)\n"
1138 "* = the next protocol command will unset this value\n"
1142 rc
= GPG_ERR_UNKNOWN_OPTION
;
1148 save_command (const char *line
)
1150 struct inquire_s
*inq
= NULL
;
1153 #ifdef HAVE_LIBREADLINE
1154 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1156 rc
= set_inquire (-1, NULL
, &inq
);
1161 if (new_keyfile
|| keyfile
)
1162 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1164 rc
= pwmd_save (pwm
, line
, inquire_cb
, inq
);
1165 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1171 do_save_passwd_command (const char *line
, int save
)
1173 struct inquire_s
*inq
= NULL
;
1176 #ifdef HAVE_LIBREADLINE
1177 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1179 rc
= set_inquire (-1, NULL
, &inq
);
1184 if (new_keyfile
|| keyfile
)
1185 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1188 rc
= pwmd_save (pwm
, line
, inquire_cb
, inq
);
1190 rc
= pwmd_passwd (pwm
, line
, inquire_cb
, inq
);
1192 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1198 parse_dotcommand (const char *line
, char **result
,
1199 size_t * len
, struct inquire_s
*inq
)
1201 const char *p
= line
;
1204 if (!strncmp (p
, ".read", 5))
1205 rc
= read_command (p
+ 5, result
, len
);
1206 else if (!strncmp (p
, ".redir", 6))
1207 rc
= redir_command (p
+ 6);
1208 else if (!strncmp (p
, ".help", 5))
1209 rc
= help_command (p
+ 5);
1210 else if (!strncmp (p
, ".open", 5))
1211 rc
= open_command (p
+ 5);
1212 else if (!strncmp (p
, ".set", 4))
1213 rc
= set_command (p
+ 4);
1214 else if (!strncmp (p
, ".save", 5))
1215 rc
= do_save_passwd_command (p
+ 5, 1);
1216 else if (!strncmp (p
, ".passwd", 7))
1217 rc
= do_save_passwd_command (p
+ 7, 0);
1220 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, line
);
1221 #ifdef HAVE_LIBREADLINE
1225 pwmd_free (keyfile
);
1226 pwmd_free (new_keyfile
);
1227 keyfile
= new_keyfile
= NULL
;
1228 #ifdef HAVE_LIBREADLINE
1236 #ifdef HAVE_LIBREADLINE
1241 struct inquire_s
*inq
= NULL
;
1244 rc
= process_cmd ();
1248 rc
= set_inquire (STDIN_FILENO
, NULL
, &inq
);
1253 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1255 rl_event_hook
= &interactive_hook
;
1256 rl_set_keyboard_input_timeout (100000);
1261 char *result
= NULL
;
1265 line
= readline ("pwm> ");
1266 if (interactive_error
)
1268 rc
= interactive_error
;
1278 if (gpg_err_code (rc
) != GPG_ERR_CANCELED
&&
1279 gpg_err_code (rc
) != GPG_ERR_EOF
)
1280 fprintf (stderr
, "ERR %i: %s\n", rc
, gpg_strerror (rc
));
1290 #ifdef HAVE_READLINE_HISTORY
1294 rc
= parse_dotcommand (line
, &result
, &len
, inq
);
1300 if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
1301 (void) pwmd_command (pwm
, &tmp
, NULL
, NULL
, NULL
,
1302 "GETINFO last_error");
1304 show_error (rc
, tmp
);
1307 else if (result
&& len
)
1308 printf ("%s%s", result
, result
[len
- 1] != '\n' ? "\n" : "");
1319 itoa (long long int n
)
1321 static char buf
[64];
1323 snprintf (buf
, sizeof (buf
), "%llu", n
);
1331 #ifdef HAVE_LIBREADLINE
1334 if (!force_save
&& interactive
)
1339 fprintf (stderr
, "\n");
1345 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1346 p
= fgets (buf
, sizeof (buf
), stdin
);
1360 return GPG_ERR_CANCELED
;
1364 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1365 "CLEARCACHE %s", filename
);
1369 interactive_hook ();
1385 if (save
&& !filename
)
1389 ("No filename was specified on the command line. Aborting.\n"));
1390 return GPG_ERR_CANCELED
;
1393 if (save
&& filename
)
1396 pwmd_strdup_printf ("%s%s %s%s %s %s%s %s%s %s %s %s --s2k-count=%lu",
1397 keygrip
? "--keygrip=" : "",
1398 keygrip
? keygrip
: "",
1399 sign_keygrip
? "--sign-keygrip=" : "",
1400 sign_keygrip
? sign_keygrip
: "",
1401 no_passphrase
? "--no-passphrase" : "",
1402 cipher
? "--cipher=" : "", cipher
? cipher
: "",
1403 iterations_arg
? "--cipher-iterations=" : "",
1404 iterations_arg
? itoa (iterations
) : "",
1405 no_gpg_agent
? "--no-agent" : "",
1406 keyparams
? "--inquire-keyparam" : "",
1407 force_save
? "--reset" : "", s2k_count
);
1409 #ifdef HAVE_LIBREADLINE
1410 if (!quiet
|| interactive
)
1416 fprintf (stderr
, "\n");
1417 fprintf (stderr
, N_("Saving changes ...\n"));
1420 rc
= save_command (args
);
1423 no_passphrase
= 0; // reset to avoid usage error on the next SAVE
1426 #ifdef HAVE_LIBREADLINE
1428 return rc
? rc
: quit
? 0 : GPG_ERR_CANCELED
;
1435 main (int argc
, char *argv
[])
1440 char command
[ASSUAN_LINELENGTH
], *p
= NULL
;
1441 char *result
= NULL
;
1443 char *pinentry_path
= NULL
;
1444 char *display
= NULL
, *tty
= NULL
, *ttytype
= NULL
;
1445 char *lcctype
= NULL
, *lcmessages
= NULL
;
1446 int outfd
= STDOUT_FILENO
;
1447 FILE *outfp
= stdout
;
1448 FILE *inquirefp
= stdin
;
1449 int show_status
= 1;
1450 char *clientname
= "pwmc";
1451 char *inquire
= NULL
;
1452 char *inquire_line
= NULL
;
1455 int use_ssh_agent
= 1;
1456 char *knownhosts
= NULL
;
1457 char *identity
= NULL
;
1460 char *cacert
= NULL
;
1461 char *clientcert
= NULL
;
1462 char *clientkey
= NULL
;
1465 char *tls_fingerprint
= NULL
;
1467 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1468 pwmd_socket_t socktype
;
1469 long socket_timeout
= 300;
1470 int connect_timeout
= 120;
1472 int lock_on_open
= 1;
1473 long lock_timeout
= 50;
1475 /* The order is important. */
1478 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1479 OPT_SOCKET_TIMEOUT
, OPT_CONNECT_TIMEOUT
,
1482 OPT_USE_SSH_AGENT
, OPT_IDENTITY
, OPT_KNOWNHOSTS
,
1485 OPT_CACERT
, OPT_CLIENTCERT
, OPT_CLIENTKEY
, OPT_PRIORITY
, OPT_VERIFY
,
1488 OPT_URL
, OPT_LOCAL
, OPT_FORCE_SAVE
, OPT_TTYNAME
, OPT_TTYTYPE
,
1489 OPT_DISPLAY
, OPT_LC_CTYPE
, OPT_LC_MESSAGES
, OPT_TIMEOUT
, OPT_TRIES
,
1490 OPT_PINENTRY
, OPT_KEYFILE
, OPT_NEW_KEYFILE
, OPT_NOLOCK
,
1491 OPT_LOCK_TIMEOUT
, OPT_SAVE
, OPT_OUTPUT_FD
, OPT_INQUIRE
,
1492 OPT_INQUIRE_FD
, OPT_INQUIRE_FILE
, OPT_INQUIRE_LINE
, OPT_NO_STATUS
,
1493 OPT_NAME
, OPT_VERSION
, OPT_HELP
, OPT_KEYGRIP
, OPT_SIGN_KEYGRIP
,
1494 OPT_NOPASSPHRASE
, OPT_CIPHER
, OPT_KEYPARAMS
, OPT_NO_PINENTRY
,
1495 OPT_S2K_COUNT
, OPT_ITERATIONS
, OPT_QUIET
, OPT_NO_GPG_AGENT
,
1496 #ifdef HAVE_LIBREADLINE
1500 const struct option long_opts
[] = {
1501 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1502 {"socket-timeout", 1, 0, 0},
1503 {"connect-timeout", 1, 0, 0},
1507 {"no-ssh-agent", 0, 0, 0},
1508 {"identity", 1, 0, 'i'},
1509 {"knownhosts", 1, 0, 'k'},
1512 {"ca-cert", 1, 0, 0},
1513 {"client-cert", 1, 0, 0},
1514 {"client-key", 1, 0, 0},
1515 {"tls-priority", 1, 0, 0},
1516 {"tls-verify", 0, 0, 0},
1517 {"tls-fingerprint", 1, 0, 0},
1520 {"local-pinentry", 0, 0},
1521 {"force-save", 0, 0},
1522 {"ttyname", 1, 0, 'y'},
1523 {"ttytype", 1, 0, 't'},
1524 {"display", 1, 0, 'd'},
1525 {"lc-ctype", 1, 0, 0},
1526 {"lc-messages", 1, 0, 0},
1527 {"timeout", 1, 0, 0},
1529 {"pinentry", 1, 0, 0},
1530 {"key-file", 1, 0, 0},
1531 {"new-key-file", 1, 0, 0},
1532 {"no-lock", 0, 0, 0},
1533 {"lock-timeout", 1, 0, 0},
1534 {"save", 0, 0, 'S'},
1535 {"output-fd", 1, 0, 0},
1536 {"inquire", 1, 0, 0},
1537 {"inquire-fd", 1, 0, 0},
1538 {"inquire-file", 1, 0, 0},
1539 {"inquire-line", 1, 0, 'L'},
1540 {"no-status", 0, 0, 0},
1541 {"name", 1, 0, 'n'},
1542 {"version", 0, 0, 0},
1544 {"keygrip", 1, 0, 0},
1545 {"sign-keygrip", 1, 0, 0},
1546 {"no-passphrase", 0, 0, 0},
1547 {"cipher", 1, 0, 0},
1548 {"key-params", 1, 0, 0},
1549 {"no-pinentry", 0, 0, 0},
1550 {"s2k-count", 1, 0, 0},
1551 {"cipher-iterations", 1, 0, 0},
1553 {"no-gpg-agent", 0, 0, 0},
1554 #ifdef HAVE_LIBREADLINE
1555 {"interactive", 0, 0},
1560 const char *optstring
= "L:y:t:d:P:I:Sn:i:k:";
1562 const char *optstring
= "L:y:t:d:P:I:Sn:";
1567 setlocale (LC_ALL
, "");
1568 bindtextdomain ("libpwmd", LOCALEDIR
);
1571 tries
= DEFAULT_PIN_TRIES
;
1572 inquirefd
= STDIN_FILENO
;
1575 getopt_long (argc
, argv
, optstring
, long_opts
, &opt_index
)) != -1)
1579 /* Handle long options without a short option part. */
1583 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1584 case OPT_SOCKET_TIMEOUT
:
1585 socket_timeout
= strtol (optarg
, &p
, 10);
1587 case OPT_CONNECT_TIMEOUT
:
1588 connect_timeout
= strtol (optarg
, &p
, 10);
1592 case OPT_USE_SSH_AGENT
:
1600 case OPT_CLIENTCERT
:
1601 clientcert
= optarg
;
1613 tls_fingerprint
= optarg
;
1616 case OPT_NO_GPG_AGENT
:
1623 keyfile
= pwmd_strdup (optarg
);
1625 case OPT_NEW_KEYFILE
:
1626 new_keyfile
= pwmd_strdup (optarg
);
1631 case OPT_LOCK_TIMEOUT
:
1632 lock_timeout
= strtol (optarg
, &p
, 10);
1640 case OPT_FORCE_SAVE
:
1641 save
= force_save
= 1;
1644 lcctype
= pwmd_strdup (optarg
);
1646 case OPT_LC_MESSAGES
:
1647 lcmessages
= pwmd_strdup (optarg
);
1650 timeout
= strtol (optarg
, &p
, 10);
1653 tries
= strtol (optarg
, &p
, 10);
1656 inquire
= escape (optarg
);
1658 case OPT_INQUIRE_FD
:
1659 inquirefd
= strtol (optarg
, &p
, 10);
1662 inquirefp
= fdopen (inquirefd
, "r");
1664 err (EXIT_FAILURE
, "%i", inquirefd
);
1667 case OPT_INQUIRE_FILE
:
1668 inquirefd
= open (optarg
, O_RDONLY
);
1669 if (inquirefd
== -1)
1670 err (EXIT_FAILURE
, "%s", optarg
);
1671 inquirefp
= fdopen (inquirefd
, "r");
1674 outfd
= strtol (optarg
, &p
, 10);
1677 outfp
= fdopen (outfd
, "w");
1679 err (EXIT_FAILURE
, "%i", outfd
);
1686 printf ("%s (pwmc)\n\n"
1687 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013\n"
1689 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1690 "Compile-time features:\n"
1691 #ifdef HAVE_LIBREADLINE
1706 #ifdef WITH_PINENTRY
1721 "\n", PACKAGE_STRING
, PACKAGE_BUGREPORT
);
1722 exit (EXIT_SUCCESS
);
1724 pinentry_path
= optarg
;
1727 usage (argv
[0], EXIT_SUCCESS
);
1731 case OPT_SIGN_KEYGRIP
:
1732 sign_keygrip
= optarg
;
1735 s2k_count
= strtoul (optarg
, &p
, 10);
1737 case OPT_ITERATIONS
:
1738 iterations
= strtoull (optarg
, &p
, 10);
1745 case OPT_NOPASSPHRASE
:
1751 case OPT_NO_PINENTRY
:
1754 #ifdef HAVE_LIBREADLINE
1755 case OPT_INTERACTIVE
:
1760 usage (argv
[0], EXIT_FAILURE
);
1765 fprintf (stderr
, N_("%s: invalid argument for option '--%s'\n"),
1766 argv
[0], long_opts
[opt_index
].name
);
1767 usage (argv
[0], EXIT_FAILURE
);
1776 knownhosts
= optarg
;
1780 inquire_line
= optarg
;
1795 clientname
= optarg
;
1798 usage (argv
[0], EXIT_FAILURE
);
1802 #ifdef HAVE_LIBREADLINE
1803 if (interactive
&& !isatty (STDIN_FILENO
))
1804 usage (argv
[0], EXIT_FAILURE
);
1805 else if (isatty (STDIN_FILENO
) && !inquire
&& !inquire_line
)
1809 filename
= argv
[optind
];
1811 gnutls_global_set_mem_functions (pwmd_malloc
, pwmd_malloc
, NULL
,
1812 pwmd_realloc
, pwmd_free
);
1815 rc
= pwmd_new (clientname
, &pwm
);
1819 pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TRIES
, tries
);
1821 fprintf (stderr
, N_("Connecting ...\n"));
1823 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1824 socktype
= is_remote_url (url
);
1825 if (socktype
!= PWMD_SOCKET_LOCAL
)
1828 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1829 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, connect_timeout
);
1834 if (socktype
== PWMD_SOCKET_SSH
)
1837 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_CB
, knownhost_cb
);
1841 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_DATA
, clientname
);
1845 if (!getenv ("SSH_AUTH_SOCK") || identity
)
1848 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_AGENT
, use_ssh_agent
);
1852 rc
= pwmd_connect (pwm
, url
, identity
, knownhosts
);
1858 rc
= pwmd_setopt (pwm
, PWMD_OPTION_TLS_VERIFY
, tls_verify
);
1862 rc
= pwmd_connect (pwm
, url
, clientcert
, clientkey
, cacert
, prio
,
1868 rc
= pwmd_connect (pwm
, url
);
1870 rc
= pwmd_connect (pwm
, url
);
1876 fprintf (stderr
, N_("Connected.\n"));
1879 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1880 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, socket_timeout
);
1887 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1888 "OPTION LOCK-TIMEOUT=%li", lock_timeout
);
1895 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCK_ON_OPEN
, 1);
1900 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, NULL
);
1906 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, timeout
);
1911 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
1915 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
,
1916 (local_pin
|| keyfile
|| new_keyfile
));
1922 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_PATH
, pinentry_path
);
1929 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DISPLAY
, display
);
1936 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TTY
, tty
);
1943 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TERM
, ttytype
);
1950 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_CTYPE
, lcctype
);
1957 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_MESSAGES
, lcmessages
);
1964 rc
= pwmd_setopt (pwm
, PWMD_OPTION_STATUS_CB
, status_msg_cb
);
1971 rc
= open_command (filename
);
1976 #ifdef HAVE_LIBREADLINE
1982 rc
= do_interactive ();
1990 struct inquire_s
*inq
= NULL
;
1992 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
1994 rc
= pwmd_command (pwm
, &result
, &len
, inquire_cb
, inq
, inquire
);
2000 fcntl (STDIN_FILENO
, F_SETFL
, O_NONBLOCK
);
2005 rc
= process_cmd ();
2010 n
= read (STDIN_FILENO
, command
, sizeof (command
));
2013 if (errno
== EAGAIN
)
2019 rc
= gpg_error_from_errno (errno
);
2030 if (!p
|| !*p
|| !strcasecmp (p
, "BYE"))
2034 struct inquire_s
*inq
= NULL
;
2035 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2038 rc
= parse_dotcommand (command
, &result
, &len
, inq
);
2048 fwrite (result
, 1, result
[len
- 1] == 0 ? len
- 1 : len
, outfp
);
2056 else if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
2057 (void) pwmd_command (pwm
, &result
, NULL
, NULL
, NULL
,
2058 "GETINFO last_error");
2060 #ifdef HAVE_LIBREADLINE
2063 memset (command
, 0, sizeof (command
));
2065 pwmd_free (keyfile
);
2066 pwmd_free (new_keyfile
);
2070 show_error (rc
, result
);
2073 if (connected
&& !quiet
)
2074 fprintf (stderr
, N_("Connection closed.\n"));
2076 exit (rc
? EXIT_FAILURE
: EXIT_SUCCESS
);