pwmc: Add passphrase-file options.
[libpwmd.git] / src / pwmc.c
blobe26e89ec993ad656129045abdcad271f1cb75b08
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>
42 #include <signal.h>
44 #ifdef WITH_GNUTLS
45 #include <gnutls/gnutls.h>
46 #endif
48 #ifdef HAVE_LOCALE_H
49 #include <locale.h>
50 #endif
52 #ifdef HAVE_GETOPT_LONG
53 #ifdef HAVE_GETOPT_H
54 #include <getopt.h>
55 #endif
56 #else
57 #include "getopt_long.h"
58 #endif
60 #ifdef HAVE_LIBREADLINE
61 #if defined(HAVE_READLINE_READLINE_H)
62 #include <readline/readline.h>
63 #elif defined(HAVE_READLINE_H)
64 #include <readline.h>
65 #endif /* !defined(HAVE_READLINE_H) */
66 static int interactive_error;
67 static int interactive;
68 #endif /* HAVE_LIBREADLINE */
70 #ifdef HAVE_READLINE_HISTORY
71 #if defined(HAVE_READLINE_HISTORY_H)
72 #include <readline/history.h>
73 #elif defined(HAVE_HISTORY_H)
74 #include <history.h>
75 #endif
76 #endif /* HAVE_READLINE_HISTORY */
78 #ifndef LINE_MAX
79 #define LINE_MAX 2048
80 #endif
82 #include "gettext.h"
83 #define N_(msgid) gettext(msgid)
85 #include "mem.h"
88 #define DEFAULT_STATUS_IGNORE "KEEPALIVE,STATE,GPGME,PASSPHRASE_INFO,PASSPHRASE_HINT"
89 #define DEFAULT_PIN_TIMEOUT 30
90 #define DEFAULT_PIN_TRIES 3
91 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
92 ? gpg_error(rc) : rc
94 static int no_pinentry;
95 static pwm_t *pwm;
96 static char *filename;
97 static int save;
98 static char *keyid;
99 static char *sign_keyid;
100 static int symmetric;
101 static char *keyparams;
102 static char *keyfile;
103 static char *new_keyfile;
104 static char *sign_keyfile;
105 static int tries;
106 static int local_pin;
107 static int inquirefd;
108 static int statusfd;
109 FILE *statusfp;
110 static int quiet;
111 static char **status_ignore;
113 struct inquire_s
115 int fd;
116 char *line;
117 size_t len;
118 size_t size; // from stat(2).
119 char *last_keyword;
122 static gpg_error_t finalize ();
123 static gpg_error_t set_inquire (int fd, const char *line,
124 struct inquire_s **result);
125 static gpg_error_t parse_dotcommand (const char *line, char **result,
126 size_t * len, struct inquire_s *inq);
127 static gpg_error_t open_command (const char *line);
128 #ifdef WITH_SSH
129 static gpg_error_t get_password (char **result, pwmd_pinentry_t w, int echo);
130 #endif
132 static void
133 show_error (pwm_t *pwm, gpg_error_t rc, const char *str)
135 #ifdef WITH_GNUTLS
136 if (pwmd_tls_error (pwm))
137 fprintf(stderr, "TLS: %s\n", gnutls_strerror(pwmd_tls_error(pwm)));
138 #endif
139 fprintf (stderr, "ERR %i: %s%s%s%s", rc, gpg_strerror (rc),
140 str ? ": " : "", str ? str : "", str ? "" : "\n");
143 static void
144 reset_keyfiles ()
146 pwmd_free (keyfile);
147 pwmd_free (new_keyfile);
148 pwmd_free (sign_keyfile);
149 keyfile = new_keyfile = sign_keyfile = NULL;
152 static void
153 usage (const char *pn, int status)
155 fprintf (status == EXIT_FAILURE ? stderr : stdout,
156 N_("Usage: pwmc [options] [file]\n"
157 " --url <string>\n"
158 " a url string to connect to (%s, see below)\n"
159 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
160 " --connect-timeout <seconds>\n"
161 " seconds before connecting to a remote host fails (0=disabled, 120)\n"
162 " --socket-timeout <seconds>\n"
163 " seconds before a remote command fails (0=disabled, 300)\n"
164 #endif
165 #ifdef WITH_GNUTLS
166 " --ca-cert <filename>\n"
167 " certificate authority (CA) used to sign the server cert\n"
168 " --client-cert <filename>\n"
169 " client certificate to use for authentication\n"
170 " --client-key <filename>\n"
171 " key file used to protect the client certificate\n"
172 " --tls-priority <string>\n"
173 " compression, cipher and hash algorithm string\n"
174 " (SECURE256:SECURE192:SECURE128:-VERS-SSL3.0)\n"
175 " --tls-verify\n"
176 " verify the hostname against the server certificate\n"
177 " --tls-fingerprint <string>\n"
178 " a SHA-256 hash of the server fingerprint to verify against\n"
179 #endif
180 #ifdef WITH_SSH
181 " --no-ssh-agent\n"
182 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
183 " --identity, -i <filename>\n"
184 " the ssh identity file to use for authentication\n"
185 " --knownhosts, -k <filename>\n"
186 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
187 #endif
188 " --no-lock\n"
189 " do not lock the data file upon opening it\n"
190 " --lock-timeout <N>\n"
191 " time in tenths of a second to wait for a locked data file (50)\n"
192 " --name, -n <string>\n"
193 " set the client name\n"
194 " --pinentry <path>\n"
195 " the full path to the pinentry binary\n"
196 " --local-pinentry\n"
197 " force using a local pinentry\n"
198 " --no-pinentry\n"
199 " disable pinentry both remotely and locally\n"
200 " --ttyname, -y <path>\n"
201 " tty that pinentry will use\n"
202 " --ttytype, -t <string>\n"
203 " pinentry terminal type (default is $TERM)\n"
204 " --display, -d\n"
205 " pinentry display (default is $DISPLAY)\n"
206 " --lc-ctype <string>\n"
207 " locale setting for pinentry\n"
208 " --lc-messages <string>\n"
209 " locale setting for pinentry\n"
210 " --tries <N>\n"
211 " number of pinentry tries before failing (3)\n"
212 " --timeout <seconds>\n"
213 " pinentry timeout\n"
214 " --inquire <COMMAND>\n"
215 " the specified command (with any options) uses a server inquire while\n"
216 " command data is read via the inquire file descriptor (stdin)\n"
217 " --inquire-line, -L <STRING>\n"
218 " the initial line to send (i.e., element path) before the inquire data\n"
219 " --inquire-fd <FD>\n"
220 " read inquire data from the specified file descriptor (stdin)\n"
221 " --inquire-file <filename>\n"
222 " read inquire data from the specified filename\n"
223 " --output-fd <FD>\n"
224 " redirect command output to the specified file descriptor\n"
225 " --save, -S\n"
226 " send the SAVE command before exiting\n"
227 " --passphrase-file <filename>\n"
228 " obtain the passphrase from the specified filename\n"
229 " --new-passphrase-file <filename>\n"
230 " obtain the passphrase to save with from the specified filename\n"
231 " --sign-passphrase-file <filename>\n"
232 " obtain the passphrase to sign with (symmetric) from the specified filename\n"
233 " --key-params <filename>\n"
234 " key parameters to use for key generation (pwmd default)\n"
235 " --keyid <recipient>[,<recipient>]\n"
236 " the public key ID to u\n"
237 " --sign-keyid <string>\n"
238 " the key ID to sign the data file with\n"
239 " --symmetric\n"
240 " use conventional encryption with optional signer(s) for new files\n"
241 " --no-status\n"
242 " disable showing of status messages from the server\n"
243 " --status-ignore <string[,...]>\n"
244 " prevent parsing of the specified status message keywords\n"
245 " --quiet\n"
246 " disable showing of extra messages (implies --no-status)\n"
247 " --status-fd <FD>\n"
248 " redirect status messages to the specified file descriptor\n"
249 #ifdef HAVE_LIBREADLINE
250 " --interactive\n"
251 " use a shell like interface to pwmd (allows more than one command)\n"
252 #endif
253 " --version\n"
254 " --help\n"),
255 #ifdef DEFAULT_PWMD_SOCKET
256 DEFAULT_PWMD_SOCKET
257 #else
258 "~/.pwmd/socket"
259 #endif
261 fprintf (status == EXIT_FAILURE ? stderr : stdout,
262 N_("\n"
263 "An optional url may be in the form of:\n"
264 " --url /path/to/socket\n"
265 " --url file://[path/to/socket]\n"
266 #ifdef WITH_SSH
267 " or\n"
268 " --url ssh[46]://[username@]hostname[:port]\n"
269 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
270 #endif
271 #ifdef WITH_GNUTLS
272 " or\n"
273 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
274 " --client-key filename\n"
275 #endif
276 #ifdef HAVE_LIBREADLINE
277 "\n"
278 "Interactive mode is used when input is from a terminal.\n"
279 #endif
281 exit (status);
284 static gpg_error_t
285 inquire_cb (void *user, const char *keyword, gpg_error_t rc,
286 char **data, size_t * size)
288 struct inquire_s *inq = user;
289 int is_password = 0;
290 int is_newpassword = 0;
291 int sign = 0;
292 int is_keyparam = 0;
294 *data = NULL;
295 *size = 0;
297 if (rc)
298 return rc;
300 if (!strcmp (keyword, "PASSPHRASE"))
301 is_password = 1;
302 else if (!strcmp (keyword, "SIGN_PASSPHRASE"))
303 is_password = sign = 1;
304 else if (!strcmp (keyword, "NEW_PASSPHRASE"))
305 is_newpassword = 1;
306 #ifdef HAVE_LIBREADLINE
307 else if (!strcmp (keyword, "KEYPARAM") && !interactive)
309 #else
310 else if (!strcmp (keyword, "KEYPARAM"))
312 #endif
313 int fd;
314 if (!keyparams || !*keyparams)
315 return gpg_error (GPG_ERR_INV_PARAMETER);
317 fd = open (keyparams, O_RDONLY);
318 if (fd == -1)
320 fprintf (stderr, "%s: %s\n", keyparams, strerror (errno));
321 return gpg_error_from_syserror ();
324 rc = set_inquire (fd, NULL, &inq);
325 if (rc)
327 close (fd);
328 return rc;
331 if (!quiet)
332 fprintf (stderr, N_("Using file '%s' as %s.\n"), keyparams, keyword);
334 is_keyparam = 1;
337 if ((is_newpassword && new_keyfile) || (is_password && keyfile)
338 || (sign && sign_keyfile))
340 int fd;
342 if (sign)
343 fd = open (sign_keyfile, O_RDONLY);
344 else
345 fd = open (is_password ? keyfile : new_keyfile, O_RDONLY);
347 if (fd == -1)
349 if (sign)
350 fprintf (stderr, "%s: %s\n", sign_keyfile, strerror (errno));
351 else
352 fprintf (stderr, "%s: %s\n", is_newpassword ? new_keyfile
353 : keyfile, strerror (errno));
354 return gpg_error_from_syserror ();
357 rc = set_inquire (fd, NULL, &inq);
358 if (rc)
360 close (fd);
361 return rc;
364 if (!quiet)
365 fprintf (stderr, N_("Using keyfile '%s' as %s.\n"),
366 sign ? sign_keyfile : is_newpassword ? new_keyfile
367 : keyfile, keyword);
369 else if ((is_password && !keyfile) || (is_newpassword && !new_keyfile)
370 || (sign && !sign_keyfile))
372 char *tmp;
374 rc = pwmd_password (pwm, keyword, &tmp, &inq->len);
375 if (rc && gpg_err_code (rc) != GPG_ERR_EOF)
376 return rc;
378 pwmd_free (inq->line);
379 inq->line = tmp;
380 *data = inq->line;
381 *size = inq->len;
382 return gpg_error (GPG_ERR_EOF);
384 #ifdef HAVE_LIBREADLINE
385 else if ((!inq->last_keyword || strcmp (keyword, inq->last_keyword))
386 && interactive)
388 fprintf (stderr,
390 ("%sPress CTRL-D to send the current line. Press twice to end. %s:\n"),
391 inq->last_keyword ? "\n" : "", keyword);
392 pwmd_free (inq->last_keyword);
393 inq->last_keyword = pwmd_strdup (keyword);
395 #endif
397 /* The first part of the command data. */
398 if (inq->len)
400 *data = inq->line;
401 *size = inq->len;
402 inq->len = 0;
403 return inq->fd == -1 ? gpg_error (GPG_ERR_EOF) : 0;
406 *size = read (inq->fd, inq->line, ASSUAN_LINELENGTH);
407 if (*size == -1)
409 *size = 0;
410 return gpg_error (gpg_error_from_syserror ());
412 else if (*size)
413 *data = inq->line;
414 else if (inq->fd != STDIN_FILENO &&
415 (is_newpassword || is_password || is_keyparam))
417 *inq->line = 0;
418 inq->size = 1;
419 *data = inq->line;
420 *size = 1;
423 if (((is_newpassword && new_keyfile) || (is_password && keyfile)
424 || (sign && sign_keyfile) || (keyparams && is_keyparam))
425 && *size == inq->size)
426 return gpg_error (GPG_ERR_EOF);
428 return *size ? 0 : gpg_error (GPG_ERR_EOF);
431 static int
432 status_msg_cb (void *data, const char *line)
434 char *p = strchr (line, ' ');
435 char **s;
437 /* Ignore status messages specified by the client via --status-ignore. */
438 for (s = status_ignore; s && *s; s++)
440 char *tmp = strchr (line, ' ');
441 size_t len = tmp ? strlen (line) - strlen (tmp) : strlen (line);
443 if (!strncmp (line, *s, len) && len == strlen (*s))
444 return 0;
447 if (statusfd != STDERR_FILENO && strncmp (line, "STATE ", 6) && *line != '#'
448 && p && strchr (p, ' ') && *++p)
450 char *p1 = strchr (p, ' ');
451 int a = strtol (p, NULL, 10);
453 if (isdigit (*p) && p1)
455 int b = strtol (p1, NULL, 10);
456 char l[64] = { 0 };
457 int t = a && b ? a * 100 / b : 0;
459 strncpy (l, line, strlen (line) - strlen (p) - 1);
460 fprintf (statusfp, "\r%s %i/%i %i%%%s", l, a, b, t,
461 a == b ? "\n" : "");
462 fflush (statusfp);
463 return 0;
467 fprintf (statusfp, "%s\n", line);
468 fflush (statusfp);
469 #ifdef HAVE_LIBREADLINE
470 rl_on_new_line ();
471 #endif
472 return 0;
475 static gpg_error_t
476 process_cmd ()
478 return pwmd_process (pwm);
481 #ifdef WITH_SSH
482 static gpg_error_t
483 get_password (char **result, pwmd_pinentry_t w, int echo)
485 char buf[LINE_MAX] = { 0 }, *p;
486 struct termios told, tnew;
487 char *key = NULL;
489 *result = NULL;
491 if (!isatty (STDIN_FILENO))
493 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
494 return GPG_ERR_ENOTTY;
497 if (!echo)
499 if (tcgetattr (STDIN_FILENO, &told) == -1)
500 return gpg_error_from_syserror ();
502 memcpy (&tnew, &told, sizeof (struct termios));
503 tnew.c_lflag &= ~(ECHO);
504 tnew.c_lflag |= ICANON | ECHONL;
506 if (tcsetattr (STDIN_FILENO, TCSANOW, &tnew) == -1)
508 int n = errno;
510 tcsetattr (STDIN_FILENO, TCSANOW, &told);
511 return gpg_error_from_errno (n);
515 switch (w)
517 case PWMD_PINENTRY_OPEN:
518 fprintf (stderr, N_("Password for %s: "), filename);
519 break;
520 case PWMD_PINENTRY_OPEN_FAILED:
521 fprintf (stderr, N_("Invalid password. Password for %s: "), filename);
522 break;
523 case PWMD_PINENTRY_SAVE:
524 fprintf (stderr, N_("New password for %s: "), filename);
525 break;
526 case PWMD_PINENTRY_SAVE_CONFIRM:
527 fprintf (stderr, N_("Confirm password: "));
528 break;
529 default:
530 break;
533 if ((p = fgets (buf, sizeof (buf), stdin)) == NULL)
535 if (!echo)
536 tcsetattr (STDIN_FILENO, TCSANOW, &told);
538 return 0;
541 if (!echo)
542 tcsetattr (STDIN_FILENO, TCSANOW, &told);
544 if (feof (stdin))
546 clearerr (stdin);
547 return GPG_ERR_CANCELED;
550 p[strlen (p) - 1] = 0;
552 if (buf[0])
554 key = pwmd_strdup_printf ("%s", p);
555 memset (&buf, 0, sizeof (buf));
557 if (!key)
558 return GPG_ERR_ENOMEM;
561 *result = key;
562 return 0;
565 static gpg_error_t
566 knownhost_cb (void *data, const char *host, const char *key, size_t len)
568 gpg_error_t rc;
569 char *buf =
570 pwmd_strdup_printf (N_
571 ("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?"),
572 (char *) data, host, host);
574 if (no_pinentry && !isatty (STDIN_FILENO))
576 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
577 pwmd_free (buf);
578 return GPG_ERR_ENOTTY;
580 else if (no_pinentry)
582 for (char *p = buf, len = 0; *p; p++, len++)
584 if (*p == '\n')
585 len = 0;
587 if (len == 78)
589 char *t = p;
591 while (!isspace (*(--p)));
592 *p = '\n';
593 p = t;
594 len = 0;
598 fprintf (stderr, "%s\n\n", buf);
599 pwmd_free (buf);
603 char *result;
605 fprintf (stderr, N_("Trust this connection [y/N]: "));
606 fflush (stderr);
607 rc = get_password (&result, PWMD_PINENTRY_CONFIRM, 1);
609 if (rc)
610 return rc;
612 if (!result || !*result || *result == 'n' || *result == 'N')
614 if (result && *result)
615 pwmd_free (result);
617 return GPG_ERR_NOT_CONFIRMED;
620 if ((*result == 'y' || *result == 'Y') && *(result + 1) == 0)
622 pwmd_free (result);
623 return 0;
626 while (1);
629 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, buf);
630 pwmd_free (buf);
632 if (rc)
633 return rc;
635 return pwmd_getpin (pwm, NULL, NULL, NULL, PWMD_PINENTRY_CONFIRM);
637 #endif
639 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
640 static pwmd_socket_t
641 is_remote_url (const char *str)
643 if (!str)
644 return PWMD_SOCKET_LOCAL;
646 #ifdef WITH_SSH
647 if (strstr (str, "ssh://") || strstr (str, "ssh4://")
648 || strstr (str, "ssh6://"))
649 return PWMD_SOCKET_SSH;
650 #endif
652 #ifdef WITH_GNUTLS
653 if (strstr (str, "tls://") || strstr (str, "tls4://")
654 || strstr (str, "tls6://"))
655 return PWMD_SOCKET_TLS;
656 #endif
658 return PWMD_SOCKET_LOCAL;
660 #endif
662 static char *
663 escape (const char *str)
665 const char *p;
666 char *buf = pwmd_malloc (ASSUAN_LINELENGTH + 1), *b = buf;
667 size_t len = 0;
669 for (p = str; *p; p++, len++)
671 if (len == ASSUAN_LINELENGTH)
672 break;
674 if (*p == '\\')
676 switch (*++p)
678 case 't':
679 *b++ = '\t';
680 break;
681 case 'n':
682 *b++ = '\n';
683 break;
684 case 'v':
685 *b++ = '\v';
686 break;
687 case 'b':
688 *b++ = '\b';
689 break;
690 case 'f':
691 *b++ = '\f';
692 break;
693 case 'r':
694 *b++ = '\r';
695 break;
696 default:
697 *b++ = *p;
698 break;
701 if (!*p)
702 break;
704 continue;
707 *b++ = *p;
710 *b = 0;
711 return buf;
714 static void
715 free_inquire (struct inquire_s *inq)
717 if (!inq)
718 return;
720 pwmd_free (inq->line);
722 if (inq->fd != -1 && inq->fd != STDIN_FILENO)
723 close (inq->fd);
725 pwmd_free (inq->last_keyword);
726 pwmd_free (inq);
729 /* When *result is not NULL it is updated to the new values and not
730 * reallocated. */
731 static gpg_error_t
732 set_inquire (int fd, const char *line, struct inquire_s **result)
734 struct inquire_s inq = { 0 };
735 struct stat st = { 0 };
736 gpg_error_t rc;
738 if (fd != -1)
740 if (fstat (fd, &st) == -1)
741 return gpg_error_from_syserror ();
743 inq.size = st.st_size;
746 inq.fd = fd;
747 inq.line = pwmd_calloc (1, ASSUAN_LINELENGTH);
748 if (!inq.line)
749 return GPG_ERR_ENOMEM;
751 if (line)
753 char *s = escape (line);
755 if (!s)
757 pwmd_free (inq.line);
758 return GPG_ERR_ENOMEM;
761 if (strlen (s) >= ASSUAN_LINELENGTH)
763 pwmd_free (inq.line);
764 pwmd_free (s);
765 return GPG_ERR_LINE_TOO_LONG;
768 strncpy (inq.line, s, ASSUAN_LINELENGTH - 1);
769 inq.len = strlen (s);
770 pwmd_free (s);
773 rc = pwmd_setopt (pwm, PWMD_OPTION_INQUIRE_TOTAL,
774 st.st_size ? st.st_size + strlen (inq.line) : 0);
775 if (rc)
777 pwmd_free (inq.line);
778 return rc;
781 if (*result == NULL)
782 *result = pwmd_malloc (sizeof (struct inquire_s));
783 else
785 if ((*result)->fd != -1 && (*result)->fd != STDIN_FILENO)
786 close ((*result)->fd);
788 pwmd_free ((*result)->line);
789 (*result)->line = NULL;
790 (*result)->fd = -1;
791 (*result)->len = 0;
794 memcpy (*result, &inq, sizeof (struct inquire_s));
795 memset (&inq, 0, sizeof (struct inquire_s));
796 return rc;
799 #ifdef HAVE_LIBREADLINE
800 static int
801 interactive_hook (void)
803 interactive_error = process_cmd ();
805 if (interactive_error)
806 rl_event_hook = NULL;
808 return 0;
811 static int
812 get_readline_char (FILE *fp)
814 if (rl_line_buffer
815 && (!strncmp (rl_line_buffer, ".set passphrase-file ", 16)
816 || !strncmp (rl_line_buffer, ".set new-passphrase-file ", 20)
817 || !strncmp (rl_line_buffer, ".set sign-passphrase-file ", 21)))
818 rl_inhibit_completion = 0;
819 else if (rl_line_buffer
820 && !strncmp (rl_line_buffer, ".redir ", 7))
822 char *p = strchr (rl_line_buffer, ' ');
824 if (strchr (++p, ' '))
825 rl_inhibit_completion = 1;
826 else
827 rl_inhibit_completion = 0;
829 else if (rl_line_buffer
830 && !strncmp (rl_line_buffer, ".read ", 6))
832 char *p = rl_line_buffer + 6;
834 if (strstr (p, "--prefix "))
836 p = strstr (p, "--prefix ");
837 p += 9;
838 p = strchr (p, ' ');
839 if (p)
840 p++;
843 if (!p || strchr (p, ' '))
844 rl_inhibit_completion = 1;
845 else
846 rl_inhibit_completion = 0;
848 else
849 rl_inhibit_completion = 1;
851 return fgetc (fp);
854 static void
855 print_help ()
857 fprintf (stderr,
859 ("------------------------------------------------------------\n"
860 "Elements are TAB delimited. Type HELP for protocol commands.\n"
861 "Type .help for pwmc commands. Press CTRL-D to quit.\n"
862 "------------------------------------------------------------\n"));
864 #endif
866 static char *
867 parse_arg (const char *src, char *dst, size_t len)
869 char *p = dst;
870 const char *s = src;
871 size_t n = 0;
873 for (; s && *s && *s != ' ' && n < len; s++, n++)
874 *p++ = *s;
876 *p = 0;
877 return dst;
880 static char *
881 parse_opt (char **line, const char *opt, gpg_error_t * rc)
883 static char result[ASSUAN_LINELENGTH] = { 0 }, *r = result;
884 char *s = strstr (*line, opt);
886 *rc = 0;
887 result[0] = 0;
888 r = result;
890 if (s)
892 size_t len = 0;
893 int quote = 0;
894 size_t rlen = strlen (opt);
895 char *p = s + rlen;
896 int lastc = 0;
898 while (*p && *p == ' ')
900 rlen++;
901 p++;
904 for (; *p && len < sizeof (result) - 1; p++, rlen++)
906 if (isspace (*p) && !quote)
907 break;
909 if (*p == '\"' && lastc != '\\')
911 quote = !quote;
912 lastc = *p;
913 continue;
916 *r++ = lastc = *p;
917 len++;
920 *r = 0;
922 if (len >= sizeof (result) - 1)
923 *rc = GPG_ERR_LINE_TOO_LONG;
924 else
926 p = s + rlen;
928 while (*p && *p == ' ')
929 p++;
931 *line = p;
935 return result;
938 static gpg_error_t
939 read_command (const char *line, char **result, size_t * len)
941 int fd;
942 gpg_error_t rc = 0;
943 char *filename = NULL;
944 struct inquire_s *inq = NULL;
945 char *p = (char *) line;
946 const char *prefix = parse_opt (&p, "--prefix", &rc);
947 char filebuf[ASSUAN_LINELENGTH];
949 if (rc)
950 return rc;
952 rc = GPG_ERR_SYNTAX;
954 if (p && *p)
956 while (*p && isspace (*p))
957 p++;
959 filename = parse_arg (p, filebuf, sizeof (filebuf));
960 if (filename && *filename)
962 p += strlen (filename) + 1;
964 while (*p && isspace (*p))
965 p++;
967 if (*p)
968 rc = 0;
972 if (rc)
974 fprintf (stderr,
976 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
977 fprintf (stderr,
979 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\\ = \\)\n"));
980 return rc;
983 fd = open (filename, O_RDONLY);
984 if (fd == -1)
985 return gpg_error_from_syserror ();
987 rc = set_inquire (fd, prefix && *prefix ? prefix : NULL, &inq);
988 if (rc)
990 close (fd);
991 return rc;
994 rc = pwmd_command (pwm, result, len, inquire_cb, inq, "%s", p);
995 free_inquire (inq);
996 return rc;
999 static gpg_error_t
1000 redir_command (const char *line)
1002 const char *p = line;
1003 int fd;
1004 gpg_error_t rc = GPG_ERR_SYNTAX;
1005 char *filename = NULL;
1006 struct inquire_s *inq = NULL;
1007 char *result = NULL;
1008 size_t len = 0;
1009 char filebuf[ASSUAN_LINELENGTH];
1011 if (p && *p && *++p)
1013 filename = parse_arg (p, filebuf, sizeof (filebuf));
1014 if (filename && *filename)
1016 p += strlen (filename) + 1;
1018 while (*p && isspace (*p))
1019 p++;
1021 if (*p)
1022 rc = 0;
1026 if (rc)
1028 fprintf (stderr, N_("Usage: .redir <filename> <command> [args]\n"));
1029 return rc;
1032 fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
1033 if (fd == -1)
1034 return gpg_error_from_syserror ();
1036 #ifdef HAVE_LIBREADLINE
1037 rc = set_inquire (interactive ? STDIN_FILENO : inquirefd, NULL, &inq);
1038 #else
1039 rc = set_inquire (inquirefd, NULL, &inq);
1040 #endif
1041 if (rc)
1043 close (fd);
1044 return rc;
1047 rc = parse_dotcommand (p, &result, &len, inq);
1048 if (!rc && result && len--)
1049 { // null byte which is always appended
1050 if (write (fd, result, len) != len)
1051 rc = GPG_ERR_TOO_SHORT;
1052 pwmd_free (result);
1055 free_inquire (inq);
1056 close (fd);
1057 return rc;
1060 static gpg_error_t
1061 help_command (const char *line)
1063 fprintf (stderr,
1064 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
1065 " .redir <filename> <command>\n"
1066 " redirect the output of a command to the specified file\n"
1067 "\n"
1068 " .open <filename>\n"
1069 " open the specified filename losing any changes to the current one\n"
1070 "\n"
1071 " .read [--prefix <string>] <filename> <command> [args]\n"
1072 " obtain data from the specified filename for an inquire command\n"
1073 "\n"
1074 " .set help | <name> [<value>]\n"
1075 " set option <name> to <value>\n"
1076 "\n"
1077 " .save [args]\n"
1078 " write changes of the file to disk\n"
1079 "\n"
1080 " .passwd [args]\n"
1081 " change the passphrase of a data file\n"
1082 "\n"
1083 " .help\n"
1084 " this help text\n"));
1085 return 0;
1088 static gpg_error_t
1089 open_command (const char *line)
1091 struct inquire_s *inq = NULL;
1092 const char *file = line;
1093 gpg_error_t rc;
1095 while (file && isspace (*file))
1096 file++;
1098 if (!file || !*file)
1100 fprintf (stderr, N_("Usage: .open <filename>\n"));
1101 return GPG_ERR_SYNTAX;
1104 #ifdef HAVE_LIBREADLINE
1105 if (interactive || !quiet)
1106 #else
1107 if (!quiet)
1108 #endif
1109 fprintf (stderr, N_("Opening data file \"%s\" ...\n"), file);
1111 #ifdef HAVE_LIBREADLINE
1112 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1113 #else
1114 rc = set_inquire (-1, NULL, &inq);
1115 #endif
1116 if (rc)
1117 return rc;
1119 if (keyfile)
1121 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1122 if (!rc)
1123 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 1);
1125 else
1127 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1128 if (!rc)
1129 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1132 if (!rc)
1133 rc = pwmd_open (pwm, file, inquire_cb, inq);
1135 #ifdef HAVE_LIBREADLINE
1136 if (interactive)
1137 reset_keyfiles ();
1138 #endif
1140 free_inquire (inq);
1141 if (!rc)
1143 pwmd_free (filename);
1144 filename = pwmd_strdup (file);
1147 return rc;
1150 static gpg_error_t
1151 set_command (const char *line)
1153 gpg_error_t rc = 0;
1154 char name[256] = { 0 };
1155 char value[512] = { 0 };
1156 char *namep;
1157 char *valuep;
1158 const char *p = line;
1160 while (p && *p && isspace (*p))
1161 p++;
1163 namep = parse_arg (p, name, sizeof (name));
1164 if (!namep || !*namep)
1166 fprintf (stderr, N_("Usage: .set help | <name> [<value>]\n"));
1167 return GPG_ERR_SYNTAX;
1170 p += strlen (namep);
1171 while (p && *p && isspace (*p))
1172 p++;
1174 valuep = parse_arg (p, value, sizeof (value));
1176 if (!strcmp (name, "passphrase-file") || !strcmp (name, "new-passphrase-file")
1177 || !strcmp (name, "sign-passphrase-file"))
1179 int is_newkeyfile = 1;
1180 int sign = !strcmp (name, "sign-passphrase-file");
1182 if (!strcmp (name, "passphrase-file") || sign)
1183 is_newkeyfile = 0;
1185 if (is_newkeyfile)
1187 pwmd_free (new_keyfile);
1188 new_keyfile = NULL;
1190 else if (sign)
1192 pwmd_free (sign_keyfile);
1193 sign_keyfile = NULL;
1195 else
1197 pwmd_free (keyfile);
1198 keyfile = NULL;
1201 if (!rc && *valuep)
1203 if (is_newkeyfile)
1204 new_keyfile = pwmd_strdup (value);
1205 else if (sign)
1206 sign_keyfile = pwmd_strdup (value);
1207 else
1208 keyfile = pwmd_strdup (value);
1210 if (!rc)
1212 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 1);
1213 if (!rc)
1214 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1217 else if (!local_pin && !no_pinentry)
1219 pwmd_socket_t t;
1221 pwmd_socket_type (pwm, &t);
1222 if (t == PWMD_SOCKET_LOCAL)
1224 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 0);
1225 if (!rc)
1226 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1230 else if (!strcmp(name, "pinentry-timeout"))
1232 char *e = NULL;
1233 int n = strtol(valuep, &e, 10);
1235 if (e && *e)
1236 return gpg_error (GPG_ERR_INV_VALUE);
1238 if (!*valuep)
1239 n = DEFAULT_PIN_TIMEOUT;
1241 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, n);
1243 else if (!strcmp (name, "help"))
1245 fprintf (stderr,
1247 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1248 "delimited. When no value is specified the option is unset.\n\n"
1249 "passphrase-file [<filename>]\n"
1250 " set or unset the file to be used when a passphrase is required (*)\n"
1251 "\n"
1252 "new-passphrase-file [<filename>]\n"
1253 " set or unset the file to be used when a new passphrase is required (*)\n"
1254 "\n"
1255 "sign-passphrase-file [<filename>]\n"
1256 " set or unset the file to be used when a passphrase is required for\n"
1257 " signing (symmetric) (*)\n"
1258 "\n"
1259 "pinentry-timeout <seconds>\n"
1260 " the amount of seconds before pinentry gives up waiting for input\n"
1261 "\n"
1262 "* = the next protocol command will unset this value\n"
1265 else
1266 rc = GPG_ERR_UNKNOWN_OPTION;
1268 return rc;
1271 static gpg_error_t
1272 save_command (const char *line)
1274 struct inquire_s *inq = NULL;
1275 gpg_error_t rc;
1277 #ifdef HAVE_LIBREADLINE
1278 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1279 #else
1280 rc = set_inquire (-1, NULL, &inq);
1281 #endif
1282 if (rc)
1283 return rc;
1285 if (new_keyfile || keyfile || sign_keyfile)
1287 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1288 if (!rc)
1289 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 1);
1291 else
1293 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1294 if (!rc)
1295 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1298 if (!rc)
1299 rc = pwmd_save (pwm, line, inquire_cb, inq);
1301 #ifdef HAVE_LIBREADLINE
1302 if (interactive)
1303 reset_keyfiles ();
1304 #endif
1306 free_inquire (inq);
1307 return rc;
1310 static gpg_error_t
1311 do_save_passwd_command (const char *line, int save)
1313 struct inquire_s *inq = NULL;
1314 gpg_error_t rc;
1316 #ifdef HAVE_LIBREADLINE
1317 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1318 #else
1319 rc = set_inquire (-1, NULL, &inq);
1320 #endif
1321 if (rc)
1322 return rc;
1324 if (new_keyfile || keyfile || sign_keyfile)
1326 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1327 if (!rc)
1328 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 1);
1330 else
1332 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1333 if (!rc)
1334 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1337 if (!rc)
1339 if (save)
1340 rc = pwmd_save (pwm, line, inquire_cb, inq);
1341 else
1342 rc = pwmd_passwd (pwm, line, inquire_cb, inq);
1345 #ifdef HAVE_LIBREADLINE
1346 if (interactive)
1347 reset_keyfiles ();
1348 #endif
1350 free_inquire (inq);
1351 return rc;
1354 static gpg_error_t
1355 parse_dotcommand (const char *line, char **result,
1356 size_t * len, struct inquire_s *inq)
1358 const char *p = line;
1359 gpg_error_t rc = 0;
1361 if (!strncmp (p, ".read", 5))
1362 rc = read_command (p + 5, result, len);
1363 else if (!strncmp (p, ".redir", 6))
1364 rc = redir_command (p + 6);
1365 else if (!strncmp (p, ".help", 5))
1366 rc = help_command (p + 5);
1367 else if (!strncmp (p, ".open", 5))
1368 rc = open_command (p + 5);
1369 else if (!strncmp (p, ".set", 4))
1370 rc = set_command (p + 4);
1371 else if (!strncmp (p, ".save", 5))
1372 rc = do_save_passwd_command (p + 5, 1);
1373 else if (!strncmp (p, ".passwd", 7))
1374 rc = do_save_passwd_command (p + 7, 0);
1375 else
1377 rc = pwmd_command (pwm, result, len, inquire_cb, inq, "%s", line);
1378 #ifdef HAVE_LIBREADLINE
1379 if (interactive)
1381 #endif
1382 reset_keyfiles ();
1383 #ifdef HAVE_LIBREADLINE
1385 #endif
1388 return FINISH (rc);
1391 #ifdef HAVE_LIBREADLINE
1392 static gpg_error_t
1393 do_interactive ()
1395 gpg_error_t rc;
1396 struct inquire_s *inq = NULL;
1398 signal (SIGINT, SIG_IGN);
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 ("pwm> ");
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 #endif
1637 int lock_on_open = 1;
1638 long lock_timeout = 50;
1639 char *url = NULL;
1640 char *tmp = NULL;
1641 /* The order is important. */
1642 enum
1644 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1645 OPT_SOCKET_TIMEOUT, OPT_CONNECT_TIMEOUT,
1646 #endif
1647 #ifdef WITH_SSH
1648 OPT_USE_SSH_AGENT, OPT_IDENTITY, OPT_KNOWNHOSTS,
1649 #endif
1650 #ifdef WITH_GNUTLS
1651 OPT_CACERT, OPT_CLIENTCERT, OPT_CLIENTKEY, OPT_PRIORITY, OPT_VERIFY,
1652 OPT_SERVER_FP,
1653 #endif
1654 OPT_URL, OPT_LOCAL, OPT_TTYNAME, OPT_TTYTYPE, OPT_DISPLAY, OPT_LC_CTYPE,
1655 OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES, OPT_PINENTRY, OPT_KEYFILE,
1656 OPT_PASSPHRASE_FILE, OPT_NEW_KEYFILE, OPT_NEW_PASSPHRASE_FILE,
1657 OPT_SIGN_KEYFILE, OPT_SIGN_PASSPHRASE_FILE, OPT_NOLOCK, OPT_LOCK_TIMEOUT,
1658 OPT_SAVE, OPT_OUTPUT_FD, OPT_INQUIRE, OPT_INQUIRE_FD, OPT_INQUIRE_FILE,
1659 OPT_INQUIRE_LINE, OPT_NO_STATUS, OPT_STATUS_IGNORE, OPT_STATUSFD, OPT_NAME,
1660 OPT_VERSION, OPT_HELP, OPT_KEYID, OPT_SIGN_KEYID, OPT_SYMMETRIC,
1661 OPT_KEYPARAMS, OPT_NO_PINENTRY, OPT_QUIET,
1662 #ifdef HAVE_LIBREADLINE
1663 OPT_INTERACTIVE,
1664 #endif
1666 const struct option long_opts[] = {
1667 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1668 {"socket-timeout", 1, 0, 0},
1669 {"connect-timeout", 1, 0, 0},
1670 #endif
1672 #ifdef WITH_SSH
1673 {"no-ssh-agent", 0, 0, 0},
1674 {"identity", 1, 0, 'i'},
1675 {"knownhosts", 1, 0, 'k'},
1676 #endif
1677 #ifdef WITH_GNUTLS
1678 {"ca-cert", 1, 0, 0},
1679 {"client-cert", 1, 0, 0},
1680 {"client-key", 1, 0, 0},
1681 {"tls-priority", 1, 0, 0},
1682 {"tls-verify", 0, 0, 0},
1683 {"tls-fingerprint", 1, 0, 0},
1684 #endif
1685 {"url", 1, 0, 0},
1686 {"local-pinentry", 0, 0},
1687 {"ttyname", 1, 0, 'y'},
1688 {"ttytype", 1, 0, 't'},
1689 {"display", 1, 0, 'd'},
1690 {"lc-ctype", 1, 0, 0},
1691 {"lc-messages", 1, 0, 0},
1692 {"timeout", 1, 0, 0},
1693 {"tries", 1, 0, 0},
1694 {"pinentry", 1, 0, 0},
1695 {"key-file", 1, 0, 0},
1696 {"passphrase-file", 1, 0, 0},
1697 {"new-key-file", 1, 0, 0},
1698 {"new-passphrase-file", 1, 0, 0},
1699 {"sign-key-file", 1, 0, 0},
1700 {"sign-passphrase-file", 1, 0, 0},
1701 {"no-lock", 0, 0, 0},
1702 {"lock-timeout", 1, 0, 0},
1703 {"save", 0, 0, 'S'},
1704 {"output-fd", 1, 0, 0},
1705 {"inquire", 1, 0, 0},
1706 {"inquire-fd", 1, 0, 0},
1707 {"inquire-file", 1, 0, 0},
1708 {"inquire-line", 1, 0, 'L'},
1709 {"no-status", 0, 0, 0},
1710 {"status-ignore", 1, 0, 0},
1711 {"status-fd", 1, 0, 0},
1712 {"name", 1, 0, 'n'},
1713 {"version", 0, 0, 0},
1714 {"help", 0, 0, 0},
1715 {"keyid", 1, 0, 0},
1716 {"sign-keyid", 1, 0, 0},
1717 {"symmetric", 0, 0, 0},
1718 {"key-params", 1, 0, 0},
1719 {"no-pinentry", 0, 0, 0},
1720 {"quiet", 0, 0, 0},
1721 #ifdef HAVE_LIBREADLINE
1722 {"interactive", 0, 0},
1723 #endif
1724 {0, 0, 0, 0}
1726 #ifdef WITH_SSH
1727 const char *optstring = "L:y:t:d:P:I:Sn:i:k:s";
1728 #else
1729 const char *optstring = "L:y:t:d:P:I:Sn:s";
1730 #endif
1731 int opt_index = 0;
1733 #ifdef ENABLE_NLS
1734 setlocale (LC_ALL, "");
1735 bindtextdomain ("libpwmd", LOCALEDIR);
1736 #endif
1738 tries = DEFAULT_PIN_TRIES;
1739 inquirefd = STDIN_FILENO;
1740 statusfd = STDERR_FILENO;
1741 statusfp = fdopen (statusfd, "w");
1742 tmp = pwmd_strdup (DEFAULT_STATUS_IGNORE);
1743 parse_status_ignore (tmp);
1744 pwmd_free (tmp);
1746 while ((opt =
1747 getopt_long (argc, argv, optstring, long_opts, &opt_index)) != -1)
1749 switch (opt)
1751 /* Handle long options without a short option part. */
1752 case 0:
1753 switch (opt_index)
1755 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1756 case OPT_SOCKET_TIMEOUT:
1757 socket_timeout = strtol (optarg, &p, 10);
1758 break;
1759 case OPT_CONNECT_TIMEOUT:
1760 connect_timeout = strtol (optarg, &p, 10);
1761 break;
1762 #endif
1763 #ifdef WITH_SSH
1764 case OPT_USE_SSH_AGENT:
1765 use_ssh_agent = 0;
1766 break;
1767 #endif
1768 #ifdef WITH_GNUTLS
1769 case OPT_CACERT:
1770 cacert = optarg;
1771 break;
1772 case OPT_CLIENTCERT:
1773 clientcert = optarg;
1774 break;
1775 case OPT_CLIENTKEY:
1776 clientkey = optarg;
1777 break;
1778 case OPT_PRIORITY:
1779 prio = optarg;
1780 break;
1781 case OPT_VERIFY:
1782 tls_verify = 1;
1783 break;
1784 case OPT_SERVER_FP:
1785 tls_fingerprint = optarg;
1786 break;
1787 #endif
1788 case OPT_SYMMETRIC:
1789 symmetric = 1;
1790 break;
1791 case OPT_KEYPARAMS:
1792 keyparams = optarg;
1793 break;
1794 case OPT_KEYFILE:
1795 case OPT_PASSPHRASE_FILE:
1796 keyfile = pwmd_strdup (optarg);
1797 break;
1798 case OPT_NEW_KEYFILE:
1799 case OPT_NEW_PASSPHRASE_FILE:
1800 new_keyfile = pwmd_strdup (optarg);
1801 break;
1802 case OPT_SIGN_KEYFILE:
1803 case OPT_SIGN_PASSPHRASE_FILE:
1804 sign_keyfile = pwmd_strdup (optarg);
1805 break;
1806 case OPT_NOLOCK:
1807 lock_on_open = 0;
1808 break;
1809 case OPT_LOCK_TIMEOUT:
1810 lock_timeout = strtol (optarg, &p, 10);
1811 break;
1812 case OPT_URL:
1813 url = optarg;
1814 break;
1815 case OPT_LOCAL:
1816 local_pin = 1;
1817 break;
1818 case OPT_LC_CTYPE:
1819 lcctype = pwmd_strdup (optarg);
1820 break;
1821 case OPT_LC_MESSAGES:
1822 lcmessages = pwmd_strdup (optarg);
1823 break;
1824 case OPT_TIMEOUT:
1825 timeout = strtol (optarg, &p, 10);
1826 break;
1827 case OPT_TRIES:
1828 tries = strtol (optarg, &p, 10);
1829 break;
1830 case OPT_INQUIRE:
1831 inquire = escape (optarg);
1832 break;
1833 case OPT_INQUIRE_FD:
1834 inquirefd = strtol (optarg, &p, 10);
1835 if (!p)
1837 inquirefp = fdopen (inquirefd, "r");
1838 if (!inquirefp)
1839 err (EXIT_FAILURE, "%i", inquirefd);
1841 break;
1842 case OPT_INQUIRE_FILE:
1843 inquirefd = open (optarg, O_RDONLY);
1844 if (inquirefd == -1)
1845 err (EXIT_FAILURE, "%s", optarg);
1846 inquirefp = fdopen (inquirefd, "r");
1847 break;
1848 case OPT_OUTPUT_FD:
1849 outfd = strtol (optarg, &p, 10);
1850 if (!p || !*p)
1852 outfp = fdopen (outfd, "w");
1853 if (!outfp)
1854 err (EXIT_FAILURE, "%i", outfd);
1856 break;
1857 case OPT_NO_STATUS:
1858 show_status = 0;
1859 break;
1860 case OPT_STATUSFD:
1861 statusfd = strtol (optarg, &p, 10);
1862 if (!p || !*p)
1864 statusfp = fdopen (statusfd, "w");
1865 if (!statusfp)
1866 err (EXIT_FAILURE, "%i", statusfd);
1868 break;
1869 case OPT_STATUS_IGNORE:
1870 parse_status_ignore (optarg);
1871 break;
1872 case OPT_VERSION:
1873 printf ("%s (pwmc)\n\n"
1874 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016\n"
1875 "%s\n"
1876 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1877 "Compile-time features:\n"
1878 #ifdef HAVE_LIBREADLINE
1879 "+INTERACTIVE "
1880 #else
1881 "-INTERACTIVE "
1882 #endif
1883 #ifdef WITH_SSH
1884 "+SSH "
1885 #else
1886 "-SSH "
1887 #endif
1888 #ifdef WITH_GNUTLS
1889 "+GNUTLS "
1890 #else
1891 "-GNUTLS "
1892 #endif
1893 #ifdef WITH_PINENTRY
1894 "+PINENTRY "
1895 #else
1896 "-PINENTRY "
1897 #endif
1898 #ifdef WITH_QUALITY
1899 "+CRACK "
1900 #else
1901 "-CRACK "
1902 #endif
1903 #ifdef MEM_DEBUG
1904 "+MEM_DEBUG "
1905 #else
1906 "-MEM_DEBUG "
1907 #endif
1908 "\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1909 exit (EXIT_SUCCESS);
1910 case OPT_PINENTRY:
1911 pinentry_path = optarg;
1912 break;
1913 case OPT_HELP:
1914 usage (argv[0], EXIT_SUCCESS);
1915 case OPT_KEYID:
1916 keyid = optarg;
1917 break;
1918 case OPT_SIGN_KEYID:
1919 sign_keyid = optarg;
1920 break;
1921 case OPT_QUIET:
1922 quiet = 1;
1923 show_status = 0;
1924 break;
1925 case OPT_NO_PINENTRY:
1926 no_pinentry = 1;
1927 break;
1928 #ifdef HAVE_LIBREADLINE
1929 case OPT_INTERACTIVE:
1930 interactive = 1;
1931 break;
1932 #endif
1933 default:
1934 usage (argv[0], EXIT_FAILURE);
1937 if (p && *p)
1939 fprintf (stderr, N_("%s: invalid argument for option '--%s'\n"),
1940 argv[0], long_opts[opt_index].name);
1941 usage (argv[0], EXIT_FAILURE);
1944 break;
1945 #ifdef WITH_SSH
1946 case 'i':
1947 identity = optarg;
1948 break;
1949 case 'k':
1950 knownhosts = optarg;
1951 break;
1952 #endif
1953 case 'L':
1954 inquire_line = optarg;
1955 break;
1956 case 'y':
1957 tty = optarg;
1958 break;
1959 case 't':
1960 ttytype = optarg;
1961 break;
1962 case 'd':
1963 display = optarg;
1964 break;
1965 case 'S':
1966 save = 1;
1967 break;
1968 case 'n':
1969 clientname = optarg;
1970 break;
1971 default:
1972 usage (argv[0], EXIT_FAILURE);
1976 #ifdef HAVE_LIBREADLINE
1977 if (interactive && !isatty (STDIN_FILENO))
1978 usage (argv[0], EXIT_FAILURE);
1979 else if (isatty (STDIN_FILENO) && !inquire && !inquire_line)
1980 interactive = 1;
1981 #endif
1983 filename = argv[optind] ? pwmd_strdup (argv[optind]) : NULL;
1984 pwmd_init ();
1985 rc = pwmd_new (clientname, &pwm);
1986 if (rc)
1987 goto done;
1989 pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
1990 if (!quiet)
1991 fprintf (stderr, N_("Connecting ...\n"));
1993 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1994 socktype = is_remote_url (url);
1995 if (socktype != PWMD_SOCKET_LOCAL)
1997 local_pin = 1;
1998 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1999 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, connect_timeout);
2000 if (rc)
2001 goto done;
2002 #endif
2004 if (socktype == PWMD_SOCKET_SSH)
2006 #ifdef WITH_SSH
2007 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_CB, knownhost_cb);
2008 if (rc)
2009 goto done;
2011 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_DATA, clientname);
2012 if (rc)
2013 goto done;
2015 if (!getenv ("SSH_AUTH_SOCK") || identity)
2016 use_ssh_agent = 0;
2018 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_AGENT, use_ssh_agent);
2019 if (rc)
2020 goto done;
2022 rc = pwmd_connect (pwm, url, identity, knownhosts);
2023 #endif
2025 #ifdef WITH_GNUTLS
2026 else
2028 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_VERIFY, tls_verify);
2029 if (rc)
2030 goto done;
2032 rc = pwmd_connect (pwm, url, clientcert, clientkey, cacert, prio,
2033 tls_fingerprint);
2035 #endif
2037 else
2038 rc = pwmd_connect (pwm, url);
2039 #else
2040 rc = pwmd_connect (pwm, url);
2041 #endif
2042 if (rc)
2043 goto done;
2045 if (!quiet)
2046 fprintf (stderr, N_("Connected.\n"));
2048 connected = 1;
2049 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2050 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, socket_timeout);
2051 if (rc)
2052 goto done;
2053 #endif
2055 if (lock_timeout)
2057 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
2058 "OPTION LOCK-TIMEOUT=%li", lock_timeout);
2059 if (rc)
2060 goto done;
2063 if (lock_on_open)
2065 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCK_ON_OPEN, 1);
2066 if (rc)
2067 goto done;
2070 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, NULL, NULL);
2071 if (rc)
2072 goto done;
2074 if (timeout > 0)
2076 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
2077 if (rc)
2078 goto done;
2081 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
2082 if (rc)
2083 goto done;
2085 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY,
2086 (local_pin || keyfile || new_keyfile || sign_keyfile));
2087 if (rc)
2088 goto done;
2090 if (pinentry_path)
2092 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
2093 if (rc)
2094 goto done;
2097 if (display)
2099 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
2100 if (rc)
2101 goto done;
2104 if (tty)
2106 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, tty);
2107 if (rc)
2108 goto done;
2111 if (ttytype)
2113 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
2114 if (rc)
2115 goto done;
2118 if (lcctype)
2120 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
2121 if (rc)
2122 goto done;
2125 if (lcmessages)
2127 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES, lcmessages);
2128 if (rc)
2129 goto done;
2132 if (show_status)
2134 rc = pwmd_setopt (pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
2135 if (rc)
2136 goto done;
2139 if (filename)
2141 rc = open_command (filename);
2142 if (rc)
2143 goto done;
2146 #ifdef HAVE_LIBREADLINE
2147 if (interactive)
2149 rc = do_interactive ();
2150 result = NULL;
2151 goto do_exit;
2153 #endif
2155 if (inquire)
2157 struct inquire_s *inq = NULL;
2159 rc = set_inquire (inquirefd, inquire_line, &inq);
2160 if (!rc)
2161 rc = pwmd_command (pwm, &result, &len, inquire_cb, inq, "%s", inquire);
2163 free_inquire (inq);
2164 goto done;
2167 if (fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1)
2169 rc = gpg_error_from_errno (errno);
2170 goto done;
2173 ssize_t n;
2175 for (;;)
2177 rc = process_cmd ();
2179 if (rc)
2180 goto done;
2182 n = read (STDIN_FILENO, command, sizeof (command)-1);
2183 if (n == -1)
2185 if (errno == EAGAIN)
2187 usleep (100000);
2188 continue;
2191 rc = gpg_error_from_errno (errno);
2192 goto done;
2194 else if (!n)
2195 goto done;
2197 p = command;
2198 command[n] = 0;
2199 break;
2202 if (!p || !*p || !strcasecmp (p, "BYE"))
2203 goto done;
2206 struct inquire_s *inq = NULL;
2207 rc = set_inquire (inquirefd, inquire_line, &inq);
2208 if (!rc)
2210 rc = parse_dotcommand (command, &result, &len, inq);
2211 free_inquire (inq);
2214 if (rc)
2215 goto done;
2217 done:
2218 if (result)
2220 fwrite (result, 1, result[len - 1] == 0 ? len - 1 : len, outfp);
2221 fflush (outfp);
2222 pwmd_free (result);
2225 result = NULL;
2226 if (!rc)
2227 rc = finalize ();
2228 else if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
2229 (void) pwmd_command (pwm, &result, NULL, NULL, NULL,
2230 "GETINFO last_error");
2232 #ifdef HAVE_LIBREADLINE
2233 do_exit:
2234 #endif
2235 memset (command, 0, sizeof (command));
2237 if (rc && !quiet)
2238 show_error (pwm, rc, result);
2240 pwmd_close (pwm);
2241 reset_keyfiles ();
2242 pwmd_deinit ();
2243 pwmd_free (result);
2244 pwmd_free (filename);
2245 parse_status_ignore (NULL);
2246 if (connected && !quiet)
2247 fprintf (stderr, N_("Connection closed.\n"));
2249 exit (rc ? EXIT_FAILURE : EXIT_SUCCESS);