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>
43 #include <gnutls/gnutls.h>
50 #ifdef HAVE_GETOPT_LONG
55 #include "getopt_long.h"
58 #ifdef HAVE_LIBREADLINE
59 #if defined(HAVE_READLINE_READLINE_H)
60 #include <readline/readline.h>
61 #elif defined(HAVE_READLINE_H)
63 #endif /* !defined(HAVE_READLINE_H) */
64 static int interactive_error
;
65 static int interactive
;
66 #endif /* HAVE_LIBREADLINE */
68 #ifdef HAVE_READLINE_HISTORY
69 #if defined(HAVE_READLINE_HISTORY_H)
70 #include <readline/history.h>
71 #elif defined(HAVE_HISTORY_H)
74 #endif /* HAVE_READLINE_HISTORY */
81 #define N_(msgid) gettext(msgid)
85 #define DEFAULT_PIN_TIMEOUT 30
86 #define DEFAULT_PIN_TRIES 3
87 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
90 static int no_pinentry
;
92 static char *filename
;
95 static char *sign_keyid
;
96 static char *keyparams
;
98 static char *new_keyfile
;
100 static int local_pin
;
101 static int inquirefd
;
109 size_t size
; // from stat(2).
113 static gpg_error_t
finalize ();
114 static gpg_error_t
set_inquire (int fd
, const char *line
,
115 struct inquire_s
**result
);
116 static gpg_error_t
parse_dotcommand (const char *line
, char **result
,
117 size_t * len
, struct inquire_s
*inq
);
118 static gpg_error_t
open_command (const char *line
);
120 static gpg_error_t
get_password (char **result
, pwmd_pinentry_t w
, int echo
);
124 show_error (pwm_t
*pwm
, gpg_error_t rc
, const char *str
)
127 if (pwmd_tls_error (pwm
))
128 fprintf(stderr
, "TLS: %s\n", gnutls_strerror(pwmd_tls_error(pwm
)));
130 fprintf (stderr
, "ERR %i: %s%s%s%s", rc
, gpg_strerror (rc
),
131 str
? ": " : "", str
? str
: "", str
? "" : "\n");
135 usage (const char *pn
, int status
)
137 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
138 N_("Usage: pwmc [options] [file]\n"
140 " a url string to connect to (%s, 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 (0=disabled, 120)\n"
144 " --socket-timeout <seconds>\n"
145 " seconds before a remote command fails (0=disabled, 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-256 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 (50)\n"
173 " --name, -n <string>\n"
174 " set the client name\n"
175 " --pinentry <path>\n"
176 " the full path to the pinentry binary\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"
208 " --key-file <filename>\n"
209 " obtain the passphrase from the specified filename\n"
210 " --new-key-file <filename>\n"
211 " obtain the passphrase to save with from the specified filename\n"
212 " --key-params <string>\n"
213 " the key parameters to use when saving a new file (pwmd default)\n"
214 " --keyid <recipient>[,<recipient>]\n"
215 " the public key ID to u\n"
216 " --sign-keyid <string>\n"
217 " the key ID to sign the data file with\n"
219 " disable showing of status messages from the server\n"
221 " disable showing of extra messages (implies --no-status)\n"
222 #ifdef HAVE_LIBREADLINE
224 " use a shell like interface to pwmd (allows more than one command)\n"
228 #ifdef DEFAULT_PWMD_SOCKET
234 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
236 "An optional url may be in the form of:\n"
237 " --url /path/to/socket\n"
238 " --url file://[path/to/socket]\n"
241 " --url ssh[46]://[username@]hostname[:port]\n"
242 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
246 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
247 " --client-key filename\n"
249 #ifdef HAVE_LIBREADLINE
251 "Interactive mode is used when input is from a terminal.\n"
258 inquire_cb (void *user
, const char *keyword
, gpg_error_t rc
,
259 char **data
, size_t * size
)
261 struct inquire_s
*inq
= user
;
263 int is_newpassword
= 0;
271 if (!strcmp (keyword
, "PASSPHRASE"))
273 else if (!strcmp (keyword
, "NEW_PASSPHRASE"))
275 #ifdef HAVE_LIBREADLINE
276 else if (!strcmp (keyword
, "KEYPARAM") && !interactive
)
279 else if (!strcmp (keyword
, "KEYPARAM"))
282 if (!keyparams
|| !*keyparams
)
283 return gpg_error (GPG_ERR_INV_PARAMETER
);
286 *size
= strlen (keyparams
);
287 return gpg_error (GPG_ERR_EOF
);
290 if ((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
))
292 int fd
= open (is_password
? keyfile
: new_keyfile
, O_RDONLY
);
296 fprintf (stderr
, "%s: %s\n", is_newpassword
? new_keyfile
: keyfile
,
298 return gpg_error_from_syserror ();
301 rc
= set_inquire (fd
, NULL
, &inq
);
309 fprintf (stderr
, N_("Using keyfile '%s' as %s.\n"),
310 is_newpassword
? new_keyfile
: keyfile
, keyword
);
312 if (!new_keyfile
|| is_newpassword
)
316 pwmd_socket_type (pwm
, &t
);
317 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
318 if (!no_pinentry
&& t
== PWMD_SOCKET_LOCAL
)
319 pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 0);
322 else if ((is_password
&& !keyfile
) || (is_newpassword
&& !new_keyfile
))
326 rc
= pwmd_password (pwm
, keyword
, &tmp
, &inq
->len
);
327 if (rc
&& gpg_err_code (rc
) != GPG_ERR_EOF
)
330 pwmd_free (inq
->line
);
334 return gpg_error (GPG_ERR_EOF
);
336 #ifdef HAVE_LIBREADLINE
337 else if ((!inq
->last_keyword
|| strcmp (keyword
, inq
->last_keyword
))
342 ("%sPress CTRL-D to send the current line. Press twice to end. %s:\n"),
343 inq
->last_keyword
? "\n" : "", keyword
);
344 pwmd_free (inq
->last_keyword
);
345 inq
->last_keyword
= pwmd_strdup (keyword
);
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"))
388 else if (!strncmp (line
, "GPGME", 5))
390 else if (!strncmp (line
, "PASSPHRASE_HINT", 15))
392 else if (!strncmp (line
, "PASSPHRASE_INFO", 15))
395 if (*line
!= '#' && p
&& strchr (p
, ' ') && *++p
)
397 char *p1
= strchr (p
, ' ');
398 int a
= strtol (p
, NULL
, 10);
400 if (isdigit (*p
) && p1
)
402 int b
= strtol (p1
, NULL
, 10);
404 int t
= a
&& b
? a
* 100 / b
: 0;
406 strncpy (l
, line
, strlen (line
) - strlen (p
) - 1);
407 fprintf (stderr
, "\r%s %i/%i %i%%%s", l
, a
, b
, t
,
414 fprintf (stderr
, "%s\n", line
);
416 #ifdef HAVE_LIBREADLINE
425 return pwmd_process (pwm
);
430 get_password (char **result
, pwmd_pinentry_t w
, int echo
)
432 char buf
[LINE_MAX
] = { 0 }, *p
;
433 struct termios told
, tnew
;
438 if (!isatty (STDIN_FILENO
))
440 fprintf (stderr
, N_("Input is not from a terminal! Failing.\n"));
441 return GPG_ERR_ENOTTY
;
446 if (tcgetattr (STDIN_FILENO
, &told
) == -1)
447 return gpg_error_from_syserror ();
449 memcpy (&tnew
, &told
, sizeof (struct termios
));
450 tnew
.c_lflag
&= ~(ECHO
);
451 tnew
.c_lflag
|= ICANON
| ECHONL
;
453 if (tcsetattr (STDIN_FILENO
, TCSANOW
, &tnew
) == -1)
457 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
458 return gpg_error_from_errno (n
);
464 case PWMD_PINENTRY_OPEN
:
465 fprintf (stderr
, N_("Password for %s: "), filename
);
467 case PWMD_PINENTRY_OPEN_FAILED
:
468 fprintf (stderr
, N_("Invalid password. Password for %s: "), filename
);
470 case PWMD_PINENTRY_SAVE
:
471 fprintf (stderr
, N_("New password for %s: "), filename
);
473 case PWMD_PINENTRY_SAVE_CONFIRM
:
474 fprintf (stderr
, N_("Confirm password: "));
480 if ((p
= fgets (buf
, sizeof (buf
), stdin
)) == NULL
)
482 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
487 tcsetattr (STDIN_FILENO
, TCSANOW
, &told
);
492 return GPG_ERR_CANCELED
;
495 p
[strlen (p
) - 1] = 0;
499 key
= pwmd_strdup_printf ("%s", p
);
500 memset (&buf
, 0, sizeof (buf
));
503 return GPG_ERR_ENOMEM
;
511 knownhost_cb (void *data
, const char *host
, const char *key
, size_t len
)
515 pwmd_strdup_printf (N_
516 ("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?"),
517 (char *) data
, host
, host
);
519 if (no_pinentry
&& !isatty (STDIN_FILENO
))
521 fprintf (stderr
, N_("Input is not from a terminal! Failing.\n"));
523 return GPG_ERR_ENOTTY
;
525 else if (no_pinentry
)
527 for (char *p
= buf
, len
= 0; *p
; p
++, len
++)
536 while (!isspace (*(--p
)));
543 fprintf (stderr
, "%s\n\n", buf
);
550 fprintf (stderr
, N_("Trust this connection [y/N]: "));
552 rc
= get_password (&result
, PWMD_PINENTRY_CONFIRM
, 1);
557 if (!result
|| !*result
|| *result
== 'n' || *result
== 'N')
559 if (result
&& *result
)
562 return GPG_ERR_NOT_CONFIRMED
;
565 if ((*result
== 'y' || *result
== 'Y') && *(result
+ 1) == 0)
574 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, buf
);
580 return pwmd_getpin (pwm
, NULL
, NULL
, NULL
, PWMD_PINENTRY_CONFIRM
);
584 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
586 is_remote_url (const char *str
)
589 return PWMD_SOCKET_LOCAL
;
592 if (strstr (str
, "ssh://") || strstr (str
, "ssh4://")
593 || strstr (str
, "ssh6://"))
594 return PWMD_SOCKET_SSH
;
598 if (strstr (str
, "tls://") || strstr (str
, "tls4://")
599 || strstr (str
, "tls6://"))
600 return PWMD_SOCKET_TLS
;
603 return PWMD_SOCKET_LOCAL
;
608 escape (const char *str
)
611 char *buf
= pwmd_malloc (ASSUAN_LINELENGTH
+ 1), *b
= buf
;
614 for (p
= str
; *p
; p
++, len
++)
616 if (len
== ASSUAN_LINELENGTH
)
660 free_inquire (struct inquire_s
*inq
)
665 pwmd_free (inq
->line
);
667 if (inq
->fd
!= -1 && inq
->fd
!= STDIN_FILENO
)
670 pwmd_free (inq
->last_keyword
);
674 /* When *result is not NULL it is updated to the new values and not
677 set_inquire (int fd
, const char *line
, struct inquire_s
**result
)
679 struct inquire_s inq
= { 0 };
680 struct stat st
= { 0 };
685 if (fstat (fd
, &st
) == -1)
686 return gpg_error_from_syserror ();
688 inq
.size
= st
.st_size
;
692 inq
.line
= pwmd_calloc (1, ASSUAN_LINELENGTH
);
694 return GPG_ERR_ENOMEM
;
698 char *s
= escape (line
);
702 pwmd_free (inq
.line
);
703 return GPG_ERR_ENOMEM
;
706 if (strlen (s
) >= ASSUAN_LINELENGTH
)
708 pwmd_free (inq
.line
);
710 return GPG_ERR_LINE_TOO_LONG
;
713 strncpy (inq
.line
, s
, ASSUAN_LINELENGTH
- 1);
714 inq
.len
= strlen (s
);
718 rc
= pwmd_setopt (pwm
, PWMD_OPTION_INQUIRE_TOTAL
,
719 st
.st_size
? st
.st_size
+ strlen (inq
.line
) : 0);
722 pwmd_free (inq
.line
);
727 *result
= pwmd_malloc (sizeof (struct inquire_s
));
730 if ((*result
)->fd
!= -1 && (*result
)->fd
!= STDIN_FILENO
)
731 close ((*result
)->fd
);
733 pwmd_free ((*result
)->line
);
734 (*result
)->line
= NULL
;
739 memcpy (*result
, &inq
, sizeof (struct inquire_s
));
740 memset (&inq
, 0, sizeof (struct inquire_s
));
744 #ifdef HAVE_LIBREADLINE
746 interactive_hook (void)
748 interactive_error
= process_cmd ();
750 if (interactive_error
)
751 rl_event_hook
= NULL
;
761 ("------------------------------------------------------------------------------\n"
762 "Elements are TAB delimited. Press CTRL-V then TAB to insert from the prompt.\n"
764 "Type HELP for protocol commands. Type .help for pwmc commands. Press CTRL-D\n"
766 "------------------------------------------------------------------------------\n"));
771 parse_arg (const char *src
, char *dst
, size_t len
)
777 for (; s
&& *s
&& *s
!= ' ' && n
< len
; s
++, n
++)
785 parse_opt (char **line
, const char *opt
, gpg_error_t
* rc
)
787 static char result
[ASSUAN_LINELENGTH
] = { 0 }, *r
= result
;
788 char *s
= strstr (*line
, opt
);
798 size_t rlen
= strlen (opt
);
802 while (*p
&& *p
== ' ')
808 for (; *p
&& len
< sizeof (result
) - 1; p
++, rlen
++)
810 if (isspace (*p
) && !quote
)
813 if (*p
== '\"' && lastc
!= '\\')
826 if (len
>= sizeof (result
) - 1)
827 *rc
= GPG_ERR_LINE_TOO_LONG
;
832 while (*p
&& *p
== ' ')
843 read_command (const char *line
, char **result
, size_t * len
)
847 char *filename
= NULL
;
848 struct inquire_s
*inq
= NULL
;
849 char *p
= (char *) line
;
850 const char *prefix
= parse_opt (&p
, "--prefix", &rc
);
859 char filebuf
[ASSUAN_LINELENGTH
];
861 while (*p
&& isspace (*p
))
864 filename
= parse_arg (p
, filebuf
, sizeof (filebuf
));
865 if (filename
&& *filename
)
867 p
+= strlen (filename
) + 1;
869 while (*p
&& isspace (*p
))
881 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
884 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\" = \")\n"));
888 fd
= open (filename
, O_RDONLY
);
890 return gpg_error_from_syserror ();
892 rc
= set_inquire (fd
, prefix
&& *prefix
? prefix
: NULL
, &inq
);
899 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, p
);
905 redir_command (const char *line
)
907 const char *p
= line
;
909 gpg_error_t rc
= GPG_ERR_SYNTAX
;
910 char *filename
= NULL
;
911 struct inquire_s
*inq
= NULL
;
917 char filebuf
[ASSUAN_LINELENGTH
];
919 filename
= parse_arg (p
, filebuf
, sizeof (filebuf
));
920 if (filename
&& *filename
)
922 p
+= strlen (filename
) + 1;
924 while (*p
&& isspace (*p
))
934 fprintf (stderr
, N_("Usage: .redir <filename> <command> [args]\n"));
938 fd
= open (filename
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600);
940 return gpg_error_from_syserror ();
942 #ifdef HAVE_LIBREADLINE
943 rc
= set_inquire (interactive
? STDIN_FILENO
: inquirefd
, NULL
, &inq
);
945 rc
= set_inquire (inquirefd
, NULL
, &inq
);
953 rc
= parse_dotcommand (p
, &result
, &len
, inq
);
954 if (!rc
&& result
&& len
--)
955 { // null byte which is always appended
956 if (write (fd
, result
, len
) != len
)
957 rc
= GPG_ERR_TOO_SHORT
;
967 help_command (const char *line
)
970 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
971 " .redir <filename> <command>\n"
972 " redirect the output of a command to the specified file\n"
974 " .open <filename>\n"
975 " open the specified filename losing any changes to the current one\n"
977 " .read [--prefix <string>] <filename> <command> [args]\n"
978 " obtain data from the specified filename for an inquire command\n"
980 " .set help | <name> [<value>]\n"
981 " set option <name> to <value>\n"
984 " write changes of the file to disk\n"
987 " change the passphrase of a data file\n"
990 " this help text\n"));
995 open_command (const char *line
)
997 struct inquire_s
*inq
= NULL
;
998 const char *filename
= line
;
1001 while (filename
&& isspace (*filename
))
1004 if (!filename
|| !*filename
)
1006 fprintf (stderr
, N_("Usage: .open <filename>\n"));
1007 return GPG_ERR_SYNTAX
;
1010 #ifdef HAVE_LIBREADLINE
1011 if (interactive
|| !quiet
)
1015 fprintf (stderr
, N_("Opening data file \"%s\" ...\n"), filename
);
1017 #ifdef HAVE_LIBREADLINE
1018 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1020 rc
= set_inquire (-1, NULL
, &inq
);
1026 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1028 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1030 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
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;
1066 if (!strcmp (name
, "keyfile"))
1071 pwmd_free (new_keyfile
);
1076 pwmd_free (keyfile
);
1080 p
+= strlen (valuep
);
1081 while (p
&& *p
&& isspace (*p
))
1084 valuep
= (char *) p
;
1088 new_keyfile
= pwmd_strdup (value
);
1090 keyfile
= pwmd_strdup (value
);
1094 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 1);
1096 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1099 else if (!local_pin
&& !no_pinentry
)
1103 pwmd_socket_type (pwm
, &t
);
1104 if (t
== PWMD_SOCKET_LOCAL
)
1106 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, 0);
1108 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1112 else if (!strcmp(name
, "pinentry-timeout"))
1115 int n
= strtol(valuep
, &e
, 10);
1118 return gpg_error (GPG_ERR_INV_VALUE
);
1120 if (!valuep
|| !*valuep
)
1121 n
= DEFAULT_PIN_TIMEOUT
;
1123 rc
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, n
);
1125 else if (!strcmp (name
, "help"))
1129 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1130 "delimited. When no value is specified the option is unset.\n\n"
1131 "keyfile <datafile> [<filename>]\n"
1132 " set or unset the keyfile to be used when a passphrase is required (*)\n"
1134 "new-keyfile <datafile> [<filename>]\n"
1135 " set or unset the keyfile to be used when a new passphrase is required (*)\n"
1137 "pinentry-timeout <seconds>\n"
1138 " the amount of seconds before pinentry gives up waiting for input\n"
1140 "* = the next protocol command will unset this value\n"
1144 rc
= GPG_ERR_UNKNOWN_OPTION
;
1150 save_command (const char *line
)
1152 struct inquire_s
*inq
= NULL
;
1155 #ifdef HAVE_LIBREADLINE
1156 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1158 rc
= set_inquire (-1, NULL
, &inq
);
1163 if (new_keyfile
|| keyfile
)
1164 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1166 rc
= pwmd_save (pwm
, line
, inquire_cb
, inq
);
1167 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1173 do_save_passwd_command (const char *line
, int save
)
1175 struct inquire_s
*inq
= NULL
;
1178 #ifdef HAVE_LIBREADLINE
1179 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1181 rc
= set_inquire (-1, NULL
, &inq
);
1186 if (new_keyfile
|| keyfile
)
1187 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1190 rc
= pwmd_save (pwm
, line
, inquire_cb
, inq
);
1192 rc
= pwmd_passwd (pwm
, line
, inquire_cb
, inq
);
1194 pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1200 parse_dotcommand (const char *line
, char **result
,
1201 size_t * len
, struct inquire_s
*inq
)
1203 const char *p
= line
;
1206 if (!strncmp (p
, ".read", 5))
1207 rc
= read_command (p
+ 5, result
, len
);
1208 else if (!strncmp (p
, ".redir", 6))
1209 rc
= redir_command (p
+ 6);
1210 else if (!strncmp (p
, ".help", 5))
1211 rc
= help_command (p
+ 5);
1212 else if (!strncmp (p
, ".open", 5))
1213 rc
= open_command (p
+ 5);
1214 else if (!strncmp (p
, ".set", 4))
1215 rc
= set_command (p
+ 4);
1216 else if (!strncmp (p
, ".save", 5))
1217 rc
= do_save_passwd_command (p
+ 5, 1);
1218 else if (!strncmp (p
, ".passwd", 7))
1219 rc
= do_save_passwd_command (p
+ 7, 0);
1222 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, line
);
1223 #ifdef HAVE_LIBREADLINE
1227 pwmd_free (keyfile
);
1228 pwmd_free (new_keyfile
);
1229 keyfile
= new_keyfile
= NULL
;
1230 #ifdef HAVE_LIBREADLINE
1238 #ifdef HAVE_LIBREADLINE
1243 struct inquire_s
*inq
= NULL
;
1246 rc
= process_cmd ();
1250 rc
= set_inquire (STDIN_FILENO
, NULL
, &inq
);
1255 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1257 rl_event_hook
= &interactive_hook
;
1258 rl_set_keyboard_input_timeout (100000);
1263 char *result
= NULL
;
1267 line
= readline ("pwm> ");
1268 if (interactive_error
)
1271 rc
= interactive_error
;
1281 if (gpg_err_code (rc
) != GPG_ERR_CANCELED
&&
1282 gpg_err_code (rc
) != GPG_ERR_EOF
)
1283 fprintf (stderr
, "ERR %i: %s\n", rc
, gpg_strerror (rc
));
1293 #ifdef HAVE_READLINE_HISTORY
1296 rc
= parse_dotcommand (line
, &result
, &len
, inq
);
1302 if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
1303 (void) pwmd_command (pwm
, &tmp
, NULL
, NULL
, NULL
,
1304 "GETINFO last_error");
1306 show_error (pwm
, rc
, tmp
);
1309 else if (result
&& len
)
1310 printf ("%s%s", result
, result
[len
- 1] != '\n' ? "\n" : "");
1324 #ifdef HAVE_LIBREADLINE
1331 fprintf (stderr
, "\n");
1339 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1340 p
= fgets (buf
, sizeof (buf
), stdin
);
1354 return GPG_ERR_CANCELED
;
1358 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1359 "CLEARCACHE %s", filename
);
1363 interactive_hook ();
1379 if (save
&& !filename
)
1383 ("No filename was specified on the command line. Aborting.\n"));
1384 return GPG_ERR_CANCELED
;
1387 if (save
&& filename
)
1390 pwmd_strdup_printf ("%s%s %s%s %s",
1391 keyid
? "--keyid=" : "",
1393 sign_keyid
? "--sign-keyid=" : "",
1394 sign_keyid
? sign_keyid
: "",
1395 keyparams
? "--inquire-keyparam" : "");
1397 #ifdef HAVE_LIBREADLINE
1398 if (!quiet
|| interactive
)
1404 fprintf (stderr
, "\n");
1405 fprintf (stderr
, N_("Saving changes ...\n"));
1408 rc
= save_command (args
);
1412 #ifdef HAVE_LIBREADLINE
1414 return rc
? rc
: quit
? 0 : GPG_ERR_CANCELED
;
1421 main (int argc
, char *argv
[])
1426 char command
[ASSUAN_LINELENGTH
], *p
= NULL
;
1427 char *result
= NULL
;
1429 char *pinentry_path
= NULL
;
1430 char *display
= NULL
, *tty
= NULL
, *ttytype
= NULL
;
1431 char *lcctype
= NULL
, *lcmessages
= NULL
;
1432 int outfd
= STDOUT_FILENO
;
1433 FILE *outfp
= stdout
;
1434 FILE *inquirefp
= stdin
;
1435 int show_status
= 1;
1436 char *clientname
= "pwmc";
1437 char *inquire
= NULL
;
1438 char *inquire_line
= NULL
;
1441 int use_ssh_agent
= 1;
1442 char *knownhosts
= NULL
;
1443 char *identity
= NULL
;
1446 char *cacert
= NULL
;
1447 char *clientcert
= NULL
;
1448 char *clientkey
= NULL
;
1451 char *tls_fingerprint
= NULL
;
1453 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1454 pwmd_socket_t socktype
;
1455 long socket_timeout
= 300;
1456 int connect_timeout
= 120;
1458 int lock_on_open
= 1;
1459 long lock_timeout
= 50;
1461 /* The order is important. */
1464 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1465 OPT_SOCKET_TIMEOUT
, OPT_CONNECT_TIMEOUT
,
1468 OPT_USE_SSH_AGENT
, OPT_IDENTITY
, OPT_KNOWNHOSTS
,
1471 OPT_CACERT
, OPT_CLIENTCERT
, OPT_CLIENTKEY
, OPT_PRIORITY
, OPT_VERIFY
,
1474 OPT_URL
, OPT_LOCAL
, OPT_TTYNAME
, OPT_TTYTYPE
,
1475 OPT_DISPLAY
, OPT_LC_CTYPE
, OPT_LC_MESSAGES
, OPT_TIMEOUT
, OPT_TRIES
,
1476 OPT_PINENTRY
, OPT_KEYFILE
, OPT_NEW_KEYFILE
, OPT_NOLOCK
,
1477 OPT_LOCK_TIMEOUT
, OPT_SAVE
, OPT_OUTPUT_FD
, OPT_INQUIRE
,
1478 OPT_INQUIRE_FD
, OPT_INQUIRE_FILE
, OPT_INQUIRE_LINE
, OPT_NO_STATUS
,
1479 OPT_NAME
, OPT_VERSION
, OPT_HELP
, OPT_KEYID
, OPT_SIGN_KEYID
,
1480 OPT_KEYPARAMS
, OPT_NO_PINENTRY
, OPT_QUIET
,
1481 #ifdef HAVE_LIBREADLINE
1485 const struct option long_opts
[] = {
1486 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1487 {"socket-timeout", 1, 0, 0},
1488 {"connect-timeout", 1, 0, 0},
1492 {"no-ssh-agent", 0, 0, 0},
1493 {"identity", 1, 0, 'i'},
1494 {"knownhosts", 1, 0, 'k'},
1497 {"ca-cert", 1, 0, 0},
1498 {"client-cert", 1, 0, 0},
1499 {"client-key", 1, 0, 0},
1500 {"tls-priority", 1, 0, 0},
1501 {"tls-verify", 0, 0, 0},
1502 {"tls-fingerprint", 1, 0, 0},
1505 {"local-pinentry", 0, 0},
1506 {"ttyname", 1, 0, 'y'},
1507 {"ttytype", 1, 0, 't'},
1508 {"display", 1, 0, 'd'},
1509 {"lc-ctype", 1, 0, 0},
1510 {"lc-messages", 1, 0, 0},
1511 {"timeout", 1, 0, 0},
1513 {"pinentry", 1, 0, 0},
1514 {"key-file", 1, 0, 0},
1515 {"new-key-file", 1, 0, 0},
1516 {"no-lock", 0, 0, 0},
1517 {"lock-timeout", 1, 0, 0},
1518 {"save", 0, 0, 'S'},
1519 {"output-fd", 1, 0, 0},
1520 {"inquire", 1, 0, 0},
1521 {"inquire-fd", 1, 0, 0},
1522 {"inquire-file", 1, 0, 0},
1523 {"inquire-line", 1, 0, 'L'},
1524 {"no-status", 0, 0, 0},
1525 {"name", 1, 0, 'n'},
1526 {"version", 0, 0, 0},
1529 {"sign-keyid", 1, 0, 0},
1530 {"key-params", 1, 0, 0},
1531 {"no-pinentry", 0, 0, 0},
1533 #ifdef HAVE_LIBREADLINE
1534 {"interactive", 0, 0},
1539 const char *optstring
= "L:y:t:d:P:I:Sn:i:k:";
1541 const char *optstring
= "L:y:t:d:P:I:Sn:";
1546 setlocale (LC_ALL
, "");
1547 bindtextdomain ("libpwmd", LOCALEDIR
);
1550 tries
= DEFAULT_PIN_TRIES
;
1551 inquirefd
= STDIN_FILENO
;
1554 getopt_long (argc
, argv
, optstring
, long_opts
, &opt_index
)) != -1)
1558 /* Handle long options without a short option part. */
1562 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1563 case OPT_SOCKET_TIMEOUT
:
1564 socket_timeout
= strtol (optarg
, &p
, 10);
1566 case OPT_CONNECT_TIMEOUT
:
1567 connect_timeout
= strtol (optarg
, &p
, 10);
1571 case OPT_USE_SSH_AGENT
:
1579 case OPT_CLIENTCERT
:
1580 clientcert
= optarg
;
1592 tls_fingerprint
= optarg
;
1599 keyfile
= pwmd_strdup (optarg
);
1601 case OPT_NEW_KEYFILE
:
1602 new_keyfile
= pwmd_strdup (optarg
);
1607 case OPT_LOCK_TIMEOUT
:
1608 lock_timeout
= strtol (optarg
, &p
, 10);
1617 lcctype
= pwmd_strdup (optarg
);
1619 case OPT_LC_MESSAGES
:
1620 lcmessages
= pwmd_strdup (optarg
);
1623 timeout
= strtol (optarg
, &p
, 10);
1626 tries
= strtol (optarg
, &p
, 10);
1629 inquire
= escape (optarg
);
1631 case OPT_INQUIRE_FD
:
1632 inquirefd
= strtol (optarg
, &p
, 10);
1635 inquirefp
= fdopen (inquirefd
, "r");
1637 err (EXIT_FAILURE
, "%i", inquirefd
);
1640 case OPT_INQUIRE_FILE
:
1641 inquirefd
= open (optarg
, O_RDONLY
);
1642 if (inquirefd
== -1)
1643 err (EXIT_FAILURE
, "%s", optarg
);
1644 inquirefp
= fdopen (inquirefd
, "r");
1647 outfd
= strtol (optarg
, &p
, 10);
1650 outfp
= fdopen (outfd
, "w");
1652 err (EXIT_FAILURE
, "%i", outfd
);
1659 printf ("%s (pwmc)\n\n"
1660 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014\n"
1662 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1663 "Compile-time features:\n"
1664 #ifdef HAVE_LIBREADLINE
1679 #ifdef WITH_PINENTRY
1694 "\n", PACKAGE_STRING
, PACKAGE_BUGREPORT
);
1695 exit (EXIT_SUCCESS
);
1697 pinentry_path
= optarg
;
1700 usage (argv
[0], EXIT_SUCCESS
);
1704 case OPT_SIGN_KEYID
:
1705 sign_keyid
= optarg
;
1711 case OPT_NO_PINENTRY
:
1714 #ifdef HAVE_LIBREADLINE
1715 case OPT_INTERACTIVE
:
1720 usage (argv
[0], EXIT_FAILURE
);
1725 fprintf (stderr
, N_("%s: invalid argument for option '--%s'\n"),
1726 argv
[0], long_opts
[opt_index
].name
);
1727 usage (argv
[0], EXIT_FAILURE
);
1736 knownhosts
= optarg
;
1740 inquire_line
= optarg
;
1755 clientname
= optarg
;
1758 usage (argv
[0], EXIT_FAILURE
);
1762 #ifdef HAVE_LIBREADLINE
1763 if (interactive
&& !isatty (STDIN_FILENO
))
1764 usage (argv
[0], EXIT_FAILURE
);
1765 else if (isatty (STDIN_FILENO
) && !inquire
&& !inquire_line
)
1769 filename
= argv
[optind
];
1771 gnutls_global_set_mem_functions (pwmd_malloc
, pwmd_malloc
, NULL
,
1772 pwmd_realloc
, pwmd_free
);
1775 rc
= pwmd_new (clientname
, &pwm
);
1779 pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TRIES
, tries
);
1781 fprintf (stderr
, N_("Connecting ...\n"));
1783 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1784 socktype
= is_remote_url (url
);
1785 if (socktype
!= PWMD_SOCKET_LOCAL
)
1788 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1789 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, connect_timeout
);
1794 if (socktype
== PWMD_SOCKET_SSH
)
1797 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_CB
, knownhost_cb
);
1801 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_DATA
, clientname
);
1805 if (!getenv ("SSH_AUTH_SOCK") || identity
)
1808 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_AGENT
, use_ssh_agent
);
1812 rc
= pwmd_connect (pwm
, url
, identity
, knownhosts
);
1818 rc
= pwmd_setopt (pwm
, PWMD_OPTION_TLS_VERIFY
, tls_verify
);
1822 rc
= pwmd_connect (pwm
, url
, clientcert
, clientkey
, cacert
, prio
,
1828 rc
= pwmd_connect (pwm
, url
);
1830 rc
= pwmd_connect (pwm
, url
);
1836 fprintf (stderr
, N_("Connected.\n"));
1839 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1840 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, socket_timeout
);
1847 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1848 "OPTION LOCK-TIMEOUT=%li", lock_timeout
);
1855 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCK_ON_OPEN
, 1);
1860 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, NULL
, NULL
);
1866 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, timeout
);
1871 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
1875 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
,
1876 (local_pin
|| keyfile
|| new_keyfile
));
1882 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_PATH
, pinentry_path
);
1889 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DISPLAY
, display
);
1896 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TTY
, tty
);
1903 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TERM
, ttytype
);
1910 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_CTYPE
, lcctype
);
1917 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_MESSAGES
, lcmessages
);
1924 rc
= pwmd_setopt (pwm
, PWMD_OPTION_STATUS_CB
, status_msg_cb
);
1931 rc
= open_command (filename
);
1936 #ifdef HAVE_LIBREADLINE
1939 rc
= do_interactive ();
1947 struct inquire_s
*inq
= NULL
;
1949 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
1951 rc
= pwmd_command (pwm
, &result
, &len
, inquire_cb
, inq
, inquire
);
1957 fcntl (STDIN_FILENO
, F_SETFL
, O_NONBLOCK
);
1962 rc
= process_cmd ();
1967 n
= read (STDIN_FILENO
, command
, sizeof (command
));
1970 if (errno
== EAGAIN
)
1976 rc
= gpg_error_from_errno (errno
);
1987 if (!p
|| !*p
|| !strcasecmp (p
, "BYE"))
1991 struct inquire_s
*inq
= NULL
;
1992 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
1995 rc
= parse_dotcommand (command
, &result
, &len
, inq
);
2005 fwrite (result
, 1, result
[len
- 1] == 0 ? len
- 1 : len
, outfp
);
2013 else if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
2014 (void) pwmd_command (pwm
, &result
, NULL
, NULL
, NULL
,
2015 "GETINFO last_error");
2017 #ifdef HAVE_LIBREADLINE
2020 memset (command
, 0, sizeof (command
));
2023 show_error (pwm
, rc
, result
);
2026 pwmd_free (keyfile
);
2027 pwmd_free (new_keyfile
);
2030 if (connected
&& !quiet
)
2031 fprintf (stderr
, N_("Connection closed.\n"));
2033 exit (rc
? EXIT_FAILURE
: EXIT_SUCCESS
);