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
;
95 static char *password
;
97 static char *new_keyfile
;
98 static unsigned long s2k_count
;
99 static uint64_t iterations
;
100 static int iterations_arg
;
102 static int local_pin
;
103 static int inquirefd
;
105 static int no_gpg_agent
;
112 size_t size
; // from stat(2).
116 static gpg_error_t
finalize ();
117 static gpg_error_t
set_inquire (int fd
, const char *line
,
118 struct inquire_s
**result
);
119 static gpg_error_t
parse_dotcommand (const char *line
, char **result
,
120 size_t * len
, struct inquire_s
*inq
);
121 static gpg_error_t
open_command (const char *line
);
123 static gpg_error_t
get_password (char **result
, pwmd_pinentry_t w
, int echo
);
127 show_error (gpg_error_t rc
, const char *str
)
129 fprintf (stderr
, "ERR %i: %s%s%s%s", rc
, gpg_strerror (rc
),
130 str
? ": " : "", str
? str
: "", str
? "" : "\n");
134 usage (const char *pn
, int status
)
136 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
137 N_("Read a PWMD protocol command from standard input.\n\n"
138 "Usage: pwmc [options] [file]\n"
140 " a url string to connect to (see below)\n"
141 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
142 " --connect-timeout <seconds>\n"
143 " seconds before connecting to a remote host fails (120)\n"
144 " --socket-timeout <seconds>\n"
145 " seconds before a remote command fails (0=disabled, default=300)\n"
148 " --ca-cert <filename>\n"
149 " certificate authority (CA) used to sign the server cert\n"
150 " --client-cert <filename>\n"
151 " client certificate to use for authentication\n"
152 " --client-key <filename>\n"
153 " key file used to protect the client certificate\n"
154 " --tls-priority <string>\n"
155 " compression, cipher and hash algorithm string (SECURE256)\n"
157 " verify the hostname against the server certificate\n"
158 " --tls-fingerprint <string>\n"
159 " a SHA-1 hash of the server fingerprint to verify against\n"
163 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
164 " --identity, -i <filename>\n"
165 " the ssh identity file to use for authentication\n"
166 " --knownhosts, -k <filename>\n"
167 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
170 " do not lock the data file upon opening it\n"
171 " --lock-timeout <N>\n"
172 " time in tenths of a second to wait for a locked data file\n"
173 " --name, -n <string>\n"
174 " set the client name\n"
175 " --pinentry <path>\n"
176 " the full path to the pinentry binary (server default)\n"
177 " --local-pinentry\n"
178 " force using a local pinentry\n"
180 " disable pinentry both remotely and locally\n"
181 " --ttyname, -y <path>\n"
182 " tty that pinentry will use\n"
183 " --ttytype, -t <string>\n"
184 " pinentry terminal type (default is $TERM)\n"
186 " pinentry display (default is $DISPLAY)\n"
187 " --lc-ctype <string>\n"
188 " locale setting for pinentry\n"
189 " --lc-messages <string>\n"
190 " locale setting for pinentry\n"
192 " number of pinentry tries before failing (3)\n"
193 " --timeout <seconds>\n"
194 " pinentry timeout\n"
195 " --inquire <COMMAND>\n"
196 " the specified command (with any options) uses a server inquire while\n"
197 " command data is read via the inquire file descriptor (stdin)\n"
198 " --inquire-line, -L <STRING>\n"
199 " the initial line to send (i.e., element path) before the inquire data\n"
200 " --inquire-fd <FD>\n"
201 " read inquire data from the specified file descriptor (stdin)\n"
202 " --inquire-file <filename>\n"
203 " read inquire data from the specified filename\n"
204 " --output-fd <FD>\n"
205 " redirect command output to the specified file descriptor\n"
207 " send the SAVE command before exiting\n"
209 " like --save but always ask for a passphrase\n"
211 " do not require a passphrase when saving a new file\n"
213 " disable use of gpg-agent when saving to a new file\n"
214 " --key-file <filename>\n"
215 " obtain the passphrase from the specified filename\n"
216 " --new-key-file <filename>\n"
217 " obtain the passphrase to save with from the specified filename\n"
218 " --cipher <string>\n"
219 " the cipher to use when saving (see pwmd(1))\n"
220 " --cipher-iterations <N>\n"
221 " the number of times to encrypt the XML data (N+1)\n"
222 " --key-params <string>\n"
223 " the key parameters to use when saving a new file (pwmd default)\n"
224 " --keygrip <string>\n"
225 " the hex string of the keygrip to save to\n"
226 " --sign-keygrip <string>\n"
227 " the hex string of the keygrip to sign with\n"
229 " the number of times to hash the passphrase for a new file\n"
231 " disable showing of status messages from the server\n"
233 " disable showing of extra messages (implies --no-status)\n"
234 #ifdef HAVE_LIBREADLINE
236 " use a shell like interface to pwmd (allows more than one command)\n"
240 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
242 "An optional url may be in the form of:\n"
243 " --url /path/to/socket\n"
244 " --url file://[path/to/socket]\n"
247 " --url ssh[46]://[username@]hostname[:port]\n"
248 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
252 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
253 " --client-key filename\n"
260 inquire_cb (void *user
, const char *keyword
, gpg_error_t rc
,
261 char **data
, size_t * size
)
263 struct inquire_s
*inq
= user
;
265 int is_newpassword
= 0;
273 if (!strcmp (keyword
, "PASSPHRASE"))
275 else if (!strcmp (keyword
, "NEW_PASSPHRASE"))
277 #ifdef HAVE_LIBREADLINE
278 else if (!strcmp (keyword
, "KEYPARAM") && !interactive
)
281 else if (!strcmp (keyword
, "KEYPARAM"))
284 if (!keyparams
|| !*keyparams
)
285 return gpg_error (GPG_ERR_INV_PARAMETER
);
288 *size
= strlen (keyparams
);
289 return gpg_error (GPG_ERR_EOF
);
292 if ((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
))
294 int fd
= open (is_password
? keyfile
: new_keyfile
, O_RDONLY
);
298 fprintf (stderr
, "%s: %s\n", is_newpassword
? new_keyfile
: keyfile
,
300 return gpg_error_from_syserror ();
303 rc
= set_inquire (fd
, NULL
, &inq
);
311 fprintf (stderr
, N_("Using keyfile '%s' as %s.\n"),
312 is_newpassword
? new_keyfile
: keyfile
, keyword
);
314 if (!new_keyfile
|| is_newpassword
)
318 pwmd_socket_type (pwm
, &t
);
319 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
320 if (!no_pinentry
&& t
== PWMD_SOCKET_LOCAL
)
321 pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 0);
324 else if (is_password
&& !keyfile
)
328 rc
= pwmd_password (pwm
, keyword
, &tmp
, &inq
->len
);
329 if (rc
&& gpg_err_code (rc
) != GPG_ERR_EOF
)
332 pwmd_free (inq
->line
);
336 return gpg_error (GPG_ERR_EOF
);
338 #ifdef HAVE_LIBREADLINE
339 else if (!inq
->header
&& interactive
)
343 ("Press CTRL-D to send the current line. Press twice to end. %s:\n"),
349 /* The first part of the command data. */
355 return inq
->fd
== -1 ? gpg_error (GPG_ERR_EOF
) : 0;
358 *size
= read (inq
->fd
, inq
->line
, ASSUAN_LINELENGTH
);
362 return gpg_error (gpg_error_from_syserror ());
366 else if (inq
->fd
!= STDIN_FILENO
&& (is_newpassword
|| is_password
))
374 if (((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
))
375 && *size
== inq
->size
)
376 return gpg_error (GPG_ERR_EOF
);
378 return *size
? 0 : gpg_error (GPG_ERR_EOF
);
382 status_msg_cb (void *data
, const char *line
)
384 char *p
= strchr (line
, ' ');
386 if (!strcmp (line
, "KEEPALIVE"))
389 if (*line
!= '#' && p
&& strchr (p
, ' ') && *++p
)
391 char *p1
= strchr (p
, ' ');
392 int a
= strtol (p
, NULL
, 10);
394 if (isdigit (*p
) && p1
)
396 int b
= strtol (p1
, NULL
, 10);
398 int t
= a
&& b
? a
* 100 / b
: 0;
400 strncpy (l
, line
, strlen (line
) - strlen (p
) - 1);
401 fprintf (stderr
, "\r%s %i/%i %i%%%s", l
, a
, b
, t
,
408 fprintf (stderr
, "%s\n", line
);
410 #ifdef HAVE_LIBREADLINE
419 return pwmd_process (pwm
);
424 get_password (char **result
, pwmd_pinentry_t w
, int echo
)
426 char buf
[LINE_MAX
] = { 0 }, *p
;
427 struct termios told
, tnew
;
432 if (!isatty (STDIN_FILENO
))
434 fprintf (stderr
, N_("Input is not from a terminal! Failing.\n"));
435 return GPG_ERR_ENOTTY
;
440 if (tcgetattr (STDIN_FILENO
, &told
) == -1)
441 return gpg_error_from_syserror ();
443 memcpy (&tnew
, &told
, sizeof (struct termios
));
444 tnew
.c_lflag
&= ~(ECHO
);
445 tnew
.c_lflag
|= ICANON
| ECHONL
;
447 if (tcsetattr (STDIN_FILENO
, TCSANOW
, &tnew
) == -1)
451 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
452 return gpg_error_from_errno (n
);
458 case PWMD_PINENTRY_OPEN
:
459 fprintf (stderr
, N_("Password for %s: "), filename
);
461 case PWMD_PINENTRY_OPEN_FAILED
:
462 fprintf (stderr
, N_("Invalid password. Password for %s: "), filename
);
464 case PWMD_PINENTRY_SAVE
:
465 fprintf (stderr
, N_("New password for %s: "), filename
);
467 case PWMD_PINENTRY_SAVE_CONFIRM
:
468 fprintf (stderr
, N_("Confirm password: "));
474 if ((p
= fgets (buf
, sizeof (buf
), stdin
)) == NULL
)
476 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
481 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
486 return GPG_ERR_CANCELED
;
489 p
[strlen (p
) - 1] = 0;
493 key
= pwmd_strdup_printf ("%s", p
);
494 memset (&buf
, 0, sizeof (buf
));
497 return GPG_ERR_ENOMEM
;
505 knownhost_cb (void *data
, const char *host
, const char *key
, size_t len
)
509 pwmd_strdup_printf (N_
510 ("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?"),
511 (char *) data
, host
, host
);
513 if (no_pinentry
&& !isatty (STDIN_FILENO
))
515 fprintf (stderr
, N_("Input is not from a terminal! Failing.\n"));
517 return GPG_ERR_ENOTTY
;
519 else if (no_pinentry
)
521 for (char *p
= buf
, len
= 0; *p
; p
++, len
++)
530 while (!isspace (*(--p
)));
537 fprintf (stderr
, "%s\n\n", buf
);
544 fprintf (stderr
, N_("Trust this connection [y/N]: "));
546 rc
= get_password (&result
, PWMD_PINENTRY_CONFIRM
, 1);
551 if (!result
|| !*result
|| *result
== 'n' || *result
== 'N')
553 if (result
&& *result
)
556 return GPG_ERR_NOT_CONFIRMED
;
559 if ((*result
== 'y' || *result
== 'Y') && *(result
+ 1) == 0)
568 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, buf
);
574 return pwmd_getpin (pwm
, NULL
, NULL
, NULL
, PWMD_PINENTRY_CONFIRM
);
578 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
580 is_remote_url (const char *str
)
583 return PWMD_SOCKET_LOCAL
;
586 if (strstr (str
, "ssh://") || strstr (str
, "ssh4://")
587 || strstr (str
, "ssh6://"))
588 return PWMD_SOCKET_SSH
;
592 if (strstr (str
, "tls://") || strstr (str
, "tls4://")
593 || strstr (str
, "tls6://"))
594 return PWMD_SOCKET_TLS
;
597 return PWMD_SOCKET_LOCAL
;
602 escape (const char *str
)
605 char *buf
= pwmd_malloc (ASSUAN_LINELENGTH
+ 1), *b
= buf
;
608 for (p
= str
; *p
; p
++, len
++)
610 if (len
== ASSUAN_LINELENGTH
)
654 free_inquire (struct inquire_s
*inq
)
659 pwmd_free (inq
->line
);
661 if (inq
->fd
!= -1 && inq
->fd
!= STDIN_FILENO
)
667 /* When *result is not NULL it is updated to the new values and not
670 set_inquire (int fd
, const char *line
, struct inquire_s
**result
)
672 struct inquire_s inq
= { 0 };
673 struct stat st
= { 0 };
678 if (fstat (fd
, &st
) == -1)
679 return gpg_error_from_syserror ();
681 inq
.size
= st
.st_size
;
685 inq
.line
= pwmd_calloc (1, ASSUAN_LINELENGTH
);
687 return GPG_ERR_ENOMEM
;
691 char *s
= escape (line
);
695 pwmd_free (inq
.line
);
696 return GPG_ERR_ENOMEM
;
699 if (strlen (s
) >= ASSUAN_LINELENGTH
)
701 pwmd_free (inq
.line
);
703 return GPG_ERR_LINE_TOO_LONG
;
706 strncpy (inq
.line
, s
, ASSUAN_LINELENGTH
- 1);
707 inq
.len
= strlen (s
);
711 rc
= pwmd_setopt (pwm
, PWMD_OPTION_INQUIRE_TOTAL
,
712 st
.st_size
? st
.st_size
+ strlen (inq
.line
) : 0);
715 pwmd_free (inq
.line
);
720 *result
= pwmd_malloc (sizeof (struct inquire_s
));
723 if ((*result
)->fd
!= -1 && (*result
)->fd
!= STDIN_FILENO
)
724 close ((*result
)->fd
);
726 pwmd_free ((*result
)->line
);
727 (*result
)->line
= NULL
;
732 memcpy (*result
, &inq
, sizeof (struct inquire_s
));
733 memset (&inq
, 0, sizeof (struct inquire_s
));
737 #ifdef HAVE_LIBREADLINE
739 interactive_hook (void)
741 interactive_error
= process_cmd ();
743 if (interactive_error
)
744 rl_event_hook
= NULL
;
754 ("------------------------------------------------------------------------------\n"
755 "Elements are TAB delimited. Press CTRL-V then TAB to insert from the prompt.\n"
757 "Type HELP for protocol commands. Type .help for pwmc commands. Press CTRL-D\n"
759 "------------------------------------------------------------------------------\n"));
764 parse_arg (const char *src
, char *dst
, size_t len
)
770 for (; s
&& *s
&& *s
!= ' ' && n
< len
; s
++, n
++)
778 parse_opt (char **line
, const char *opt
, gpg_error_t
* rc
)
780 static char result
[ASSUAN_LINELENGTH
] = { 0 }, *r
= result
;
782 char *s
= strstr (*line
, opt
);
791 size_t rlen
= strlen (opt
);
795 while (*p
&& *p
== ' ')
801 for (; *p
&& len
< sizeof (result
) - 1; p
++, rlen
++)
803 if (isspace (*p
) && !quote
)
806 if (*p
== '\"' && lastc
!= '\\')
819 if (len
>= sizeof (result
) - 1)
820 *rc
= GPG_ERR_LINE_TOO_LONG
;
825 while (*p
&& *p
== ' ')
836 read_command (const char *line
, char **result
, size_t * len
)
840 char filebuf
[ASSUAN_LINELENGTH
];
841 char *filename
= NULL
;
842 struct inquire_s
*inq
= NULL
;
843 char *p
= (char *) line
;
844 const char *prefix
= parse_opt (&p
, "--prefix", &rc
);
853 while (*p
&& isspace (*p
))
856 filename
= parse_arg (p
, filebuf
, sizeof (filebuf
));
857 if (filename
&& *filename
)
859 p
+= strlen (filename
) + 1;
861 while (*p
&& isspace (*p
))
873 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
876 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\" = \")\n"));
880 fd
= open (filename
, O_RDONLY
);
882 return gpg_error_from_syserror ();
884 rc
= set_inquire (fd
, prefix
&& *prefix
? prefix
: NULL
, &inq
);
892 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, p
);
898 redir_command (const char *line
)
900 const char *p
= line
;
902 gpg_error_t rc
= GPG_ERR_SYNTAX
;
903 char filebuf
[ASSUAN_LINELENGTH
];
904 char *filename
= NULL
;
905 struct inquire_s
*inq
= NULL
;
911 filename
= parse_arg (p
, filebuf
, sizeof (filebuf
));
912 if (filename
&& *filename
)
914 p
+= strlen (filename
) + 1;
916 while (*p
&& isspace (*p
))
926 fprintf (stderr
, N_("Usage: .redir <filename> <command> [args]\n"));
930 fd
= open (filename
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600);
932 return gpg_error_from_syserror ();
934 #ifdef HAVE_LIBREADLINE
935 rc
= set_inquire (interactive
? STDIN_FILENO
: inquirefd
, NULL
, &inq
);
937 rc
= set_inquire (inquirefd
, NULL
, &inq
);
945 rc
= parse_dotcommand (p
, &result
, &len
, inq
);
946 if (!rc
&& result
&& len
--)
947 { // null byte which is always appended
948 if (write (fd
, result
, len
) != len
)
949 rc
= GPG_ERR_TOO_SHORT
;
959 help_command (const char *line
)
962 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
963 " .redir <filename> <command>\n"
964 " redirect the output of a command to the specified file\n"
966 " .open <filename>\n"
967 " open the specified filename losing any changes to the current one\n"
969 " .read [--prefix <string>] <filename> <command> [args]\n"
970 " obtain data from the specified filename for an inquire command\n"
972 " .set help | <name> [<value>]\n"
973 " set option <name> to <value>\n"
976 " write changes of the file to disk\n"
979 " this help text\n"));
984 open_command (const char *line
)
986 struct inquire_s
*inq
= NULL
;
987 const char *filename
= line
;
990 while (filename
&& isspace (*filename
))
993 if (!filename
|| !*filename
)
995 fprintf (stderr
, N_("Usage: .open <filename>\n"));
996 return GPG_ERR_SYNTAX
;
999 #ifdef HAVE_LIBREADLINE
1000 if (interactive
|| !quiet
)
1004 fprintf (stderr
, N_("Opening data file \"%s\" ...\n"), filename
);
1006 #ifdef HAVE_LIBREADLINE
1007 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1009 rc
= set_inquire (-1, NULL
, &inq
);
1015 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1017 #ifdef HAVE_LIBREADLINE
1018 // For safety. This file may be a different one. Make the user set it
1022 pwmd_free (new_keyfile
);
1027 rc
= pwmd_open (pwm
, filename
, inquire_cb
, inq
);
1033 set_command (const char *line
)
1036 char name
[256] = { 0 };
1037 char value
[512] = { 0 };
1040 const char *p
= line
;
1042 while (p
&& *p
&& isspace (*p
))
1045 namep
= parse_arg (p
, name
, sizeof (name
));
1046 if (!namep
|| !*namep
)
1048 fprintf (stderr
, N_("Usage: .set help | <name> [<value>]\n"));
1049 return GPG_ERR_SYNTAX
;
1052 p
+= strlen (namep
);
1053 while (p
&& *p
&& isspace (*p
))
1056 valuep
= parse_arg (p
, value
, sizeof (value
));
1058 if (!strcmp (name
, "keyfile") || !strcmp (name
, "new-keyfile"))
1060 int is_newkeyfile
= 1;
1064 if (!strcmp (name
, "keyfile"))
1069 pwmd_free (new_keyfile
);
1074 pwmd_free (keyfile
);
1078 p
+= strlen (valuep
);
1079 while (p
&& *p
&& isspace (*p
))
1082 valuep
= (char *) p
;
1085 memcpy (datafile
, value
, sizeof (datafile
));
1086 valuep
= parse_arg (p
, value
, sizeof (value
));
1087 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
, "KEYGRIP %s",
1089 if (gpg_err_code (rc
) == GPG_ERR_NOT_SUPPORTED
1090 || (gpg_err_source (rc
) == GPG_ERR_SOURCE_USER_1
1091 && gpg_err_code (rc
) == GPG_ERR_ENOENT
))
1103 new_keyfile
= pwmd_strdup (value
);
1105 keyfile
= pwmd_strdup (value
);
1110 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1111 "AGENT option pinentry-mode=loopback");
1115 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 1);
1116 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1119 else if (!local_pin
&& !no_pinentry
)
1123 pwmd_socket_type (pwm
, &t
);
1124 if (t
== PWMD_SOCKET_LOCAL
)
1126 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 0);
1127 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1131 else if (!strcmp (name
, "help"))
1135 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1136 "delimited. When no value is specified the option is unset.\n\n"
1137 "keyfile <datafile> [<filename>]\n"
1138 " set or unset the keyfile to be used when a passphrase is required\n"
1139 "\n" "new-keyfile <datafile> [<filename>]\n"
1140 " set or unset the keyfile to be used when a new passphrase is required\n"));
1143 rc
= GPG_ERR_UNKNOWN_OPTION
;
1149 save_command (const char *line
)
1151 struct inquire_s
*inq
= NULL
;
1154 #ifdef HAVE_LIBREADLINE
1155 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1157 rc
= set_inquire (-1, NULL
, &inq
);
1162 rc
= pwmd_save (pwm
, line
, inquire_cb
, inq
);
1165 #ifdef HAVE_LIBREADLINE
1166 // For safety. This file may be a different one. Make the user set it
1170 pwmd_free (new_keyfile
);
1179 parse_dotcommand (const char *line
, char **result
,
1180 size_t * len
, struct inquire_s
*inq
)
1182 const char *p
= line
;
1185 if (!strncmp (p
, ".read", 5))
1186 rc
= read_command (p
+ 5, result
, len
);
1187 else if (!strncmp (p
, ".redir", 6))
1188 rc
= redir_command (p
+ 6);
1189 else if (!strncmp (p
, ".help", 5))
1190 rc
= help_command (p
+ 5);
1191 else if (!strncmp (p
, ".open", 5))
1192 rc
= open_command (p
+ 5);
1193 else if (!strncmp (p
, ".set", 4))
1194 rc
= set_command (p
+ 4);
1195 else if (!strncmp (p
, ".save", 5))
1196 rc
= save_command (p
+ 5);
1198 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, line
);
1203 #ifdef HAVE_LIBREADLINE
1208 struct inquire_s
*inq
= NULL
;
1211 rc
= process_cmd ();
1215 rc
= set_inquire (STDIN_FILENO
, NULL
, &inq
);
1220 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1222 rl_event_hook
= &interactive_hook
;
1223 rl_set_keyboard_input_timeout (100000);
1228 char *result
= NULL
;
1232 line
= readline ("pwm> ");
1233 if (interactive_error
)
1235 rc
= interactive_error
;
1245 if (gpg_err_code (rc
) != GPG_ERR_CANCELED
&&
1246 gpg_err_code (rc
) != GPG_ERR_EOF
)
1247 fprintf (stderr
, "ERR %i: %s\n", rc
, gpg_strerror (rc
));
1257 #ifdef HAVE_READLINE_HISTORY
1261 rc
= parse_dotcommand (line
, &result
, &len
, inq
);
1267 if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
1268 (void) pwmd_command (pwm
, &tmp
, NULL
, NULL
, NULL
,
1269 "GETINFO last_error");
1271 show_error (rc
, tmp
);
1274 else if (result
&& len
)
1275 printf ("%s%s", result
, result
[len
- 1] != '\n' ? "\n" : "");
1286 itoa (long long int n
)
1288 static char buf
[64];
1290 snprintf (buf
, sizeof (buf
), "%llu", n
);
1298 #ifdef HAVE_LIBREADLINE
1301 if (!force_save
&& interactive
)
1306 fprintf (stderr
, "\n");
1312 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1313 p
= fgets (buf
, sizeof (buf
), stdin
);
1327 return GPG_ERR_CANCELED
;
1331 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1332 "CLEARCACHE %s", filename
);
1336 interactive_hook ();
1352 if (save
&& !filename
)
1356 ("No filename was specified on the command line. Aborting.\n"));
1357 return GPG_ERR_CANCELED
;
1360 if (save
&& filename
)
1363 pwmd_strdup_printf ("%s%s %s%s %s %s%s %s%s %s --s2k-count=%lu",
1364 keygrip
? "--keygrip=" : "",
1365 keygrip
? keygrip
: "",
1366 sign_keygrip
? "--sign-keygrip=" : "",
1367 sign_keygrip
? sign_keygrip
: "",
1368 no_passphrase
? "--no-passphrase" : "",
1369 cipher
? "--cipher=" : "", cipher
? cipher
: "",
1370 iterations_arg
? "--cipher-iterations=" : "",
1371 iterations_arg
? itoa (iterations
) : "",
1372 no_gpg_agent
? "--no-agent" : "",
1375 #ifdef HAVE_LIBREADLINE
1376 if (!quiet
|| interactive
)
1382 fprintf (stderr
, "\n");
1383 fprintf (stderr
, N_("Saving changes ...\n"));
1386 rc
= pwmd_save (pwm
, args
, inquire_cb
, NULL
);
1390 no_passphrase
= 0; // reset to avoid usage error on the next SAVE
1393 #ifdef HAVE_LIBREADLINE
1395 return rc
? rc
: quit
? 0 : GPG_ERR_CANCELED
;
1402 main (int argc
, char *argv
[])
1407 char command
[ASSUAN_LINELENGTH
], *p
= NULL
;
1408 char *result
= NULL
;
1410 char *pinentry_path
= NULL
;
1411 char *display
= NULL
, *tty
= NULL
, *ttytype
= NULL
;
1412 char *lcctype
= NULL
, *lcmessages
= NULL
;
1413 int outfd
= STDOUT_FILENO
;
1414 FILE *outfp
= stdout
;
1415 FILE *inquirefp
= stdin
;
1416 int show_status
= 1;
1417 char *clientname
= "pwmc";
1418 char *inquire
= NULL
;
1419 char *inquire_line
= NULL
;
1422 int use_ssh_agent
= 1;
1423 char *knownhosts
= NULL
;
1424 char *identity
= NULL
;
1427 char *cacert
= NULL
;
1428 char *clientcert
= NULL
;
1429 char *clientkey
= NULL
;
1432 char *tls_fingerprint
= NULL
;
1434 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1435 pwmd_socket_t socktype
;
1436 long socket_timeout
= 300;
1437 int connect_timeout
= 120;
1439 int lock_on_open
= 1;
1440 long lock_timeout
= 0;
1442 /* The order is important. */
1445 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1446 OPT_SOCKET_TIMEOUT
, OPT_CONNECT_TIMEOUT
,
1449 OPT_USE_SSH_AGENT
, OPT_IDENTITY
, OPT_KNOWNHOSTS
,
1452 OPT_CACERT
, OPT_CLIENTCERT
, OPT_CLIENTKEY
, OPT_PRIORITY
, OPT_VERIFY
,
1455 OPT_URL
, OPT_LOCAL
, OPT_FORCE_SAVE
, OPT_TTYNAME
, OPT_TTYTYPE
,
1456 OPT_DISPLAY
, OPT_LC_CTYPE
, OPT_LC_MESSAGES
, OPT_TIMEOUT
, OPT_TRIES
,
1457 OPT_PINENTRY
, OPT_KEYFILE
, OPT_NEW_KEYFILE
, OPT_NOLOCK
,
1458 OPT_LOCK_TIMEOUT
, OPT_SAVE
, OPT_OUTPUT_FD
, OPT_INQUIRE
,
1459 OPT_INQUIRE_FD
, OPT_INQUIRE_FILE
, OPT_INQUIRE_LINE
, OPT_NO_STATUS
,
1460 OPT_NAME
, OPT_VERSION
, OPT_HELP
, OPT_KEYGRIP
, OPT_SIGN_KEYGRIP
,
1461 OPT_NOPASSPHRASE
, OPT_CIPHER
, OPT_KEYPARAMS
, OPT_NO_PINENTRY
,
1462 OPT_S2K_COUNT
, OPT_ITERATIONS
, OPT_QUIET
, OPT_NO_GPG_AGENT
,
1463 #ifdef HAVE_LIBREADLINE
1467 const struct option long_opts
[] = {
1468 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1469 {"socket-timeout", 1, 0, 0},
1470 {"connect-timeout", 1, 0, 0},
1474 {"no-ssh-agent", 0, 0, 0},
1475 {"identity", 1, 0, 'i'},
1476 {"knownhosts", 1, 0, 'k'},
1479 {"ca-cert", 1, 0, 0},
1480 {"client-cert", 1, 0, 0},
1481 {"client-key", 1, 0, 0},
1482 {"tls-priority", 1, 0, 0},
1483 {"tls-verify", 0, 0, 0},
1484 {"tls-fingerprint", 1, 0, 0},
1487 {"local-pinentry", 0, 0},
1488 {"force-save", 0, 0},
1489 {"ttyname", 1, 0, 'y'},
1490 {"ttytype", 1, 0, 't'},
1491 {"display", 1, 0, 'd'},
1492 {"lc-ctype", 1, 0, 0},
1493 {"lc-messages", 1, 0, 0},
1494 {"timeout", 1, 0, 0},
1496 {"pinentry", 1, 0, 0},
1497 {"key-file", 1, 0, 0},
1498 {"new-key-file", 1, 0, 0},
1499 {"no-lock", 0, 0, 0},
1500 {"lock-timeout", 1, 0, 0},
1501 {"save", 0, 0, 'S'},
1502 {"output-fd", 1, 0, 0},
1503 {"inquire", 1, 0, 0},
1504 {"inquire-fd", 1, 0, 0},
1505 {"inquire-file", 1, 0, 0},
1506 {"inquire-line", 1, 0, 'L'},
1507 {"no-status", 0, 0, 0},
1508 {"name", 1, 0, 'n'},
1509 {"version", 0, 0, 0},
1511 {"keygrip", 1, 0, 0},
1512 {"sign-keygrip", 1, 0, 0},
1513 {"no-passphrase", 0, 0, 0},
1514 {"cipher", 1, 0, 0},
1515 {"key-params", 1, 0, 0},
1516 {"no-pinentry", 0, 0, 0},
1517 {"s2k-count", 1, 0, 0},
1518 {"cipher-iterations", 1, 0, 0},
1520 {"no-gpg-agent", 0, 0, 0},
1521 #ifdef HAVE_LIBREADLINE
1522 {"interactive", 0, 0},
1527 const char *optstring
= "L:y:t:d:P:I:Sn:i:k:";
1529 const char *optstring
= "L:y:t:d:P:I:Sn:";
1534 setlocale (LC_ALL
, "");
1535 bindtextdomain ("libpwmd", LOCALEDIR
);
1538 tries
= DEFAULT_PIN_TRIES
;
1539 inquirefd
= STDIN_FILENO
;
1542 getopt_long (argc
, argv
, optstring
, long_opts
, &opt_index
)) != -1)
1546 /* Handle long options without a short option part. */
1550 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1551 case OPT_SOCKET_TIMEOUT
:
1552 socket_timeout
= strtol (optarg
, &p
, 10);
1554 case OPT_CONNECT_TIMEOUT
:
1555 connect_timeout
= strtol (optarg
, &p
, 10);
1559 case OPT_USE_SSH_AGENT
:
1567 case OPT_CLIENTCERT
:
1568 clientcert
= optarg
;
1580 tls_fingerprint
= optarg
;
1583 case OPT_NO_GPG_AGENT
:
1590 keyfile
= pwmd_strdup (optarg
);
1592 case OPT_NEW_KEYFILE
:
1593 new_keyfile
= pwmd_strdup (optarg
);
1598 case OPT_LOCK_TIMEOUT
:
1599 lock_timeout
= strtol (optarg
, &p
, 10);
1607 case OPT_FORCE_SAVE
:
1608 save
= force_save
= 1;
1611 lcctype
= pwmd_strdup (optarg
);
1613 case OPT_LC_MESSAGES
:
1614 lcmessages
= pwmd_strdup (optarg
);
1617 timeout
= strtol (optarg
, &p
, 10);
1620 tries
= strtol (optarg
, &p
, 10);
1625 case OPT_INQUIRE_FD
:
1626 inquirefd
= strtol (optarg
, &p
, 10);
1629 inquirefp
= fdopen (inquirefd
, "r");
1632 pwmd_free (password
);
1633 err (EXIT_FAILURE
, "%i", inquirefd
);
1637 case OPT_INQUIRE_FILE
:
1638 inquirefd
= open (optarg
, O_RDONLY
);
1639 if (inquirefd
== -1)
1641 pwmd_free (password
);
1642 err (EXIT_FAILURE
, "%s", optarg
);
1644 inquirefp
= fdopen (inquirefd
, "r");
1647 outfd
= strtol (optarg
, &p
, 10);
1650 outfp
= fdopen (outfd
, "w");
1653 pwmd_free (password
);
1654 err (EXIT_FAILURE
, "%i", outfd
);
1662 pwmd_free (password
);
1663 printf ("%s (pwmc)\n\n"
1664 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013\n"
1666 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1667 "Compile-time features:\n"
1668 #ifdef HAVE_LIBREADLINE
1683 #ifdef WITH_PINENTRY
1698 "\n", PACKAGE_STRING
, PACKAGE_BUGREPORT
);
1699 exit (EXIT_SUCCESS
);
1701 pinentry_path
= optarg
;
1704 usage (argv
[0], EXIT_SUCCESS
);
1708 case OPT_SIGN_KEYGRIP
:
1709 sign_keygrip
= optarg
;
1712 s2k_count
= strtoul (optarg
, &p
, 10);
1714 case OPT_ITERATIONS
:
1715 iterations
= strtoull (optarg
, &p
, 10);
1722 case OPT_NOPASSPHRASE
:
1728 case OPT_NO_PINENTRY
:
1731 #ifdef HAVE_LIBREADLINE
1732 case OPT_INTERACTIVE
:
1737 usage (argv
[0], EXIT_FAILURE
);
1742 fprintf (stderr
, N_("%s: invalid argument for option '--%s'\n"),
1743 argv
[0], long_opts
[opt_index
].name
);
1744 usage (argv
[0], EXIT_FAILURE
);
1753 knownhosts
= optarg
;
1757 inquire_line
= optarg
;
1772 clientname
= optarg
;
1775 pwmd_free (password
);
1776 usage (argv
[0], EXIT_FAILURE
);
1780 #ifdef HAVE_LIBREADLINE
1781 if (interactive
&& !isatty (STDIN_FILENO
))
1783 pwmd_free (password
);
1784 usage (argv
[0], EXIT_FAILURE
);
1786 else if (isatty (STDIN_FILENO
) && !inquire
&& !inquire_line
)
1790 filename
= argv
[optind
];
1792 gnutls_global_set_mem_functions (pwmd_malloc
, pwmd_malloc
, NULL
,
1793 pwmd_realloc
, pwmd_free
);
1796 rc
= pwmd_new (clientname
, &pwm
);
1800 pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TRIES
, tries
);
1802 fprintf (stderr
, N_("Connecting ...\n"));
1804 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1805 socktype
= is_remote_url (url
);
1806 if (socktype
!= PWMD_SOCKET_LOCAL
)
1809 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1810 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, connect_timeout
);
1815 if (socktype
== PWMD_SOCKET_SSH
)
1818 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_CB
, knownhost_cb
);
1822 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_DATA
, clientname
);
1826 if (!getenv ("SSH_AUTH_SOCK") || identity
)
1829 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_AGENT
, use_ssh_agent
);
1833 rc
= pwmd_connect (pwm
, url
, identity
, knownhosts
);
1839 rc
= pwmd_setopt (pwm
, PWMD_OPTION_TLS_VERIFY
, tls_verify
);
1843 rc
= pwmd_connect (pwm
, url
, clientcert
, clientkey
, cacert
, prio
,
1849 rc
= pwmd_connect (pwm
, url
);
1851 rc
= pwmd_connect (pwm
, url
);
1857 fprintf (stderr
, N_("Connected.\n"));
1860 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1861 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, socket_timeout
);
1868 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1869 "OPTION LOCK-TIMEOUT=%li", lock_timeout
);
1876 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCK_ON_OPEN
, 1);
1881 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, NULL
);
1887 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, timeout
);
1892 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
1896 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
,
1897 (local_pin
|| keyfile
|| new_keyfile
));
1903 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_PATH
, pinentry_path
);
1910 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DISPLAY
, display
);
1917 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TTY
, tty
);
1924 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TERM
, ttytype
);
1931 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_CTYPE
, lcctype
);
1938 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_MESSAGES
, lcmessages
);
1945 rc
= pwmd_setopt (pwm
, PWMD_OPTION_STATUS_CB
, status_msg_cb
);
1952 rc
= open_command (filename
);
1957 #ifdef HAVE_LIBREADLINE
1963 rc
= do_interactive ();
1971 struct inquire_s
*inq
= NULL
;
1973 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
1975 rc
= pwmd_command (pwm
, &result
, &len
, inquire_cb
, inq
, inquire
);
1981 fcntl (STDIN_FILENO
, F_SETFL
, O_NONBLOCK
);
1986 rc
= process_cmd ();
1991 n
= read (STDIN_FILENO
, command
, sizeof (command
));
1994 if (errno
== EAGAIN
)
2000 rc
= gpg_error_from_errno (errno
);
2011 if (!p
|| !*p
|| !strcasecmp (p
, "BYE"))
2015 struct inquire_s
*inq
= NULL
;
2016 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2019 rc
= parse_dotcommand (command
, &result
, &len
, inq
);
2029 fwrite (result
, 1, result
[len
- 1] == 0 ? len
- 1 : len
, outfp
);
2034 pwmd_free (password
);
2035 password
= result
= NULL
;
2038 else if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
2039 (void) pwmd_command (pwm
, &result
, NULL
, NULL
, NULL
,
2040 "GETINFO last_error");
2042 #ifdef HAVE_LIBREADLINE
2045 memset (command
, 0, sizeof (command
));
2047 pwmd_free (keyfile
);
2048 pwmd_free (new_keyfile
);
2052 show_error (rc
, result
);
2055 if (connected
&& !quiet
)
2056 fprintf (stderr
, N_("Connection closed.\n"));
2058 exit (rc
? EXIT_FAILURE
: EXIT_SUCCESS
);