2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014
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_TIMEOUT 30
82 #define DEFAULT_PIN_TRIES 3
83 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
86 static int no_pinentry
;
88 static char *filename
;
90 static int force_save
;
91 static int no_passphrase
;
94 static char *sign_keygrip
;
95 static char *keyparams
;
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_("Usage: pwmc [options] [file]\n"
139 " a url string to connect to (%s, see below)\n"
140 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
141 " --connect-timeout <seconds>\n"
142 " seconds before connecting to a remote host fails (0=disabled, 120)\n"
143 " --socket-timeout <seconds>\n"
144 " seconds before a remote command fails (0=disabled, 300)\n"
147 " --ca-cert <filename>\n"
148 " certificate authority (CA) used to sign the server cert\n"
149 " --client-cert <filename>\n"
150 " client certificate to use for authentication\n"
151 " --client-key <filename>\n"
152 " key file used to protect the client certificate\n"
153 " --tls-priority <string>\n"
154 " compression, cipher and hash algorithm string (SECURE256)\n"
156 " verify the hostname against the server certificate\n"
157 " --tls-fingerprint <string>\n"
158 " a SHA-256 hash of the server fingerprint to verify against\n"
162 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
163 " --identity, -i <filename>\n"
164 " the ssh identity file to use for authentication\n"
165 " --knownhosts, -k <filename>\n"
166 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
169 " do not lock the data file upon opening it\n"
170 " --lock-timeout <N>\n"
171 " time in tenths of a second to wait for a locked data file (50)\n"
172 " --name, -n <string>\n"
173 " set the client name\n"
174 " --pinentry <path>\n"
175 " the full path to the pinentry binary (server default)\n"
176 " --local-pinentry\n"
177 " force using a local pinentry\n"
179 " disable pinentry both remotely and locally\n"
180 " --ttyname, -y <path>\n"
181 " tty that pinentry will use\n"
182 " --ttytype, -t <string>\n"
183 " pinentry terminal type (default is $TERM)\n"
185 " pinentry display (default is $DISPLAY)\n"
186 " --lc-ctype <string>\n"
187 " locale setting for pinentry\n"
188 " --lc-messages <string>\n"
189 " locale setting for pinentry\n"
191 " number of pinentry tries before failing (3)\n"
192 " --timeout <seconds>\n"
193 " pinentry timeout\n"
194 " --inquire <COMMAND>\n"
195 " the specified command (with any options) uses a server inquire while\n"
196 " command data is read via the inquire file descriptor (stdin)\n"
197 " --inquire-line, -L <STRING>\n"
198 " the initial line to send (i.e., element path) before the inquire data\n"
199 " --inquire-fd <FD>\n"
200 " read inquire data from the specified file descriptor (stdin)\n"
201 " --inquire-file <filename>\n"
202 " read inquire data from the specified filename\n"
203 " --output-fd <FD>\n"
204 " redirect command output to the specified file descriptor\n"
206 " send the SAVE command before exiting\n"
208 " like --save but always ask for a passphrase\n"
210 " do not require a passphrase when saving a new file\n"
212 " disable use of gpg-agent when saving to a new file\n"
213 " --key-file <filename>\n"
214 " obtain the passphrase from the specified filename\n"
215 " --new-key-file <filename>\n"
216 " obtain the passphrase to save with from the specified filename\n"
217 " --cipher <string>\n"
218 " the cipher to use when saving (see pwmd(1))\n"
219 " --cipher-iterations <N>\n"
220 " the number of times to encrypt the XML data (N+1)\n"
221 " --key-params <string>\n"
222 " the key parameters to use when saving a new file (pwmd default)\n"
223 " --keygrip <string>\n"
224 " the hex string of the keygrip to save to\n"
225 " --sign-keygrip <string>\n"
226 " the hex string of the keygrip to sign with\n"
228 " the number of times to hash the passphrase for a new file\n"
230 " disable showing of status messages from the server\n"
232 " disable showing of extra messages (implies --no-status)\n"
233 #ifdef HAVE_LIBREADLINE
235 " use a shell like interface to pwmd (allows more than one command)\n"
239 #ifdef DEFAULT_PWMD_SOCKET
245 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
247 "An optional url may be in the form of:\n"
248 " --url /path/to/socket\n"
249 " --url file://[path/to/socket]\n"
252 " --url ssh[46]://[username@]hostname[:port]\n"
253 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
257 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
258 " --client-key filename\n"
260 #ifdef HAVE_LIBREADLINE
262 "Interactive mode is used when input is from a terminal.\n"
269 inquire_cb (void *user
, const char *keyword
, gpg_error_t rc
,
270 char **data
, size_t * size
)
272 struct inquire_s
*inq
= user
;
274 int is_newpassword
= 0;
282 if (!strcmp (keyword
, "PASSPHRASE"))
284 else if (!strcmp (keyword
, "NEW_PASSPHRASE"))
286 #ifdef HAVE_LIBREADLINE
287 else if (!strcmp (keyword
, "KEYPARAM") && !interactive
)
290 else if (!strcmp (keyword
, "KEYPARAM"))
293 if (!keyparams
|| !*keyparams
)
294 return gpg_error (GPG_ERR_INV_PARAMETER
);
297 *size
= strlen (keyparams
);
298 return gpg_error (GPG_ERR_EOF
);
301 if ((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
))
303 int fd
= open (is_password
? keyfile
: new_keyfile
, O_RDONLY
);
307 fprintf (stderr
, "%s: %s\n", is_newpassword
? new_keyfile
: keyfile
,
309 return gpg_error_from_syserror ();
312 rc
= set_inquire (fd
, NULL
, &inq
);
320 fprintf (stderr
, N_("Using keyfile '%s' as %s.\n"),
321 is_newpassword
? new_keyfile
: keyfile
, keyword
);
323 if (!new_keyfile
|| is_newpassword
)
327 pwmd_socket_type (pwm
, &t
);
328 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
329 if (!no_pinentry
&& t
== PWMD_SOCKET_LOCAL
)
330 pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 0);
333 else if ((is_password
&& !keyfile
) || (is_newpassword
&& !new_keyfile
))
337 rc
= pwmd_password (pwm
, keyword
, &tmp
, &inq
->len
);
338 if (rc
&& gpg_err_code (rc
) != GPG_ERR_EOF
)
341 pwmd_free (inq
->line
);
345 return gpg_error (GPG_ERR_EOF
);
347 #ifdef HAVE_LIBREADLINE
348 else if (!inq
->header
&& interactive
)
352 ("Press CTRL-D to send the current line. Press twice to end. %s:\n"),
358 /* The first part of the command data. */
364 return inq
->fd
== -1 ? gpg_error (GPG_ERR_EOF
) : 0;
367 *size
= read (inq
->fd
, inq
->line
, ASSUAN_LINELENGTH
);
371 return gpg_error (gpg_error_from_syserror ());
375 else if (inq
->fd
!= STDIN_FILENO
&& (is_newpassword
|| is_password
))
383 if (((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
))
384 && *size
== inq
->size
)
385 return gpg_error (GPG_ERR_EOF
);
387 return *size
? 0 : gpg_error (GPG_ERR_EOF
);
391 status_msg_cb (void *data
, const char *line
)
393 char *p
= strchr (line
, ' ');
395 if (!strcmp (line
, "KEEPALIVE"))
398 if (*line
!= '#' && p
&& strchr (p
, ' ') && *++p
)
400 char *p1
= strchr (p
, ' ');
401 int a
= strtol (p
, NULL
, 10);
403 if (isdigit (*p
) && p1
)
405 int b
= strtol (p1
, NULL
, 10);
407 int t
= a
&& b
? a
* 100 / b
: 0;
409 strncpy (l
, line
, strlen (line
) - strlen (p
) - 1);
410 fprintf (stderr
, "\r%s %i/%i %i%%%s", l
, a
, b
, t
,
417 fprintf (stderr
, "%s\n", line
);
419 #ifdef HAVE_LIBREADLINE
428 return pwmd_process (pwm
);
433 get_password (char **result
, pwmd_pinentry_t w
, int echo
)
435 char buf
[LINE_MAX
] = { 0 }, *p
;
436 struct termios told
, tnew
;
441 if (!isatty (STDIN_FILENO
))
443 fprintf (stderr
, N_("Input is not from a terminal! Failing.\n"));
444 return GPG_ERR_ENOTTY
;
449 if (tcgetattr (STDIN_FILENO
, &told
) == -1)
450 return gpg_error_from_syserror ();
452 memcpy (&tnew
, &told
, sizeof (struct termios
));
453 tnew
.c_lflag
&= ~(ECHO
);
454 tnew
.c_lflag
|= ICANON
| ECHONL
;
456 if (tcsetattr (STDIN_FILENO
, TCSANOW
, &tnew
) == -1)
460 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
461 return gpg_error_from_errno (n
);
467 case PWMD_PINENTRY_OPEN
:
468 fprintf (stderr
, N_("Password for %s: "), filename
);
470 case PWMD_PINENTRY_OPEN_FAILED
:
471 fprintf (stderr
, N_("Invalid password. Password for %s: "), filename
);
473 case PWMD_PINENTRY_SAVE
:
474 fprintf (stderr
, N_("New password for %s: "), filename
);
476 case PWMD_PINENTRY_SAVE_CONFIRM
:
477 fprintf (stderr
, N_("Confirm password: "));
483 if ((p
= fgets (buf
, sizeof (buf
), stdin
)) == NULL
)
485 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
490 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
495 return GPG_ERR_CANCELED
;
498 p
[strlen (p
) - 1] = 0;
502 key
= pwmd_strdup_printf ("%s", p
);
503 memset (&buf
, 0, sizeof (buf
));
506 return GPG_ERR_ENOMEM
;
514 knownhost_cb (void *data
, const char *host
, const char *key
, size_t len
)
518 pwmd_strdup_printf (N_
519 ("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?"),
520 (char *) data
, host
, host
);
522 if (no_pinentry
&& !isatty (STDIN_FILENO
))
524 fprintf (stderr
, N_("Input is not from a terminal! Failing.\n"));
526 return GPG_ERR_ENOTTY
;
528 else if (no_pinentry
)
530 for (char *p
= buf
, len
= 0; *p
; p
++, len
++)
539 while (!isspace (*(--p
)));
546 fprintf (stderr
, "%s\n\n", buf
);
553 fprintf (stderr
, N_("Trust this connection [y/N]: "));
555 rc
= get_password (&result
, PWMD_PINENTRY_CONFIRM
, 1);
560 if (!result
|| !*result
|| *result
== 'n' || *result
== 'N')
562 if (result
&& *result
)
565 return GPG_ERR_NOT_CONFIRMED
;
568 if ((*result
== 'y' || *result
== 'Y') && *(result
+ 1) == 0)
577 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, buf
);
583 return pwmd_getpin (pwm
, NULL
, NULL
, NULL
, PWMD_PINENTRY_CONFIRM
);
587 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
589 is_remote_url (const char *str
)
592 return PWMD_SOCKET_LOCAL
;
595 if (strstr (str
, "ssh://") || strstr (str
, "ssh4://")
596 || strstr (str
, "ssh6://"))
597 return PWMD_SOCKET_SSH
;
601 if (strstr (str
, "tls://") || strstr (str
, "tls4://")
602 || strstr (str
, "tls6://"))
603 return PWMD_SOCKET_TLS
;
606 return PWMD_SOCKET_LOCAL
;
611 escape (const char *str
)
614 char *buf
= pwmd_malloc (ASSUAN_LINELENGTH
+ 1), *b
= buf
;
617 for (p
= str
; *p
; p
++, len
++)
619 if (len
== ASSUAN_LINELENGTH
)
663 free_inquire (struct inquire_s
*inq
)
668 pwmd_free (inq
->line
);
670 if (inq
->fd
!= -1 && inq
->fd
!= STDIN_FILENO
)
676 /* When *result is not NULL it is updated to the new values and not
679 set_inquire (int fd
, const char *line
, struct inquire_s
**result
)
681 struct inquire_s inq
= { 0 };
682 struct stat st
= { 0 };
687 if (fstat (fd
, &st
) == -1)
688 return gpg_error_from_syserror ();
690 inq
.size
= st
.st_size
;
694 inq
.line
= pwmd_calloc (1, ASSUAN_LINELENGTH
);
696 return GPG_ERR_ENOMEM
;
700 char *s
= escape (line
);
704 pwmd_free (inq
.line
);
705 return GPG_ERR_ENOMEM
;
708 if (strlen (s
) >= ASSUAN_LINELENGTH
)
710 pwmd_free (inq
.line
);
712 return GPG_ERR_LINE_TOO_LONG
;
715 strncpy (inq
.line
, s
, ASSUAN_LINELENGTH
- 1);
716 inq
.len
= strlen (s
);
720 rc
= pwmd_setopt (pwm
, PWMD_OPTION_INQUIRE_TOTAL
,
721 st
.st_size
? st
.st_size
+ strlen (inq
.line
) : 0);
724 pwmd_free (inq
.line
);
729 *result
= pwmd_malloc (sizeof (struct inquire_s
));
732 if ((*result
)->fd
!= -1 && (*result
)->fd
!= STDIN_FILENO
)
733 close ((*result
)->fd
);
735 pwmd_free ((*result
)->line
);
736 (*result
)->line
= NULL
;
741 memcpy (*result
, &inq
, sizeof (struct inquire_s
));
742 memset (&inq
, 0, sizeof (struct inquire_s
));
746 #ifdef HAVE_LIBREADLINE
748 interactive_hook (void)
750 interactive_error
= process_cmd ();
752 if (interactive_error
)
753 rl_event_hook
= NULL
;
763 ("------------------------------------------------------------------------------\n"
764 "Elements are TAB delimited. Press CTRL-V then TAB to insert from the prompt.\n"
766 "Type HELP for protocol commands. Type .help for pwmc commands. Press CTRL-D\n"
768 "------------------------------------------------------------------------------\n"));
773 parse_arg (const char *src
, char *dst
, size_t len
)
779 for (; s
&& *s
&& *s
!= ' ' && n
< len
; s
++, n
++)
787 parse_opt (char **line
, const char *opt
, gpg_error_t
* rc
)
789 static char result
[ASSUAN_LINELENGTH
] = { 0 }, *r
= result
;
790 char *s
= strstr (*line
, opt
);
800 size_t rlen
= strlen (opt
);
804 while (*p
&& *p
== ' ')
810 for (; *p
&& len
< sizeof (result
) - 1; p
++, rlen
++)
812 if (isspace (*p
) && !quote
)
815 if (*p
== '\"' && lastc
!= '\\')
828 if (len
>= sizeof (result
) - 1)
829 *rc
= GPG_ERR_LINE_TOO_LONG
;
834 while (*p
&& *p
== ' ')
845 read_command (const char *line
, char **result
, size_t * len
)
849 char *filename
= NULL
;
850 struct inquire_s
*inq
= NULL
;
851 char *p
= (char *) line
;
852 const char *prefix
= parse_opt (&p
, "--prefix", &rc
);
861 char filebuf
[ASSUAN_LINELENGTH
];
863 while (*p
&& isspace (*p
))
866 filename
= parse_arg (p
, filebuf
, sizeof (filebuf
));
867 if (filename
&& *filename
)
869 p
+= strlen (filename
) + 1;
871 while (*p
&& isspace (*p
))
883 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
886 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\" = \")\n"));
890 fd
= open (filename
, O_RDONLY
);
892 return gpg_error_from_syserror ();
894 rc
= set_inquire (fd
, prefix
&& *prefix
? prefix
: NULL
, &inq
);
902 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, p
);
908 redir_command (const char *line
)
910 const char *p
= line
;
912 gpg_error_t rc
= GPG_ERR_SYNTAX
;
913 char *filename
= NULL
;
914 struct inquire_s
*inq
= NULL
;
920 char filebuf
[ASSUAN_LINELENGTH
];
922 filename
= parse_arg (p
, filebuf
, sizeof (filebuf
));
923 if (filename
&& *filename
)
925 p
+= strlen (filename
) + 1;
927 while (*p
&& isspace (*p
))
937 fprintf (stderr
, N_("Usage: .redir <filename> <command> [args]\n"));
941 fd
= open (filename
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600);
943 return gpg_error_from_syserror ();
945 #ifdef HAVE_LIBREADLINE
946 rc
= set_inquire (interactive
? STDIN_FILENO
: inquirefd
, NULL
, &inq
);
948 rc
= set_inquire (inquirefd
, NULL
, &inq
);
956 rc
= parse_dotcommand (p
, &result
, &len
, inq
);
957 if (!rc
&& result
&& len
--)
958 { // null byte which is always appended
959 if (write (fd
, result
, len
) != len
)
960 rc
= GPG_ERR_TOO_SHORT
;
970 help_command (const char *line
)
973 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
974 " .redir <filename> <command>\n"
975 " redirect the output of a command to the specified file\n"
977 " .open <filename>\n"
978 " open the specified filename losing any changes to the current one\n"
980 " .read [--prefix <string>] <filename> <command> [args]\n"
981 " obtain data from the specified filename for an inquire command\n"
983 " .set help | <name> [<value>]\n"
984 " set option <name> to <value>\n"
987 " write changes of the file to disk\n"
990 " change the passphrase of a data file\n"
993 " this help text\n"));
998 open_command (const char *line
)
1000 struct inquire_s
*inq
= NULL
;
1001 const char *filename
= line
;
1004 while (filename
&& isspace (*filename
))
1007 if (!filename
|| !*filename
)
1009 fprintf (stderr
, N_("Usage: .open <filename>\n"));
1010 return GPG_ERR_SYNTAX
;
1013 #ifdef HAVE_LIBREADLINE
1014 if (interactive
|| !quiet
)
1018 fprintf (stderr
, N_("Opening data file \"%s\" ...\n"), filename
);
1020 #ifdef HAVE_LIBREADLINE
1021 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1023 rc
= set_inquire (-1, NULL
, &inq
);
1029 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1031 rc
= pwmd_open (pwm
, filename
, inquire_cb
, inq
);
1037 set_command (const char *line
)
1040 char name
[256] = { 0 };
1041 char value
[512] = { 0 };
1044 const char *p
= line
;
1046 while (p
&& *p
&& isspace (*p
))
1049 namep
= parse_arg (p
, name
, sizeof (name
));
1050 if (!namep
|| !*namep
)
1052 fprintf (stderr
, N_("Usage: .set help | <name> [<value>]\n"));
1053 return GPG_ERR_SYNTAX
;
1056 p
+= strlen (namep
);
1057 while (p
&& *p
&& isspace (*p
))
1060 valuep
= parse_arg (p
, value
, sizeof (value
));
1062 if (!strcmp (name
, "keyfile") || !strcmp (name
, "new-keyfile"))
1064 int is_newkeyfile
= 1;
1067 if (!strcmp (name
, "keyfile"))
1072 pwmd_free (new_keyfile
);
1077 pwmd_free (keyfile
);
1081 p
+= strlen (valuep
);
1082 while (p
&& *p
&& isspace (*p
))
1085 valuep
= (char *) p
;
1090 memcpy (datafile
, value
, sizeof (datafile
));
1091 valuep
= parse_arg (p
, value
, sizeof (value
));
1092 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
, "KEYGRIP %s",
1094 if (gpg_err_code (rc
) == GPG_ERR_NOT_SUPPORTED
1095 || (gpg_err_source (rc
) == GPG_ERR_SOURCE_USER_1
1096 && gpg_err_code (rc
) == GPG_ERR_ENOENT
))
1108 new_keyfile
= pwmd_strdup (value
);
1110 keyfile
= pwmd_strdup (value
);
1115 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1116 "AGENT option pinentry-mode=loopback");
1120 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 1);
1122 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1125 else if (!local_pin
&& !no_pinentry
)
1129 pwmd_socket_type (pwm
, &t
);
1130 if (t
== PWMD_SOCKET_LOCAL
)
1132 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 0);
1134 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1138 else if (!strcmp(name
, "pinentry-timeout"))
1141 int n
= strtol(valuep
, &e
, 10);
1144 return gpg_error (GPG_ERR_INV_VALUE
);
1146 if (!valuep
|| !*valuep
)
1147 n
= DEFAULT_PIN_TIMEOUT
;
1149 rc
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, n
);
1151 else if (!strcmp (name
, "help"))
1155 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1156 "delimited. When no value is specified the option is unset.\n\n"
1157 "keyfile <datafile> [<filename>]\n"
1158 " set or unset the keyfile to be used when a passphrase is required (*)\n"
1160 "new-keyfile <datafile> [<filename>]\n"
1161 " set or unset the keyfile to be used when a new passphrase is required (*)\n"
1163 "pinentry-timeout <seconds>\n"
1164 " the amount of seconds before pinentry gives up waiting for input\n"
1166 "* = the next protocol command will unset this value\n"
1170 rc
= GPG_ERR_UNKNOWN_OPTION
;
1176 save_command (const char *line
)
1178 struct inquire_s
*inq
= NULL
;
1181 #ifdef HAVE_LIBREADLINE
1182 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1184 rc
= set_inquire (-1, NULL
, &inq
);
1189 if (new_keyfile
|| keyfile
)
1190 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1192 rc
= pwmd_save (pwm
, line
, inquire_cb
, inq
);
1193 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1199 do_save_passwd_command (const char *line
, int save
)
1201 struct inquire_s
*inq
= NULL
;
1204 #ifdef HAVE_LIBREADLINE
1205 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1207 rc
= set_inquire (-1, NULL
, &inq
);
1212 if (new_keyfile
|| keyfile
)
1213 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1216 rc
= pwmd_save (pwm
, line
, inquire_cb
, inq
);
1218 rc
= pwmd_passwd (pwm
, line
, inquire_cb
, inq
);
1220 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1226 parse_dotcommand (const char *line
, char **result
,
1227 size_t * len
, struct inquire_s
*inq
)
1229 const char *p
= line
;
1232 if (!strncmp (p
, ".read", 5))
1233 rc
= read_command (p
+ 5, result
, len
);
1234 else if (!strncmp (p
, ".redir", 6))
1235 rc
= redir_command (p
+ 6);
1236 else if (!strncmp (p
, ".help", 5))
1237 rc
= help_command (p
+ 5);
1238 else if (!strncmp (p
, ".open", 5))
1239 rc
= open_command (p
+ 5);
1240 else if (!strncmp (p
, ".set", 4))
1241 rc
= set_command (p
+ 4);
1242 else if (!strncmp (p
, ".save", 5))
1243 rc
= do_save_passwd_command (p
+ 5, 1);
1244 else if (!strncmp (p
, ".passwd", 7))
1245 rc
= do_save_passwd_command (p
+ 7, 0);
1248 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, line
);
1249 #ifdef HAVE_LIBREADLINE
1253 pwmd_free (keyfile
);
1254 pwmd_free (new_keyfile
);
1255 keyfile
= new_keyfile
= NULL
;
1256 #ifdef HAVE_LIBREADLINE
1264 #ifdef HAVE_LIBREADLINE
1269 struct inquire_s
*inq
= NULL
;
1272 rc
= process_cmd ();
1276 rc
= set_inquire (STDIN_FILENO
, NULL
, &inq
);
1281 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1283 rl_event_hook
= &interactive_hook
;
1284 rl_set_keyboard_input_timeout (100000);
1289 char *result
= NULL
;
1293 line
= readline ("pwm> ");
1294 if (interactive_error
)
1296 rc
= interactive_error
;
1306 if (gpg_err_code (rc
) != GPG_ERR_CANCELED
&&
1307 gpg_err_code (rc
) != GPG_ERR_EOF
)
1308 fprintf (stderr
, "ERR %i: %s\n", rc
, gpg_strerror (rc
));
1318 #ifdef HAVE_READLINE_HISTORY
1322 rc
= parse_dotcommand (line
, &result
, &len
, inq
);
1328 if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
1329 (void) pwmd_command (pwm
, &tmp
, NULL
, NULL
, NULL
,
1330 "GETINFO last_error");
1332 show_error (rc
, tmp
);
1335 else if (result
&& len
)
1336 printf ("%s%s", result
, result
[len
- 1] != '\n' ? "\n" : "");
1347 itoa (long long int n
)
1349 static char buf
[64];
1351 snprintf (buf
, sizeof (buf
), "%lli", n
);
1359 #ifdef HAVE_LIBREADLINE
1362 if (!force_save
&& interactive
)
1366 fprintf (stderr
, "\n");
1374 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1375 p
= fgets (buf
, sizeof (buf
), stdin
);
1389 return GPG_ERR_CANCELED
;
1393 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1394 "CLEARCACHE %s", filename
);
1398 interactive_hook ();
1414 if (save
&& !filename
)
1418 ("No filename was specified on the command line. Aborting.\n"));
1419 return GPG_ERR_CANCELED
;
1422 if (save
&& filename
)
1425 pwmd_strdup_printf ("%s%s %s%s %s %s%s %s%s %s %s %s --s2k-count=%lu",
1426 keygrip
? "--keygrip=" : "",
1427 keygrip
? keygrip
: "",
1428 sign_keygrip
? "--sign-keygrip=" : "",
1429 sign_keygrip
? sign_keygrip
: "",
1430 no_passphrase
? "--no-passphrase" : "",
1431 cipher
? "--cipher=" : "", cipher
? cipher
: "",
1432 iterations_arg
? "--cipher-iterations=" : "",
1433 iterations_arg
? itoa (iterations
) : "",
1434 no_gpg_agent
? "--no-agent" : "",
1435 keyparams
? "--inquire-keyparam" : "",
1436 force_save
? "--reset" : "", s2k_count
);
1438 #ifdef HAVE_LIBREADLINE
1439 if (!quiet
|| interactive
)
1445 fprintf (stderr
, "\n");
1446 fprintf (stderr
, N_("Saving changes ...\n"));
1449 rc
= save_command (args
);
1452 no_passphrase
= 0; // reset to avoid usage error on the next SAVE
1455 #ifdef HAVE_LIBREADLINE
1457 return rc
? rc
: quit
? 0 : GPG_ERR_CANCELED
;
1464 main (int argc
, char *argv
[])
1469 char command
[ASSUAN_LINELENGTH
], *p
= NULL
;
1470 char *result
= NULL
;
1472 char *pinentry_path
= NULL
;
1473 char *display
= NULL
, *tty
= NULL
, *ttytype
= NULL
;
1474 char *lcctype
= NULL
, *lcmessages
= NULL
;
1475 int outfd
= STDOUT_FILENO
;
1476 FILE *outfp
= stdout
;
1477 FILE *inquirefp
= stdin
;
1478 int show_status
= 1;
1479 char *clientname
= "pwmc";
1480 char *inquire
= NULL
;
1481 char *inquire_line
= NULL
;
1484 int use_ssh_agent
= 1;
1485 char *knownhosts
= NULL
;
1486 char *identity
= NULL
;
1489 char *cacert
= NULL
;
1490 char *clientcert
= NULL
;
1491 char *clientkey
= NULL
;
1494 char *tls_fingerprint
= NULL
;
1496 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1497 pwmd_socket_t socktype
;
1498 long socket_timeout
= 300;
1499 int connect_timeout
= 120;
1501 int lock_on_open
= 1;
1502 long lock_timeout
= 50;
1504 /* The order is important. */
1507 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1508 OPT_SOCKET_TIMEOUT
, OPT_CONNECT_TIMEOUT
,
1511 OPT_USE_SSH_AGENT
, OPT_IDENTITY
, OPT_KNOWNHOSTS
,
1514 OPT_CACERT
, OPT_CLIENTCERT
, OPT_CLIENTKEY
, OPT_PRIORITY
, OPT_VERIFY
,
1517 OPT_URL
, OPT_LOCAL
, OPT_FORCE_SAVE
, OPT_TTYNAME
, OPT_TTYTYPE
,
1518 OPT_DISPLAY
, OPT_LC_CTYPE
, OPT_LC_MESSAGES
, OPT_TIMEOUT
, OPT_TRIES
,
1519 OPT_PINENTRY
, OPT_KEYFILE
, OPT_NEW_KEYFILE
, OPT_NOLOCK
,
1520 OPT_LOCK_TIMEOUT
, OPT_SAVE
, OPT_OUTPUT_FD
, OPT_INQUIRE
,
1521 OPT_INQUIRE_FD
, OPT_INQUIRE_FILE
, OPT_INQUIRE_LINE
, OPT_NO_STATUS
,
1522 OPT_NAME
, OPT_VERSION
, OPT_HELP
, OPT_KEYGRIP
, OPT_SIGN_KEYGRIP
,
1523 OPT_NOPASSPHRASE
, OPT_CIPHER
, OPT_KEYPARAMS
, OPT_NO_PINENTRY
,
1524 OPT_S2K_COUNT
, OPT_ITERATIONS
, OPT_QUIET
, OPT_NO_GPG_AGENT
,
1525 #ifdef HAVE_LIBREADLINE
1529 const struct option long_opts
[] = {
1530 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1531 {"socket-timeout", 1, 0, 0},
1532 {"connect-timeout", 1, 0, 0},
1536 {"no-ssh-agent", 0, 0, 0},
1537 {"identity", 1, 0, 'i'},
1538 {"knownhosts", 1, 0, 'k'},
1541 {"ca-cert", 1, 0, 0},
1542 {"client-cert", 1, 0, 0},
1543 {"client-key", 1, 0, 0},
1544 {"tls-priority", 1, 0, 0},
1545 {"tls-verify", 0, 0, 0},
1546 {"tls-fingerprint", 1, 0, 0},
1549 {"local-pinentry", 0, 0},
1550 {"force-save", 0, 0},
1551 {"ttyname", 1, 0, 'y'},
1552 {"ttytype", 1, 0, 't'},
1553 {"display", 1, 0, 'd'},
1554 {"lc-ctype", 1, 0, 0},
1555 {"lc-messages", 1, 0, 0},
1556 {"timeout", 1, 0, 0},
1558 {"pinentry", 1, 0, 0},
1559 {"key-file", 1, 0, 0},
1560 {"new-key-file", 1, 0, 0},
1561 {"no-lock", 0, 0, 0},
1562 {"lock-timeout", 1, 0, 0},
1563 {"save", 0, 0, 'S'},
1564 {"output-fd", 1, 0, 0},
1565 {"inquire", 1, 0, 0},
1566 {"inquire-fd", 1, 0, 0},
1567 {"inquire-file", 1, 0, 0},
1568 {"inquire-line", 1, 0, 'L'},
1569 {"no-status", 0, 0, 0},
1570 {"name", 1, 0, 'n'},
1571 {"version", 0, 0, 0},
1573 {"keygrip", 1, 0, 0},
1574 {"sign-keygrip", 1, 0, 0},
1575 {"no-passphrase", 0, 0, 0},
1576 {"cipher", 1, 0, 0},
1577 {"key-params", 1, 0, 0},
1578 {"no-pinentry", 0, 0, 0},
1579 {"s2k-count", 1, 0, 0},
1580 {"cipher-iterations", 1, 0, 0},
1582 {"no-gpg-agent", 0, 0, 0},
1583 #ifdef HAVE_LIBREADLINE
1584 {"interactive", 0, 0},
1589 const char *optstring
= "L:y:t:d:P:I:Sn:i:k:";
1591 const char *optstring
= "L:y:t:d:P:I:Sn:";
1596 setlocale (LC_ALL
, "");
1597 bindtextdomain ("libpwmd", LOCALEDIR
);
1600 tries
= DEFAULT_PIN_TRIES
;
1601 inquirefd
= STDIN_FILENO
;
1604 getopt_long (argc
, argv
, optstring
, long_opts
, &opt_index
)) != -1)
1608 /* Handle long options without a short option part. */
1612 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1613 case OPT_SOCKET_TIMEOUT
:
1614 socket_timeout
= strtol (optarg
, &p
, 10);
1616 case OPT_CONNECT_TIMEOUT
:
1617 connect_timeout
= strtol (optarg
, &p
, 10);
1621 case OPT_USE_SSH_AGENT
:
1629 case OPT_CLIENTCERT
:
1630 clientcert
= optarg
;
1642 tls_fingerprint
= optarg
;
1645 case OPT_NO_GPG_AGENT
:
1652 keyfile
= pwmd_strdup (optarg
);
1654 case OPT_NEW_KEYFILE
:
1655 new_keyfile
= pwmd_strdup (optarg
);
1660 case OPT_LOCK_TIMEOUT
:
1661 lock_timeout
= strtol (optarg
, &p
, 10);
1669 case OPT_FORCE_SAVE
:
1670 save
= force_save
= 1;
1673 lcctype
= pwmd_strdup (optarg
);
1675 case OPT_LC_MESSAGES
:
1676 lcmessages
= pwmd_strdup (optarg
);
1679 timeout
= strtol (optarg
, &p
, 10);
1682 tries
= strtol (optarg
, &p
, 10);
1685 inquire
= escape (optarg
);
1687 case OPT_INQUIRE_FD
:
1688 inquirefd
= strtol (optarg
, &p
, 10);
1691 inquirefp
= fdopen (inquirefd
, "r");
1693 err (EXIT_FAILURE
, "%i", inquirefd
);
1696 case OPT_INQUIRE_FILE
:
1697 inquirefd
= open (optarg
, O_RDONLY
);
1698 if (inquirefd
== -1)
1699 err (EXIT_FAILURE
, "%s", optarg
);
1700 inquirefp
= fdopen (inquirefd
, "r");
1703 outfd
= strtol (optarg
, &p
, 10);
1706 outfp
= fdopen (outfd
, "w");
1708 err (EXIT_FAILURE
, "%i", outfd
);
1715 printf ("%s (pwmc)\n\n"
1716 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014\n"
1718 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1719 "Compile-time features:\n"
1720 #ifdef HAVE_LIBREADLINE
1735 #ifdef WITH_PINENTRY
1750 "\n", PACKAGE_STRING
, PACKAGE_BUGREPORT
);
1751 exit (EXIT_SUCCESS
);
1753 pinentry_path
= optarg
;
1756 usage (argv
[0], EXIT_SUCCESS
);
1760 case OPT_SIGN_KEYGRIP
:
1761 sign_keygrip
= optarg
;
1764 s2k_count
= strtoul (optarg
, &p
, 10);
1766 case OPT_ITERATIONS
:
1767 iterations
= strtoull (optarg
, &p
, 10);
1774 case OPT_NOPASSPHRASE
:
1780 case OPT_NO_PINENTRY
:
1783 #ifdef HAVE_LIBREADLINE
1784 case OPT_INTERACTIVE
:
1789 usage (argv
[0], EXIT_FAILURE
);
1794 fprintf (stderr
, N_("%s: invalid argument for option '--%s'\n"),
1795 argv
[0], long_opts
[opt_index
].name
);
1796 usage (argv
[0], EXIT_FAILURE
);
1805 knownhosts
= optarg
;
1809 inquire_line
= optarg
;
1824 clientname
= optarg
;
1827 usage (argv
[0], EXIT_FAILURE
);
1831 #ifdef HAVE_LIBREADLINE
1832 if (interactive
&& !isatty (STDIN_FILENO
))
1833 usage (argv
[0], EXIT_FAILURE
);
1834 else if (isatty (STDIN_FILENO
) && !inquire
&& !inquire_line
)
1838 filename
= argv
[optind
];
1840 gnutls_global_set_mem_functions (pwmd_malloc
, pwmd_malloc
, NULL
,
1841 pwmd_realloc
, pwmd_free
);
1844 rc
= pwmd_new (clientname
, &pwm
);
1848 pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TRIES
, tries
);
1850 fprintf (stderr
, N_("Connecting ...\n"));
1852 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1853 socktype
= is_remote_url (url
);
1854 if (socktype
!= PWMD_SOCKET_LOCAL
)
1857 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1858 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, connect_timeout
);
1863 if (socktype
== PWMD_SOCKET_SSH
)
1866 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_CB
, knownhost_cb
);
1870 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_DATA
, clientname
);
1874 if (!getenv ("SSH_AUTH_SOCK") || identity
)
1877 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_AGENT
, use_ssh_agent
);
1881 rc
= pwmd_connect (pwm
, url
, identity
, knownhosts
);
1887 rc
= pwmd_setopt (pwm
, PWMD_OPTION_TLS_VERIFY
, tls_verify
);
1891 rc
= pwmd_connect (pwm
, url
, clientcert
, clientkey
, cacert
, prio
,
1897 rc
= pwmd_connect (pwm
, url
);
1899 rc
= pwmd_connect (pwm
, url
);
1905 fprintf (stderr
, N_("Connected.\n"));
1908 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1909 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, socket_timeout
);
1916 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1917 "OPTION LOCK-TIMEOUT=%li", lock_timeout
);
1924 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCK_ON_OPEN
, 1);
1929 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, NULL
, NULL
);
1935 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, timeout
);
1940 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
1944 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
,
1945 (local_pin
|| keyfile
|| new_keyfile
));
1951 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_PATH
, pinentry_path
);
1958 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DISPLAY
, display
);
1965 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TTY
, tty
);
1972 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TERM
, ttytype
);
1979 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_CTYPE
, lcctype
);
1986 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_MESSAGES
, lcmessages
);
1993 rc
= pwmd_setopt (pwm
, PWMD_OPTION_STATUS_CB
, status_msg_cb
);
2000 rc
= open_command (filename
);
2005 #ifdef HAVE_LIBREADLINE
2011 rc
= do_interactive ();
2019 struct inquire_s
*inq
= NULL
;
2021 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2023 rc
= pwmd_command (pwm
, &result
, &len
, inquire_cb
, inq
, inquire
);
2029 fcntl (STDIN_FILENO
, F_SETFL
, O_NONBLOCK
);
2034 rc
= process_cmd ();
2039 n
= read (STDIN_FILENO
, command
, sizeof (command
));
2042 if (errno
== EAGAIN
)
2048 rc
= gpg_error_from_errno (errno
);
2059 if (!p
|| !*p
|| !strcasecmp (p
, "BYE"))
2063 struct inquire_s
*inq
= NULL
;
2064 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2067 rc
= parse_dotcommand (command
, &result
, &len
, inq
);
2077 fwrite (result
, 1, result
[len
- 1] == 0 ? len
- 1 : len
, outfp
);
2085 else if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
2086 (void) pwmd_command (pwm
, &result
, NULL
, NULL
, NULL
,
2087 "GETINFO last_error");
2089 #ifdef HAVE_LIBREADLINE
2092 memset (command
, 0, sizeof (command
));
2094 pwmd_free (keyfile
);
2095 pwmd_free (new_keyfile
);
2099 show_error (rc
, result
);
2102 if (connected
&& !quiet
)
2103 fprintf (stderr
, N_("Connection closed.\n"));
2105 exit (rc
? EXIT_FAILURE
: EXIT_SUCCESS
);