pwmc: Fix passphrase file logic in inquire callback.
[libpwmd.git] / src / pwmc.c
blob98ad6376d67b7ff6f17d5a1719f20c0da65ec418
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015,
3 2016
4 Ben Kibbey <bjk@luxsci.net>
6 This file is part of libpwmd.
8 Libpwmd is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
13 Libpwmd is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Libpwmd. If not, see <http://www.gnu.org/licenses/>.
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <stdint.h>
29 #include <err.h>
30 #include <errno.h>
31 #include <string.h>
32 #include <libpwmd.h>
33 #include <assuan.h>
34 #include <sys/select.h>
35 #include <fcntl.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <libgen.h>
39 #include <termios.h>
40 #include <limits.h>
41 #include <ctype.h>
43 #ifdef WITH_GNUTLS
44 #include <gnutls/gnutls.h>
45 #endif
47 #ifdef HAVE_LOCALE_H
48 #include <locale.h>
49 #endif
51 #ifdef HAVE_GETOPT_LONG
52 #ifdef HAVE_GETOPT_H
53 #include <getopt.h>
54 #endif
55 #else
56 #include "getopt_long.h"
57 #endif
59 #ifdef HAVE_LIBREADLINE
60 #if defined(HAVE_READLINE_READLINE_H)
61 #include <readline/readline.h>
62 #elif defined(HAVE_READLINE_H)
63 #include <readline.h>
64 #endif /* !defined(HAVE_READLINE_H) */
65 static int interactive_error;
66 static int interactive;
67 #endif /* HAVE_LIBREADLINE */
69 #ifdef HAVE_READLINE_HISTORY
70 #if defined(HAVE_READLINE_HISTORY_H)
71 #include <readline/history.h>
72 #elif defined(HAVE_HISTORY_H)
73 #include <history.h>
74 #endif
75 #endif /* HAVE_READLINE_HISTORY */
77 #ifndef LINE_MAX
78 #define LINE_MAX 2048
79 #endif
81 #include "gettext.h"
82 #define N_(msgid) gettext(msgid)
84 #include "mem.h"
87 #define DEFAULT_STATUS_IGNORE "KEEPALIVE,STATE,GPGME,PASSPHRASE_INFO,PASSPHRASE_HINT"
88 #define DEFAULT_PIN_TIMEOUT 30
89 #define DEFAULT_PIN_TRIES 3
90 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
91 ? gpg_error(rc) : rc
93 static int no_pinentry;
94 static pwm_t *pwm;
95 static char *filename;
96 static int save;
97 static char *keyid;
98 static char *sign_keyid;
99 static int symmetric;
100 static char *keyparams;
101 static char *keyfile;
102 static char *new_keyfile;
103 static char *sign_keyfile;
104 static int tries;
105 static int local_pin;
106 static int inquirefd;
107 static int statusfd;
108 FILE *statusfp;
109 static int quiet;
110 static char **status_ignore;
112 struct inquire_s
114 int fd;
115 char *line;
116 size_t len;
117 size_t size; // from stat(2).
118 char *last_keyword;
121 static gpg_error_t finalize ();
122 static gpg_error_t set_inquire (int fd, const char *line,
123 struct inquire_s **result);
124 static gpg_error_t parse_dotcommand (const char *line, char **result,
125 size_t * len, struct inquire_s *inq);
126 static gpg_error_t open_command (char *line);
127 #ifdef WITH_SSH
128 static gpg_error_t get_password (char **result, pwmd_pinentry_t w, int echo);
129 #endif
131 static void
132 show_error (pwm_t *pwm, gpg_error_t rc, const char *str)
134 #ifdef WITH_GNUTLS
135 if (pwmd_tls_error (pwm))
136 fprintf(stderr, "TLS: %s\n", gnutls_strerror(pwmd_tls_error(pwm)));
137 #endif
138 fprintf (stderr, "ERR %i: %s%s%s%s", rc, gpg_strerror (rc),
139 str ? ": " : "", str ? str : "", str ? "" : "\n");
142 static void
143 reset_keyfiles ()
145 pwmd_free (keyfile);
146 pwmd_free (new_keyfile);
147 pwmd_free (sign_keyfile);
148 keyfile = new_keyfile = sign_keyfile = NULL;
151 static void
152 usage (const char *pn, int status)
154 fprintf (status == EXIT_FAILURE ? stderr : stdout,
155 N_("Usage: pwmc [options] [file]\n"
156 " --url <string>\n"
157 " a url string to connect to (%s, see below)\n"
158 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
159 " --connect-timeout <seconds>\n"
160 " seconds before connecting to a remote host fails (0=disabled, 120)\n"
161 " --socket-timeout <seconds>\n"
162 " seconds before a remote command fails (0=disabled, 300)\n"
163 #endif
164 #ifdef WITH_GNUTLS
165 " --ca-cert <filename>\n"
166 " certificate authority (CA) used to sign the server cert\n"
167 " --client-cert <filename>\n"
168 " client certificate to use for authentication\n"
169 " --client-key <filename>\n"
170 " key file used to protect the client certificate\n"
171 " --tls-priority <string>\n"
172 " compression, cipher and hash algorithm string\n"
173 " (SECURE256:SECURE192:SECURE128:-VERS-SSL3.0)\n"
174 " --tls-verify\n"
175 " verify the hostname against the server certificate\n"
176 " --tls-fingerprint <string>\n"
177 " a SHA-256 hash of the server fingerprint to verify against\n"
178 #endif
179 #ifdef WITH_SSH
180 " --no-ssh-agent\n"
181 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
182 " --identity, -i <filename>\n"
183 " the ssh identity file to use for authentication\n"
184 " --knownhosts, -k <filename>\n"
185 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
186 " --ssh-needs-passphrase\n"
187 " prompt for a passphrase for the SSH identity file\n"
188 #endif
189 " --no-lock\n"
190 " do not lock the data file upon opening it\n"
191 " --lock-timeout <N>\n"
192 " time in tenths of a second to wait for a locked data file (50)\n"
193 " --name, -n <string>\n"
194 " set the client name\n"
195 " --pinentry <path>\n"
196 " the full path to the pinentry binary\n"
197 " --local-pinentry\n"
198 " force using a local pinentry\n"
199 " --no-pinentry\n"
200 " disable pinentry both remotely and locally\n"
201 " --ttyname, -y <path>\n"
202 " tty that pinentry will use\n"
203 " --ttytype, -t <string>\n"
204 " pinentry terminal type (default is $TERM)\n"
205 " --display, -d\n"
206 " pinentry display (default is $DISPLAY)\n"
207 " --lc-ctype <string>\n"
208 " locale setting for pinentry\n"
209 " --lc-messages <string>\n"
210 " locale setting for pinentry\n"
211 " --tries <N>\n"
212 " number of pinentry tries before failing (3)\n"
213 " --timeout <seconds>\n"
214 " pinentry timeout\n"
215 " --inquire <COMMAND>\n"
216 " the specified command (with any options) uses a server inquire while\n"
217 " command data is read via the inquire file descriptor (stdin)\n"
218 " --inquire-line, -L <STRING>\n"
219 " the initial line to send (i.e., element path) before the inquire data\n"
220 " --inquire-fd <FD>\n"
221 " read inquire data from the specified file descriptor (stdin)\n"
222 " --inquire-file <filename>\n"
223 " read inquire data from the specified filename\n"
224 " --output-fd <FD>\n"
225 " redirect command output to the specified file descriptor\n"
226 " --save, -S\n"
227 " send the SAVE command before exiting\n"
228 " --passphrase-file <filename>\n"
229 " obtain the passphrase from the specified filename\n"
230 " --new-passphrase-file <filename>\n"
231 " obtain the passphrase to save with from the specified filename\n"
232 " --sign-passphrase-file <filename>\n"
233 " obtain the passphrase to sign with (symmetric) from the specified filename\n"
234 " --key-params <filename>\n"
235 " key parameters to use for key generation (pwmd default)\n"
236 " --keyid <recipient>[,<recipient>]\n"
237 " the public key ID to u\n"
238 " --sign-keyid <string>\n"
239 " the key ID to sign the data file with\n"
240 " --symmetric\n"
241 " use conventional encryption with optional signer(s) for new files\n"
242 " --no-status\n"
243 " disable showing of status messages from the server\n"
244 " --status-fd <FD>\n"
245 " redirect status messages to the specified file descriptor\n"
246 " --status-ignore <string[,...]>\n"
247 " prevent parsing of the specified status message keywords\n"
248 " --quiet\n"
249 " disable showing of extra messages (implies --no-status)\n"
250 #ifdef HAVE_LIBREADLINE
251 " --interactive\n"
252 " use a shell like interface to pwmd (allows more than one command)\n"
253 #endif
254 " --version\n"
255 " --help\n"),
256 #ifdef DEFAULT_PWMD_SOCKET
257 DEFAULT_PWMD_SOCKET
258 #else
259 "~/.pwmd/socket"
260 #endif
262 fprintf (status == EXIT_FAILURE ? stderr : stdout,
263 N_("\n"
264 "An optional url may be in the form of:\n"
265 " --url /path/to/socket\n"
266 " --url file://[path/to/socket]\n"
267 #ifdef WITH_SSH
268 " or\n"
269 " --url ssh[46]://[username@]hostname[:port]\n"
270 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
271 #endif
272 #ifdef WITH_GNUTLS
273 " or\n"
274 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
275 " --client-key filename\n"
276 #endif
277 #ifdef HAVE_LIBREADLINE
278 "\n"
279 "Interactive mode is used when input is from a terminal.\n"
280 #endif
282 exit (status);
285 static gpg_error_t
286 inquire_cb (void *user, const char *keyword, gpg_error_t rc,
287 char **data, size_t * size)
289 struct inquire_s *inq = user;
290 int is_password = 0;
291 int is_newpassword = 0;
292 int sign = 0;
293 int is_keyparam = 0;
295 *data = NULL;
296 *size = 0;
298 if (rc)
299 return rc;
301 if (!strcmp (keyword, "PASSPHRASE"))
302 is_password = 1;
303 else if (!strcmp (keyword, "SIGN_PASSPHRASE"))
304 sign = 1;
305 else if (!strcmp (keyword, "NEW_PASSPHRASE"))
306 is_newpassword = 1;
307 #ifdef HAVE_LIBREADLINE
308 else if (!strcmp (keyword, "KEYPARAM") && !interactive)
310 #else
311 else if (!strcmp (keyword, "KEYPARAM"))
313 #endif
314 int fd;
315 if (!keyparams || !*keyparams)
316 return gpg_error (GPG_ERR_INV_PARAMETER);
318 fd = open (keyparams, O_RDONLY);
319 if (fd == -1)
321 fprintf (stderr, "%s: %s\n", keyparams, strerror (errno));
322 return gpg_error_from_syserror ();
325 rc = set_inquire (fd, NULL, &inq);
326 if (rc)
328 close (fd);
329 return rc;
332 if (!quiet)
333 fprintf (stderr, N_("Using file '%s' as %s.\n"), keyparams, keyword);
335 is_keyparam = 1;
338 if ((is_password && !keyfile) || (is_newpassword && !new_keyfile)
339 || (sign && !sign_keyfile))
341 char *tmp;
343 rc = pwmd_password (pwm, keyword, &tmp, &inq->len);
344 if (rc && gpg_err_code (rc) != GPG_ERR_EOF)
345 return rc;
347 pwmd_free (inq->line);
348 inq->line = tmp;
349 *data = inq->line;
350 *size = inq->len;
351 return gpg_error (GPG_ERR_EOF);
353 else if ((is_newpassword && new_keyfile) || (is_password && keyfile)
354 || (sign && sign_keyfile))
356 int fd;
358 if (sign)
359 fd = open (sign_keyfile, O_RDONLY);
360 else
361 fd = open (is_password || sign ? keyfile : new_keyfile, O_RDONLY);
363 if (fd == -1)
365 if (sign)
366 fprintf (stderr, "%s: %s\n", sign_keyfile, strerror (errno));
367 else
368 fprintf (stderr, "%s: %s\n", is_newpassword ? new_keyfile
369 : keyfile, strerror (errno));
370 return gpg_error_from_syserror ();
373 rc = set_inquire (fd, NULL, &inq);
374 if (rc)
376 close (fd);
377 return rc;
380 if (!quiet)
381 fprintf (stderr, N_("Using keyfile '%s' as %s.\n"),
382 sign ? sign_keyfile : is_newpassword ? new_keyfile
383 : keyfile, keyword);
385 #ifdef HAVE_LIBREADLINE
386 else if ((!inq->last_keyword || strcmp (keyword, inq->last_keyword))
387 && interactive)
389 fprintf (stderr,
391 ("%sPress CTRL-D to send the current line. Press twice to end. %s:\n"),
392 inq->last_keyword ? "\n" : "", keyword);
393 pwmd_free (inq->last_keyword);
394 inq->last_keyword = pwmd_strdup (keyword);
396 #endif
398 /* The first part of the command data. */
399 if (inq->len)
401 *data = inq->line;
402 *size = inq->len;
403 inq->len = 0;
404 return inq->fd == -1 ? gpg_error (GPG_ERR_EOF) : 0;
407 *size = read (inq->fd, inq->line, ASSUAN_LINELENGTH);
408 if (*size == -1)
410 *size = 0;
411 return gpg_error (gpg_error_from_syserror ());
413 else if (*size)
414 *data = inq->line;
415 else if (inq->fd != STDIN_FILENO &&
416 (is_newpassword || is_password || sign || is_keyparam))
418 *inq->line = 0;
419 inq->size = 1;
420 *data = inq->line;
421 *size = 1;
424 if (((is_newpassword && new_keyfile) || (is_password && keyfile)
425 || (sign && sign_keyfile) || (keyparams && is_keyparam))
426 && *size == inq->size)
427 return gpg_error (GPG_ERR_EOF);
429 return *size ? 0 : gpg_error (GPG_ERR_EOF);
432 static int
433 status_msg_cb (void *data, const char *line)
435 char *p = strchr (line, ' ');
436 char **s;
438 /* Ignore status messages specified by the client via --status-ignore. */
439 for (s = status_ignore; s && *s; s++)
441 char *tmp = strchr (line, ' ');
442 size_t len = tmp ? strlen (line) - strlen (tmp) : strlen (line);
444 if (!strncmp (line, *s, len) && len == strlen (*s))
445 return 0;
448 if (interactive && !strncmp (line, "XFER ", 5) && *line != '#' && p
449 && strchr (p, ' ') && *++p)
451 char *p1 = strchr (p, ' ');
452 int a = strtol (p, NULL, 10);
454 if (isdigit (*p) && p1)
456 int b = strtol (p1, NULL, 10);
457 char l[64] = { 0 };
458 int t = a && b ? a * 100 / b : 0;
460 strncpy (l, line, strlen (line) - strlen (p) - 1);
461 fprintf (statusfp, "\rS:%s %i/%i %i%%%s", l, a, b, t,
462 a == b ? "\n" : "");
463 fflush (statusfp);
464 return 0;
468 fprintf (statusfp, "S:%s\n", line);
469 fflush (statusfp);
470 #ifdef HAVE_LIBREADLINE
471 rl_on_new_line ();
472 #endif
473 return 0;
476 static gpg_error_t
477 process_cmd ()
479 return pwmd_process (pwm);
482 #ifdef WITH_SSH
483 static gpg_error_t
484 get_password (char **result, pwmd_pinentry_t w, int echo)
486 char buf[LINE_MAX] = { 0 }, *p;
487 struct termios told, tnew;
488 char *key = NULL;
490 *result = NULL;
492 if (!isatty (STDIN_FILENO))
494 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
495 return GPG_ERR_ENOTTY;
498 if (!echo)
500 if (tcgetattr (STDIN_FILENO, &told) == -1)
501 return gpg_error_from_syserror ();
503 memcpy (&tnew, &told, sizeof (struct termios));
504 tnew.c_lflag &= ~(ECHO);
505 tnew.c_lflag |= ICANON | ECHONL;
507 if (tcsetattr (STDIN_FILENO, TCSANOW, &tnew) == -1)
509 int n = errno;
511 tcsetattr (STDIN_FILENO, TCSANOW, &told);
512 return gpg_error_from_errno (n);
516 switch (w)
518 case PWMD_PINENTRY_OPEN:
519 fprintf (stderr, N_("Password for %s: "), filename);
520 break;
521 case PWMD_PINENTRY_OPEN_FAILED:
522 fprintf (stderr, N_("Invalid password. Password for %s: "), filename);
523 break;
524 case PWMD_PINENTRY_SAVE:
525 fprintf (stderr, N_("New password for %s: "), filename);
526 break;
527 case PWMD_PINENTRY_SAVE_CONFIRM:
528 fprintf (stderr, N_("Confirm password: "));
529 break;
530 default:
531 break;
534 if ((p = fgets (buf, sizeof (buf), stdin)) == NULL)
536 if (!echo)
537 tcsetattr (STDIN_FILENO, TCSANOW, &told);
539 return 0;
542 if (!echo)
543 tcsetattr (STDIN_FILENO, TCSANOW, &told);
545 if (feof (stdin))
547 clearerr (stdin);
548 return GPG_ERR_CANCELED;
551 p[strlen (p) - 1] = 0;
553 if (buf[0])
555 key = pwmd_strdup_printf ("%s", p);
556 memset (&buf, 0, sizeof (buf));
558 if (!key)
559 return GPG_ERR_ENOMEM;
562 *result = key;
563 return 0;
566 static gpg_error_t
567 knownhost_cb (void *data, const char *host, const char *key, size_t len)
569 gpg_error_t rc;
570 char *buf =
571 pwmd_strdup_printf (N_
572 ("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?"),
573 (char *) data, host, host);
575 if (no_pinentry && !isatty (STDIN_FILENO))
577 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
578 pwmd_free (buf);
579 return GPG_ERR_ENOTTY;
581 else if (no_pinentry)
583 for (char *p = buf, len = 0; *p; p++, len++)
585 if (*p == '\n')
586 len = 0;
588 if (len == 78)
590 char *t = p;
592 while (!isspace (*(--p)));
593 *p = '\n';
594 p = t;
595 len = 0;
599 fprintf (stderr, "%s\n\n", buf);
600 pwmd_free (buf);
604 char *result;
606 fprintf (stderr, N_("Trust this connection [y/N]: "));
607 fflush (stderr);
608 rc = get_password (&result, PWMD_PINENTRY_CONFIRM, 1);
610 if (rc)
611 return rc;
613 if (!result || !*result || *result == 'n' || *result == 'N')
615 if (result && *result)
616 pwmd_free (result);
618 return GPG_ERR_NOT_CONFIRMED;
621 if ((*result == 'y' || *result == 'Y') && *(result + 1) == 0)
623 pwmd_free (result);
624 return 0;
627 while (1);
630 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, buf);
631 pwmd_free (buf);
633 if (rc)
634 return rc;
636 return pwmd_getpin (pwm, NULL, NULL, NULL, PWMD_PINENTRY_CONFIRM);
638 #endif
640 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
641 static pwmd_socket_t
642 is_remote_url (const char *str)
644 if (!str)
645 return PWMD_SOCKET_LOCAL;
647 #ifdef WITH_SSH
648 if (strstr (str, "ssh://") || strstr (str, "ssh4://")
649 || strstr (str, "ssh6://"))
650 return PWMD_SOCKET_SSH;
651 #endif
653 #ifdef WITH_GNUTLS
654 if (strstr (str, "tls://") || strstr (str, "tls4://")
655 || strstr (str, "tls6://"))
656 return PWMD_SOCKET_TLS;
657 #endif
659 return PWMD_SOCKET_LOCAL;
661 #endif
663 static char *
664 escape (const char *str)
666 const char *p;
667 char *buf = pwmd_malloc (ASSUAN_LINELENGTH + 1), *b = buf;
668 size_t len = 0;
670 for (p = str; *p; p++, len++)
672 if (len == ASSUAN_LINELENGTH)
673 break;
675 if (*p == '\\')
677 switch (*++p)
679 case 't':
680 *b++ = '\t';
681 break;
682 case 'n':
683 *b++ = '\n';
684 break;
685 case 'v':
686 *b++ = '\v';
687 break;
688 case 'b':
689 *b++ = '\b';
690 break;
691 case 'f':
692 *b++ = '\f';
693 break;
694 case 'r':
695 *b++ = '\r';
696 break;
697 default:
698 *b++ = *p;
699 break;
702 if (!*p)
703 break;
705 continue;
708 *b++ = *p;
711 *b = 0;
712 return buf;
715 static void
716 free_inquire (struct inquire_s *inq)
718 if (!inq)
719 return;
721 pwmd_free (inq->line);
723 if (inq->fd != -1 && inq->fd != STDIN_FILENO)
724 close (inq->fd);
726 pwmd_free (inq->last_keyword);
727 pwmd_free (inq);
730 /* When *result is not NULL it is updated to the new values and not
731 * reallocated. */
732 static gpg_error_t
733 set_inquire (int fd, const char *line, struct inquire_s **result)
735 struct inquire_s inq = { 0 };
736 struct stat st = { 0 };
737 gpg_error_t rc;
739 if (fd != -1)
741 if (fstat (fd, &st) == -1)
742 return gpg_error_from_syserror ();
744 inq.size = st.st_size;
747 inq.fd = fd;
748 inq.line = pwmd_calloc (1, ASSUAN_LINELENGTH);
749 if (!inq.line)
750 return GPG_ERR_ENOMEM;
752 if (line)
754 char *s = escape (line);
756 if (!s)
758 pwmd_free (inq.line);
759 return GPG_ERR_ENOMEM;
762 if (strlen (s) >= ASSUAN_LINELENGTH)
764 pwmd_free (inq.line);
765 pwmd_free (s);
766 return GPG_ERR_LINE_TOO_LONG;
769 strncpy (inq.line, s, ASSUAN_LINELENGTH - 1);
770 inq.len = strlen (s);
771 pwmd_free (s);
774 rc = pwmd_setopt (pwm, PWMD_OPTION_INQUIRE_TOTAL,
775 st.st_size ? st.st_size + strlen (inq.line) : 0);
776 if (rc)
778 pwmd_free (inq.line);
779 return rc;
782 if (*result == NULL)
783 *result = pwmd_malloc (sizeof (struct inquire_s));
784 else
786 if ((*result)->fd != -1 && (*result)->fd != STDIN_FILENO)
787 close ((*result)->fd);
789 pwmd_free ((*result)->line);
790 (*result)->line = NULL;
791 (*result)->fd = -1;
792 (*result)->len = 0;
795 memcpy (*result, &inq, sizeof (struct inquire_s));
796 memset (&inq, 0, sizeof (struct inquire_s));
797 return rc;
800 #ifdef HAVE_LIBREADLINE
801 static int
802 interactive_hook (void)
804 interactive_error = process_cmd ();
806 if (interactive_error)
807 rl_event_hook = NULL;
809 return 0;
812 static int
813 get_readline_char (FILE *fp)
815 if (rl_line_buffer
816 && (!strncmp (rl_line_buffer, ".set passphrase-file ", 16)
817 || !strncmp (rl_line_buffer, ".set new-passphrase-file ", 20)
818 || !strncmp (rl_line_buffer, ".set sign-passphrase-file ", 21)))
819 rl_inhibit_completion = 0;
820 else if (rl_line_buffer
821 && !strncmp (rl_line_buffer, ".redir ", 7))
823 char *p = strchr (rl_line_buffer, ' ');
825 if (strchr (++p, ' '))
826 rl_inhibit_completion = 1;
827 else
828 rl_inhibit_completion = 0;
830 else if (rl_line_buffer
831 && !strncmp (rl_line_buffer, ".read ", 6))
833 char *p = rl_line_buffer + 6;
835 if (strstr (p, "--prefix "))
837 p = strstr (p, "--prefix ");
838 p += 9;
839 p = strchr (p, ' ');
840 if (p)
841 p++;
844 if (!p || strchr (p, ' '))
845 rl_inhibit_completion = 1;
846 else
847 rl_inhibit_completion = 0;
849 else
850 rl_inhibit_completion = 1;
852 return fgetc (fp);
855 static void
856 print_help ()
858 fprintf (stderr,
860 ("------------------------------------------------------------\n"
861 "Elements are TAB delimited. Type HELP for protocol commands.\n"
862 "Type .help for pwmc commands. Press CTRL-D to quit.\n"
863 "------------------------------------------------------------\n"));
865 #endif
867 static char *
868 parse_arg (const char *src, char *dst, size_t len)
870 char *p = dst;
871 const char *s = src;
872 size_t n = 0;
874 for (; s && *s && *s != ' ' && n < len; s++, n++)
875 *p++ = *s;
877 *p = 0;
878 return dst;
881 static char *
882 parse_opt (char **line, const char *opt, gpg_error_t * rc)
884 static char result[ASSUAN_LINELENGTH] = { 0 }, *r = result;
885 char *s = strstr (*line, opt);
887 *rc = 0;
888 result[0] = 0;
889 r = result;
891 if (s)
893 size_t len = 0;
894 int quote = 0;
895 size_t rlen = strlen (opt);
896 char *p = s + rlen;
897 int lastc = 0;
899 while (*p && *p == ' ')
901 rlen++;
902 p++;
905 for (; *p && len < sizeof (result) - 1; p++, rlen++)
907 if (isspace (*p) && !quote)
908 break;
910 if (*p == '\"' && lastc != '\\')
912 quote = !quote;
913 lastc = *p;
914 continue;
917 *r++ = lastc = *p;
918 len++;
921 *r = 0;
923 if (len >= sizeof (result) - 1)
924 *rc = GPG_ERR_LINE_TOO_LONG;
925 else
927 p = s + rlen;
929 while (*p && *p == ' ')
930 p++;
932 *line = p;
936 return result;
939 static gpg_error_t
940 read_command (const char *line, char **result, size_t * len)
942 int fd;
943 gpg_error_t rc = 0;
944 char *file = NULL;
945 struct inquire_s *inq = NULL;
946 char *p = (char *) line;
947 const char *prefix = parse_opt (&p, "--prefix", &rc);
948 char filebuf[ASSUAN_LINELENGTH];
950 if (rc)
951 return rc;
953 rc = GPG_ERR_SYNTAX;
955 if (p && *p)
957 while (*p && isspace (*p))
958 p++;
960 file = parse_arg (p, filebuf, sizeof (filebuf));
961 if (file && *file)
963 p += strlen (file) + 1;
965 while (*p && isspace (*p))
966 p++;
968 if (*p)
969 rc = 0;
973 if (rc)
975 fprintf (stderr,
977 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
978 fprintf (stderr,
980 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\\ = \\)\n"));
981 return rc;
984 fd = open (file, O_RDONLY);
985 if (fd == -1)
986 return gpg_error_from_syserror ();
988 rc = set_inquire (fd, prefix && *prefix ? prefix : NULL, &inq);
989 if (rc)
991 close (fd);
992 return rc;
995 rc = pwmd_command (pwm, result, len, inquire_cb, inq, "%s", p);
996 free_inquire (inq);
997 return rc;
1000 static gpg_error_t
1001 redir_command (const char *line)
1003 const char *p = line;
1004 int fd;
1005 gpg_error_t rc = GPG_ERR_SYNTAX;
1006 char *file = NULL;
1007 struct inquire_s *inq = NULL;
1008 char *result = NULL;
1009 size_t len = 0;
1010 char filebuf[ASSUAN_LINELENGTH];
1012 if (p && *p && *++p)
1014 file = parse_arg (p, filebuf, sizeof (filebuf));
1015 if (file && *file)
1017 p += strlen (file) + 1;
1019 while (*p && isspace (*p))
1020 p++;
1022 if (*p)
1023 rc = 0;
1027 if (rc)
1029 fprintf (stderr, N_("Usage: .redir <filename> <command> [args]\n"));
1030 return rc;
1033 fd = open (file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
1034 if (fd == -1)
1035 return gpg_error_from_syserror ();
1037 #ifdef HAVE_LIBREADLINE
1038 rc = set_inquire (interactive ? STDIN_FILENO : inquirefd, NULL, &inq);
1039 #else
1040 rc = set_inquire (inquirefd, NULL, &inq);
1041 #endif
1042 if (rc)
1044 close (fd);
1045 return rc;
1048 rc = parse_dotcommand (p, &result, &len, inq);
1049 if (!rc && result && len--)
1050 { // null byte which is always appended
1051 if (write (fd, result, len) != len)
1052 rc = GPG_ERR_TOO_SHORT;
1053 pwmd_free (result);
1056 free_inquire (inq);
1057 close (fd);
1058 return rc;
1061 static gpg_error_t
1062 help_command (const char *line)
1064 fprintf (stderr,
1065 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
1066 " .redir <filename> <command>\n"
1067 " redirect the output of a command to the specified file\n"
1068 "\n"
1069 " .open <filename>\n"
1070 " open the specified filename losing any changes to the current one\n"
1071 "\n"
1072 " .read [--prefix <string>] <filename> <command> [args]\n"
1073 " obtain data from the specified filename for an inquire command\n"
1074 "\n"
1075 " .set help | <name> [<value>]\n"
1076 " set option <name> to <value>\n"
1077 "\n"
1078 " .save [args]\n"
1079 " write changes of the file to disk\n"
1080 "\n"
1081 " .passwd [args]\n"
1082 " change the passphrase of a data file\n"
1083 "\n"
1084 " .help\n"
1085 " this help text\n"));
1086 return 0;
1089 static gpg_error_t
1090 open_command (char *line)
1092 struct inquire_s *inq = NULL;
1093 const char *file = line;
1094 gpg_error_t rc;
1096 while (file && isspace (*file))
1097 file++;
1099 if (!file || !*file)
1101 fprintf (stderr, N_("Usage: .open <filename>\n"));
1102 return GPG_ERR_SYNTAX;
1105 #ifdef HAVE_LIBREADLINE
1106 if (interactive || !quiet)
1107 #else
1108 if (!quiet)
1109 #endif
1110 fprintf (stderr, N_("Opening data file \"%s\" ...\n"), file);
1112 #ifdef HAVE_LIBREADLINE
1113 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1114 #else
1115 rc = set_inquire (-1, NULL, &inq);
1116 #endif
1117 if (rc)
1118 return rc;
1120 if (keyfile)
1122 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1123 if (!rc)
1124 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 1);
1126 else
1128 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1129 if (!rc)
1130 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1133 if (!rc)
1134 rc = pwmd_open (pwm, file, inquire_cb, inq);
1136 #ifdef HAVE_LIBREADLINE
1137 if (interactive)
1138 reset_keyfiles ();
1139 #endif
1141 free_inquire (inq);
1142 if (!rc && file != filename)
1144 pwmd_free (filename);
1145 filename = pwmd_strdup (file);
1148 return rc;
1151 static gpg_error_t
1152 set_command (const char *line)
1154 gpg_error_t rc = 0;
1155 char name[256] = { 0 };
1156 char value[512] = { 0 };
1157 char *namep;
1158 char *valuep;
1159 const char *p = line;
1161 while (p && *p && isspace (*p))
1162 p++;
1164 namep = parse_arg (p, name, sizeof (name));
1165 if (!namep || !*namep)
1167 fprintf (stderr, N_("Usage: .set help | <name> [<value>]\n"));
1168 return GPG_ERR_SYNTAX;
1171 p += strlen (namep);
1172 while (p && *p && isspace (*p))
1173 p++;
1175 valuep = parse_arg (p, value, sizeof (value));
1177 if (!strcmp (name, "passphrase-file") || !strcmp (name, "new-passphrase-file")
1178 || !strcmp (name, "sign-passphrase-file"))
1180 int is_newkeyfile = 1;
1181 int sign = !strcmp (name, "sign-passphrase-file");
1183 if (!strcmp (name, "passphrase-file") || sign)
1184 is_newkeyfile = 0;
1186 if (is_newkeyfile)
1188 pwmd_free (new_keyfile);
1189 new_keyfile = NULL;
1191 else if (sign)
1193 pwmd_free (sign_keyfile);
1194 sign_keyfile = NULL;
1196 else
1198 pwmd_free (keyfile);
1199 keyfile = NULL;
1202 if (!rc && *valuep)
1204 if (is_newkeyfile)
1205 new_keyfile = pwmd_strdup (value);
1206 else if (sign)
1207 sign_keyfile = pwmd_strdup (value);
1208 else
1209 keyfile = pwmd_strdup (value);
1211 if (!rc)
1213 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 1);
1214 if (!rc)
1215 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1218 else if (!local_pin && !no_pinentry)
1220 pwmd_socket_t t;
1222 pwmd_socket_type (pwm, &t);
1223 if (t == PWMD_SOCKET_LOCAL)
1225 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 0);
1226 if (!rc)
1227 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1231 else if (!strcmp(name, "pinentry-timeout"))
1233 char *e = NULL;
1234 int n = strtol(valuep, &e, 10);
1236 if (e && *e)
1237 return gpg_error (GPG_ERR_INV_VALUE);
1239 if (!*valuep)
1240 n = DEFAULT_PIN_TIMEOUT;
1242 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, n);
1244 else if (!strcmp (name, "help"))
1246 fprintf (stderr,
1248 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1249 "delimited. When no value is specified the option is unset.\n\n"
1250 "passphrase-file [<filename>]\n"
1251 " set or unset the file to be used when a passphrase is required (*)\n"
1252 "\n"
1253 "new-passphrase-file [<filename>]\n"
1254 " set or unset the file to be used when a new passphrase is required (*)\n"
1255 "\n"
1256 "sign-passphrase-file [<filename>]\n"
1257 " set or unset the file to be used when a passphrase is required for\n"
1258 " signing (symmetric) (*)\n"
1259 "\n"
1260 "pinentry-timeout <seconds>\n"
1261 " the amount of seconds before pinentry gives up waiting for input\n"
1262 "\n"
1263 "* = the next protocol command will unset this value\n"
1266 else
1267 rc = GPG_ERR_UNKNOWN_OPTION;
1269 return rc;
1272 static gpg_error_t
1273 save_command (const char *line)
1275 struct inquire_s *inq = NULL;
1276 gpg_error_t rc;
1278 #ifdef HAVE_LIBREADLINE
1279 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1280 #else
1281 rc = set_inquire (-1, NULL, &inq);
1282 #endif
1283 if (rc)
1284 return rc;
1286 if (new_keyfile || keyfile || sign_keyfile)
1288 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1289 if (!rc)
1290 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 1);
1292 else
1294 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1295 if (!rc)
1296 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1299 if (!rc)
1300 rc = pwmd_save (pwm, line, inquire_cb, inq);
1302 #ifdef HAVE_LIBREADLINE
1303 if (interactive)
1304 reset_keyfiles ();
1305 #endif
1307 free_inquire (inq);
1308 return rc;
1311 static gpg_error_t
1312 do_save_passwd_command (const char *line, int save)
1314 struct inquire_s *inq = NULL;
1315 gpg_error_t rc;
1317 #ifdef HAVE_LIBREADLINE
1318 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1319 #else
1320 rc = set_inquire (-1, NULL, &inq);
1321 #endif
1322 if (rc)
1323 return rc;
1325 if (new_keyfile || keyfile || sign_keyfile)
1327 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1328 if (!rc)
1329 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 1);
1331 else
1333 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1334 if (!rc)
1335 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1338 if (!rc)
1340 if (save)
1341 rc = pwmd_save (pwm, line, inquire_cb, inq);
1342 else
1343 rc = pwmd_passwd (pwm, line, inquire_cb, inq);
1346 #ifdef HAVE_LIBREADLINE
1347 if (interactive)
1348 reset_keyfiles ();
1349 #endif
1351 free_inquire (inq);
1352 return rc;
1355 static gpg_error_t
1356 parse_dotcommand (const char *line, char **result,
1357 size_t * len, struct inquire_s *inq)
1359 const char *p = line;
1360 gpg_error_t rc = 0;
1362 if (!strncmp (p, ".read", 5))
1363 rc = read_command (p + 5, result, len);
1364 else if (!strncmp (p, ".redir", 6))
1365 rc = redir_command (p + 6);
1366 else if (!strncmp (p, ".help", 5))
1367 rc = help_command (p + 5);
1368 else if (!strncmp (p, ".open", 5))
1369 rc = open_command ((char *)p + 5);
1370 else if (!strncmp (p, ".set", 4))
1371 rc = set_command (p + 4);
1372 else if (!strncmp (p, ".save", 5))
1373 rc = do_save_passwd_command (p + 5, 1);
1374 else if (!strncmp (p, ".passwd", 7))
1375 rc = do_save_passwd_command (p + 7, 0);
1376 else
1378 rc = pwmd_command (pwm, result, len, inquire_cb, inq, "%s", line);
1379 #ifdef HAVE_LIBREADLINE
1380 if (interactive)
1382 #endif
1383 reset_keyfiles ();
1384 #ifdef HAVE_LIBREADLINE
1386 #endif
1389 return FINISH (rc);
1392 #ifdef HAVE_LIBREADLINE
1393 static gpg_error_t
1394 do_interactive ()
1396 gpg_error_t rc;
1397 struct inquire_s *inq = NULL;
1399 rl_initialize ();
1400 rc = process_cmd ();
1401 if (rc)
1402 return rc;
1404 rc = set_inquire (STDIN_FILENO, NULL, &inq);
1405 if (rc)
1406 return rc;
1408 fprintf (stderr,
1409 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1410 print_help ();
1411 rl_event_hook = &interactive_hook;
1412 rl_getc_function = get_readline_char;
1413 rl_set_keyboard_input_timeout (100000);
1415 for (;;)
1417 char *line;
1418 char *result = NULL;
1419 size_t len;
1421 rc = 0;
1422 line = readline ("pwmc> ");
1423 if (interactive_error)
1425 free (line);
1426 rc = interactive_error;
1427 break;
1430 if (!line)
1432 rc = finalize ();
1433 if (!rc)
1434 break;
1436 if (gpg_err_code (rc) != GPG_ERR_CANCELED &&
1437 gpg_err_code (rc) != GPG_ERR_EOF)
1438 fprintf (stderr, "ERR %i: %s\n", rc, gpg_strerror (rc));
1440 continue;
1442 else if (!*line)
1444 free (line);
1445 continue;
1448 #ifdef HAVE_READLINE_HISTORY
1449 add_history (line);
1450 #endif
1451 rc = parse_dotcommand (line, &result, &len, inq);
1452 free (line);
1453 if (rc)
1455 char *tmp = NULL;
1457 if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
1458 (void) pwmd_command (pwm, &tmp, NULL, NULL, NULL,
1459 "GETINFO last_error");
1461 show_error (pwm, rc, tmp);
1462 pwmd_free (tmp);
1464 else if (result && len)
1465 printf ("%s%s", result, result[len - 1] != '\n' ? "\n" : "");
1467 pwmd_free (result);
1470 free_inquire (inq);
1471 return rc;
1473 #endif
1475 static gpg_error_t
1476 finalize ()
1478 gpg_error_t rc = 0;
1479 #ifdef HAVE_LIBREADLINE
1480 int quit = 0;
1482 if (interactive)
1484 int finished = 0;
1486 fprintf (stderr, "\n");
1490 char *p, buf[16];
1492 fprintf (stderr,
1494 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1495 p = fgets (buf, sizeof (buf), stdin);
1497 if (feof (stdin))
1499 clearerr (stdin);
1500 return GPG_ERR_EOF;
1503 switch (*p)
1505 case 'h':
1506 print_help ();
1507 break;
1508 case 'c':
1509 return GPG_ERR_CANCELED;
1510 case 'Q':
1511 return 0;
1512 case 'f':
1513 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1514 "CLEARCACHE %s", filename);
1515 if (rc)
1516 return rc;
1518 interactive_hook ();
1519 break;
1520 case 'S':
1521 quit = 1;
1522 case 's':
1523 save = 1;
1524 finished = 1;
1525 break;
1526 default:
1527 break;
1530 while (!finished);
1532 #endif
1534 if (save && !filename)
1536 fprintf (stderr,
1538 ("No filename was specified on the command line. Aborting.\n"));
1539 return GPG_ERR_CANCELED;
1542 if (save && filename)
1544 char *args =
1545 pwmd_strdup_printf ("%s %s%s %s%s %s",
1546 symmetric ? "--symmetric" : "",
1547 keyid ? "--keyid=" : "",
1548 keyid ? keyid : "",
1549 sign_keyid ? "--sign-keyid=" : "",
1550 sign_keyid ? sign_keyid : "",
1551 keyparams ? "--inquire-keyparam" : "");
1553 #ifdef HAVE_LIBREADLINE
1554 if (!quiet || interactive)
1556 #else
1557 if (!quiet)
1559 #endif
1560 fprintf (stderr, "\n");
1561 fprintf (stderr, N_("Saving changes ...\n"));
1564 rc = save_command (args);
1565 pwmd_free (args);
1568 #ifdef HAVE_LIBREADLINE
1569 if (interactive)
1570 return rc ? rc : quit ? 0 : GPG_ERR_CANCELED;
1571 #endif
1573 return rc;
1576 static void
1577 parse_status_ignore (char *str)
1579 size_t n = 0;
1580 char **p, *s;
1582 for (p = status_ignore; p && *p; p++)
1583 pwmd_free (*p);
1585 pwmd_free (status_ignore);
1586 status_ignore = NULL;
1587 if (!str || !*str)
1588 return;
1590 while ((s = strsep (&str, ",")))
1592 p = pwmd_realloc (status_ignore, (n + 2) * sizeof (char *));
1593 p[n++] = pwmd_strdup (s);
1594 p[n] = NULL;
1595 status_ignore = p;
1600 main (int argc, char *argv[])
1602 int connected = 0;
1603 gpg_error_t rc;
1604 int opt;
1605 char command[ASSUAN_LINELENGTH], *p = NULL;
1606 char *result = NULL;
1607 size_t len = 0;
1608 char *pinentry_path = NULL;
1609 char *display = NULL, *tty = NULL, *ttytype = NULL;
1610 char *lcctype = NULL, *lcmessages = NULL;
1611 int outfd = STDOUT_FILENO;
1612 FILE *outfp = stdout;
1613 FILE *inquirefp = stdin;
1614 int show_status = 1;
1615 char *clientname = "pwmc";
1616 char *inquire = NULL;
1617 char *inquire_line = NULL;
1618 int timeout = 0;
1619 #ifdef WITH_SSH
1620 int use_ssh_agent = 1;
1621 char *knownhosts = NULL;
1622 char *identity = NULL;
1623 #endif
1624 #ifdef WITH_GNUTLS
1625 char *cacert = NULL;
1626 char *clientcert = NULL;
1627 char *clientkey = NULL;
1628 char *prio = NULL;
1629 int tls_verify = 0;
1630 char *tls_fingerprint = NULL;
1631 #endif
1632 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1633 pwmd_socket_t socktype;
1634 long socket_timeout = 300;
1635 int connect_timeout = 120;
1636 int needs_passphrase = 0;
1637 #endif
1638 int lock_on_open = 1;
1639 long lock_timeout = 50;
1640 char *url = NULL;
1641 char *tmp = NULL;
1642 /* The order is important. */
1643 enum
1645 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1646 OPT_SOCKET_TIMEOUT, OPT_CONNECT_TIMEOUT,
1647 #endif
1648 #ifdef WITH_SSH
1649 OPT_USE_SSH_AGENT, OPT_IDENTITY, OPT_KNOWNHOSTS, OPT_SSH_NEEDS_PASSPHRASE,
1650 #endif
1651 #ifdef WITH_GNUTLS
1652 OPT_CACERT, OPT_CLIENTCERT, OPT_CLIENTKEY, OPT_PRIORITY, OPT_VERIFY,
1653 OPT_SERVER_FP,
1654 #endif
1655 OPT_URL, OPT_LOCAL, OPT_TTYNAME, OPT_TTYTYPE, OPT_DISPLAY, OPT_LC_CTYPE,
1656 OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES, OPT_PINENTRY, OPT_KEYFILE,
1657 OPT_PASSPHRASE_FILE, OPT_NEW_KEYFILE, OPT_NEW_PASSPHRASE_FILE,
1658 OPT_SIGN_KEYFILE, OPT_SIGN_PASSPHRASE_FILE, OPT_NOLOCK, OPT_LOCK_TIMEOUT,
1659 OPT_SAVE, OPT_OUTPUT_FD, OPT_INQUIRE, OPT_INQUIRE_FD, OPT_INQUIRE_FILE,
1660 OPT_INQUIRE_LINE, OPT_NO_STATUS, OPT_STATUS_IGNORE, OPT_STATUSFD, OPT_NAME,
1661 OPT_VERSION, OPT_HELP, OPT_KEYID, OPT_SIGN_KEYID, OPT_SYMMETRIC,
1662 OPT_KEYPARAMS, OPT_NO_PINENTRY, OPT_QUIET,
1663 #ifdef HAVE_LIBREADLINE
1664 OPT_INTERACTIVE,
1665 #endif
1667 const struct option long_opts[] = {
1668 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1669 {"socket-timeout", 1, 0, 0},
1670 {"connect-timeout", 1, 0, 0},
1671 #endif
1673 #ifdef WITH_SSH
1674 {"no-ssh-agent", 0, 0, 0},
1675 {"identity", 1, 0, 'i'},
1676 {"knownhosts", 1, 0, 'k'},
1677 {"ssh-needs-passphrase", 0, 0, 0},
1678 #endif
1679 #ifdef WITH_GNUTLS
1680 {"ca-cert", 1, 0, 0},
1681 {"client-cert", 1, 0, 0},
1682 {"client-key", 1, 0, 0},
1683 {"tls-priority", 1, 0, 0},
1684 {"tls-verify", 0, 0, 0},
1685 {"tls-fingerprint", 1, 0, 0},
1686 #endif
1687 {"url", 1, 0, 0},
1688 {"local-pinentry", 0, 0},
1689 {"ttyname", 1, 0, 'y'},
1690 {"ttytype", 1, 0, 't'},
1691 {"display", 1, 0, 'd'},
1692 {"lc-ctype", 1, 0, 0},
1693 {"lc-messages", 1, 0, 0},
1694 {"timeout", 1, 0, 0},
1695 {"tries", 1, 0, 0},
1696 {"pinentry", 1, 0, 0},
1697 {"key-file", 1, 0, 0},
1698 {"passphrase-file", 1, 0, 0},
1699 {"new-key-file", 1, 0, 0},
1700 {"new-passphrase-file", 1, 0, 0},
1701 {"sign-key-file", 1, 0, 0},
1702 {"sign-passphrase-file", 1, 0, 0},
1703 {"no-lock", 0, 0, 0},
1704 {"lock-timeout", 1, 0, 0},
1705 {"save", 0, 0, 'S'},
1706 {"output-fd", 1, 0, 0},
1707 {"inquire", 1, 0, 0},
1708 {"inquire-fd", 1, 0, 0},
1709 {"inquire-file", 1, 0, 0},
1710 {"inquire-line", 1, 0, 'L'},
1711 {"no-status", 0, 0, 0},
1712 {"status-ignore", 1, 0, 0},
1713 {"status-fd", 1, 0, 0},
1714 {"name", 1, 0, 'n'},
1715 {"version", 0, 0, 0},
1716 {"help", 0, 0, 0},
1717 {"keyid", 1, 0, 0},
1718 {"sign-keyid", 1, 0, 0},
1719 {"symmetric", 0, 0, 0},
1720 {"key-params", 1, 0, 0},
1721 {"no-pinentry", 0, 0, 0},
1722 {"quiet", 0, 0, 0},
1723 #ifdef HAVE_LIBREADLINE
1724 {"interactive", 0, 0},
1725 #endif
1726 {0, 0, 0, 0}
1728 #ifdef WITH_SSH
1729 const char *optstring = "L:y:t:d:P:I:Sn:i:k:s";
1730 #else
1731 const char *optstring = "L:y:t:d:P:I:Sn:s";
1732 #endif
1733 int opt_index = 0;
1735 #ifdef ENABLE_NLS
1736 setlocale (LC_ALL, "");
1737 bindtextdomain ("libpwmd", LOCALEDIR);
1738 #endif
1740 tries = DEFAULT_PIN_TRIES;
1741 inquirefd = STDIN_FILENO;
1742 statusfd = STDERR_FILENO;
1743 statusfp = fdopen (statusfd, "w");
1744 tmp = pwmd_strdup (DEFAULT_STATUS_IGNORE);
1745 parse_status_ignore (tmp);
1746 pwmd_free (tmp);
1748 while ((opt =
1749 getopt_long (argc, argv, optstring, long_opts, &opt_index)) != -1)
1751 switch (opt)
1753 /* Handle long options without a short option part. */
1754 case 0:
1755 switch (opt_index)
1757 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1758 case OPT_SOCKET_TIMEOUT:
1759 socket_timeout = strtol (optarg, &p, 10);
1760 break;
1761 case OPT_CONNECT_TIMEOUT:
1762 connect_timeout = strtol (optarg, &p, 10);
1763 break;
1764 #endif
1765 #ifdef WITH_SSH
1766 case OPT_USE_SSH_AGENT:
1767 use_ssh_agent = 0;
1768 break;
1769 case OPT_SSH_NEEDS_PASSPHRASE:
1770 needs_passphrase = 1;
1771 break;
1772 #endif
1773 #ifdef WITH_GNUTLS
1774 case OPT_CACERT:
1775 cacert = optarg;
1776 break;
1777 case OPT_CLIENTCERT:
1778 clientcert = optarg;
1779 break;
1780 case OPT_CLIENTKEY:
1781 clientkey = optarg;
1782 break;
1783 case OPT_PRIORITY:
1784 prio = optarg;
1785 break;
1786 case OPT_VERIFY:
1787 tls_verify = 1;
1788 break;
1789 case OPT_SERVER_FP:
1790 tls_fingerprint = optarg;
1791 break;
1792 #endif
1793 case OPT_SYMMETRIC:
1794 symmetric = 1;
1795 break;
1796 case OPT_KEYPARAMS:
1797 keyparams = optarg;
1798 break;
1799 case OPT_KEYFILE:
1800 case OPT_PASSPHRASE_FILE:
1801 keyfile = pwmd_strdup (optarg);
1802 break;
1803 case OPT_NEW_KEYFILE:
1804 case OPT_NEW_PASSPHRASE_FILE:
1805 new_keyfile = pwmd_strdup (optarg);
1806 break;
1807 case OPT_SIGN_KEYFILE:
1808 case OPT_SIGN_PASSPHRASE_FILE:
1809 sign_keyfile = pwmd_strdup (optarg);
1810 break;
1811 case OPT_NOLOCK:
1812 lock_on_open = 0;
1813 break;
1814 case OPT_LOCK_TIMEOUT:
1815 lock_timeout = strtol (optarg, &p, 10);
1816 break;
1817 case OPT_URL:
1818 url = optarg;
1819 break;
1820 case OPT_LOCAL:
1821 local_pin = 1;
1822 break;
1823 case OPT_LC_CTYPE:
1824 lcctype = pwmd_strdup (optarg);
1825 break;
1826 case OPT_LC_MESSAGES:
1827 lcmessages = pwmd_strdup (optarg);
1828 break;
1829 case OPT_TIMEOUT:
1830 timeout = strtol (optarg, &p, 10);
1831 break;
1832 case OPT_TRIES:
1833 tries = strtol (optarg, &p, 10);
1834 break;
1835 case OPT_INQUIRE:
1836 inquire = escape (optarg);
1837 break;
1838 case OPT_INQUIRE_FD:
1839 inquirefd = strtol (optarg, &p, 10);
1840 if (!p)
1842 inquirefp = fdopen (inquirefd, "r");
1843 if (!inquirefp)
1844 err (EXIT_FAILURE, "%i", inquirefd);
1846 break;
1847 case OPT_INQUIRE_FILE:
1848 inquirefd = open (optarg, O_RDONLY);
1849 if (inquirefd == -1)
1850 err (EXIT_FAILURE, "%s", optarg);
1851 inquirefp = fdopen (inquirefd, "r");
1852 break;
1853 case OPT_OUTPUT_FD:
1854 outfd = strtol (optarg, &p, 10);
1855 if (!p || !*p)
1857 outfp = fdopen (outfd, "w");
1858 if (!outfp)
1859 err (EXIT_FAILURE, "%i", outfd);
1861 break;
1862 case OPT_NO_STATUS:
1863 show_status = 0;
1864 break;
1865 case OPT_STATUSFD:
1866 statusfd = strtol (optarg, &p, 10);
1867 if (!p || !*p)
1869 statusfp = fdopen (statusfd, "w");
1870 if (!statusfp)
1871 err (EXIT_FAILURE, "%i", statusfd);
1873 break;
1874 case OPT_STATUS_IGNORE:
1875 parse_status_ignore (optarg);
1876 break;
1877 case OPT_VERSION:
1878 printf ("%s (pwmc)\n\n"
1879 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016\n"
1880 "%s\n"
1881 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1882 "Compile-time features:\n"
1883 #ifdef HAVE_LIBREADLINE
1884 "+INTERACTIVE "
1885 #else
1886 "-INTERACTIVE "
1887 #endif
1888 #ifdef WITH_SSH
1889 "+SSH "
1890 #else
1891 "-SSH "
1892 #endif
1893 #ifdef WITH_GNUTLS
1894 "+GNUTLS "
1895 #else
1896 "-GNUTLS "
1897 #endif
1898 #ifdef WITH_PINENTRY
1899 "+PINENTRY "
1900 #else
1901 "-PINENTRY "
1902 #endif
1903 #ifdef WITH_QUALITY
1904 "+CRACK "
1905 #else
1906 "-CRACK "
1907 #endif
1908 #ifdef MEM_DEBUG
1909 "+MEM_DEBUG "
1910 #else
1911 "-MEM_DEBUG "
1912 #endif
1913 "\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1914 exit (EXIT_SUCCESS);
1915 case OPT_PINENTRY:
1916 pinentry_path = optarg;
1917 break;
1918 case OPT_HELP:
1919 usage (argv[0], EXIT_SUCCESS);
1920 case OPT_KEYID:
1921 keyid = optarg;
1922 break;
1923 case OPT_SIGN_KEYID:
1924 sign_keyid = optarg;
1925 break;
1926 case OPT_QUIET:
1927 quiet = 1;
1928 show_status = 0;
1929 break;
1930 case OPT_NO_PINENTRY:
1931 no_pinentry = 1;
1932 break;
1933 #ifdef HAVE_LIBREADLINE
1934 case OPT_INTERACTIVE:
1935 interactive = 1;
1936 break;
1937 #endif
1938 default:
1939 usage (argv[0], EXIT_FAILURE);
1942 if (p && *p)
1944 fprintf (stderr, N_("%s: invalid argument for option '--%s'\n"),
1945 argv[0], long_opts[opt_index].name);
1946 usage (argv[0], EXIT_FAILURE);
1949 break;
1950 #ifdef WITH_SSH
1951 case 'i':
1952 identity = optarg;
1953 break;
1954 case 'k':
1955 knownhosts = optarg;
1956 break;
1957 #endif
1958 case 'L':
1959 inquire_line = optarg;
1960 break;
1961 case 'y':
1962 tty = optarg;
1963 break;
1964 case 't':
1965 ttytype = optarg;
1966 break;
1967 case 'd':
1968 display = optarg;
1969 break;
1970 case 'S':
1971 save = 1;
1972 break;
1973 case 'n':
1974 clientname = optarg;
1975 break;
1976 default:
1977 usage (argv[0], EXIT_FAILURE);
1981 #ifdef HAVE_LIBREADLINE
1982 if (interactive && !isatty (STDIN_FILENO))
1983 usage (argv[0], EXIT_FAILURE);
1984 else if (isatty (STDIN_FILENO) && !inquire && !inquire_line)
1985 interactive = 1;
1986 #endif
1988 pwmd_init ();
1989 rc = pwmd_new (clientname, &pwm);
1990 if (rc)
1991 goto done;
1993 filename = argv[optind] ? pwmd_strdup (argv[optind]) : NULL;
1994 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1995 if (rc)
1996 goto done;
1998 pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
1999 if (!quiet)
2000 fprintf (stderr, N_("Connecting ...\n"));
2002 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
2003 socktype = is_remote_url (url);
2004 if (socktype != PWMD_SOCKET_LOCAL)
2006 local_pin = 1;
2007 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2008 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, connect_timeout);
2009 if (rc)
2010 goto done;
2011 #endif
2013 if (socktype == PWMD_SOCKET_SSH)
2015 #ifdef WITH_SSH
2016 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_CB, knownhost_cb);
2017 if (rc)
2018 goto done;
2020 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_DATA, clientname);
2021 if (rc)
2022 goto done;
2024 if (!getenv ("SSH_AUTH_SOCK") || identity)
2025 use_ssh_agent = 0;
2027 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_AGENT, use_ssh_agent);
2028 if (rc)
2029 goto done;
2031 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_NEEDS_PASSPHRASE,
2032 needs_passphrase);
2033 if (rc)
2034 goto done;
2036 rc = pwmd_connect (pwm, url, identity, knownhosts);
2037 #endif
2039 #ifdef WITH_GNUTLS
2040 else
2042 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_VERIFY, tls_verify);
2043 if (rc)
2044 goto done;
2046 rc = pwmd_connect (pwm, url, clientcert, clientkey, cacert, prio,
2047 tls_fingerprint);
2049 #endif
2051 else
2052 rc = pwmd_connect (pwm, url);
2053 #else
2054 rc = pwmd_connect (pwm, url);
2055 #endif
2056 if (rc)
2057 goto done;
2059 if (!quiet)
2060 fprintf (stderr, N_("Connected.\n"));
2062 connected = 1;
2063 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2064 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, socket_timeout);
2065 if (rc)
2066 goto done;
2067 #endif
2069 if (lock_timeout)
2071 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
2072 "OPTION LOCK-TIMEOUT=%li", lock_timeout);
2073 if (rc)
2074 goto done;
2077 if (lock_on_open)
2079 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCK_ON_OPEN, 1);
2080 if (rc)
2081 goto done;
2084 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, NULL, NULL);
2085 if (rc)
2086 goto done;
2088 if (timeout > 0)
2090 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
2091 if (rc)
2092 goto done;
2095 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY,
2096 (local_pin || keyfile || new_keyfile || sign_keyfile));
2097 if (rc)
2098 goto done;
2100 if (pinentry_path)
2102 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
2103 if (rc)
2104 goto done;
2107 if (display)
2109 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
2110 if (rc)
2111 goto done;
2114 if (tty)
2116 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, tty);
2117 if (rc)
2118 goto done;
2121 if (ttytype)
2123 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
2124 if (rc)
2125 goto done;
2128 if (lcctype)
2130 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
2131 if (rc)
2132 goto done;
2135 if (lcmessages)
2137 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES, lcmessages);
2138 if (rc)
2139 goto done;
2142 if (show_status)
2144 rc = pwmd_setopt (pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
2145 if (rc)
2146 goto done;
2149 if (filename)
2151 rc = open_command (filename);
2152 if (rc)
2153 goto done;
2156 #ifdef HAVE_LIBREADLINE
2157 if (interactive)
2159 rc = do_interactive ();
2160 result = NULL;
2161 goto do_exit;
2163 #endif
2165 if (inquire)
2167 struct inquire_s *inq = NULL;
2169 rc = set_inquire (inquirefd, inquire_line, &inq);
2170 if (!rc)
2171 rc = pwmd_command (pwm, &result, &len, inquire_cb, inq, "%s", inquire);
2173 free_inquire (inq);
2174 goto done;
2177 if (fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1)
2179 rc = gpg_error_from_errno (errno);
2180 goto done;
2183 ssize_t n;
2185 for (;;)
2187 rc = process_cmd ();
2189 if (rc)
2190 goto done;
2192 n = read (STDIN_FILENO, command, sizeof (command)-1);
2193 if (n == -1)
2195 if (errno == EAGAIN)
2197 usleep (100000);
2198 continue;
2201 rc = gpg_error_from_errno (errno);
2202 goto done;
2204 else if (!n)
2205 goto done;
2207 p = command;
2208 command[n] = 0;
2209 break;
2212 if (!p || !*p || !strcasecmp (p, "BYE"))
2213 goto done;
2216 struct inquire_s *inq = NULL;
2217 rc = set_inquire (inquirefd, inquire_line, &inq);
2218 if (!rc)
2220 rc = parse_dotcommand (command, &result, &len, inq);
2221 free_inquire (inq);
2224 if (rc)
2225 goto done;
2227 done:
2228 if (result)
2230 fwrite (result, 1, result[len - 1] == 0 ? len - 1 : len, outfp);
2231 fflush (outfp);
2232 pwmd_free (result);
2235 result = NULL;
2236 if (!rc)
2237 rc = finalize ();
2238 else if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
2239 (void) pwmd_command (pwm, &result, NULL, NULL, NULL,
2240 "GETINFO last_error");
2242 #ifdef HAVE_LIBREADLINE
2243 do_exit:
2244 #endif
2245 memset (command, 0, sizeof (command));
2247 if (rc && !quiet)
2248 show_error (pwm, rc, result);
2250 pwmd_close (pwm);
2251 reset_keyfiles ();
2252 pwmd_deinit ();
2253 pwmd_free (result);
2254 pwmd_free (filename);
2255 parse_status_ignore (NULL);
2256 if (connected && !quiet)
2257 fprintf (stderr, N_("Connection closed.\n"));
2259 exit (rc ? EXIT_FAILURE : EXIT_SUCCESS);