pwmd_getpin: Handle PWMD_PINENTRY_CONFIRM.
[libpwmd.git] / src / pwmc.c
blob446156f782d770cbed781b8ee81a243094e42664
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);
128 static void
129 show_error (pwm_t *pwm, gpg_error_t rc, const char *str)
131 #ifdef WITH_GNUTLS
132 const char *tlsstr;
133 int e = pwmd_gnutls_error (pwm, &tlsstr);
135 if (e)
136 fprintf(stderr, "TLS: %s\n", tlsstr);
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;
342 int local;
344 /* Try to use the local pinentry between inquires (new/sign/passphrase).
345 * If --no-pinentry was specified then the passphrase is read from the
346 * terminal as usual. */
347 pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local);
348 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, 1);
349 rc = pwmd_password (pwm, keyword, &tmp, &inq->len);
350 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local);
351 if (rc && gpg_err_code (rc) != GPG_ERR_EOF)
352 return rc;
354 pwmd_free (inq->line);
355 inq->line = tmp;
356 *data = inq->line;
357 *size = inq->len;
358 return gpg_error (GPG_ERR_EOF);
360 else if ((is_newpassword && new_keyfile) || (is_password && keyfile)
361 || (sign && sign_keyfile))
363 int fd;
365 if (sign)
366 fd = open (sign_keyfile, O_RDONLY);
367 else
368 fd = open (is_password || sign ? keyfile : new_keyfile, O_RDONLY);
370 if (fd == -1)
372 if (sign)
373 fprintf (stderr, "%s: %s\n", sign_keyfile, strerror (errno));
374 else
375 fprintf (stderr, "%s: %s\n", is_newpassword ? new_keyfile
376 : keyfile, strerror (errno));
377 return gpg_error_from_syserror ();
380 rc = set_inquire (fd, NULL, &inq);
381 if (rc)
383 close (fd);
384 return rc;
387 if (!quiet)
388 fprintf (stderr, N_("Using keyfile '%s' as %s.\n"),
389 sign ? sign_keyfile : is_newpassword ? new_keyfile
390 : keyfile, keyword);
392 #ifdef HAVE_LIBREADLINE
393 else if ((!inq->last_keyword || strcmp (keyword, inq->last_keyword))
394 && interactive)
396 fprintf (stderr,
398 ("%sPress CTRL-D to send the current line. Press twice to end. %s:\n"),
399 inq->last_keyword ? "\n" : "", keyword);
400 pwmd_free (inq->last_keyword);
401 inq->last_keyword = pwmd_strdup (keyword);
403 #endif
405 /* The first part of the command data. */
406 if (inq->len)
408 *data = inq->line;
409 *size = inq->len;
410 inq->len = 0;
411 return inq->fd == -1 ? gpg_error (GPG_ERR_EOF) : 0;
414 *size = read (inq->fd, inq->line, ASSUAN_LINELENGTH);
415 if (*size == -1)
417 *size = 0;
418 return gpg_error (gpg_error_from_syserror ());
420 else if (*size)
421 *data = inq->line;
422 else if (inq->fd != STDIN_FILENO &&
423 (is_newpassword || is_password || sign || is_keyparam))
425 *inq->line = 0;
426 inq->size = 1;
427 *data = inq->line;
428 *size = 1;
431 if (((is_newpassword && new_keyfile) || (is_password && keyfile)
432 || (sign && sign_keyfile) || (keyparams && is_keyparam))
433 && *size == inq->size)
434 return gpg_error (GPG_ERR_EOF);
436 return *size ? 0 : gpg_error (GPG_ERR_EOF);
439 static int
440 status_msg_cb (void *data, const char *line)
442 char *p = strchr (line, ' ');
443 char **s;
445 /* Ignore status messages specified by the client via --status-ignore. */
446 for (s = status_ignore; s && *s; s++)
448 char *tmp = strchr (line, ' ');
449 size_t len = tmp ? strlen (line) - strlen (tmp) : strlen (line);
451 if (!strncmp (line, *s, len) && len == strlen (*s))
452 return 0;
455 if (interactive && !strncmp (line, "XFER ", 5) && *line != '#' && p
456 && strchr (p, ' ') && *++p)
458 char *p1 = strchr (p, ' ');
459 int a = strtol (p, NULL, 10);
461 if (isdigit (*p) && p1)
463 int b = strtol (p1, NULL, 10);
464 char l[64] = { 0 };
465 int t = a && b ? a * 100 / b : 0;
467 strncpy (l, line, strlen (line) - strlen (p) - 1);
468 fprintf (statusfp, "\rS:%s %i/%i %i%%%s", l, a, b, t,
469 a == b ? "\n" : "");
470 fflush (statusfp);
471 return 0;
475 fprintf (statusfp, "S:%s\n", line);
476 fflush (statusfp);
477 #ifdef HAVE_LIBREADLINE
478 rl_on_new_line ();
479 #endif
480 return 0;
483 static gpg_error_t
484 process_cmd ()
486 return pwmd_process (pwm);
489 #ifdef WITH_SSH
490 static gpg_error_t
491 knownhost_cb (void *data, const char *host, const char *key, size_t len)
493 gpg_error_t rc = 0;
494 char *buf =
495 pwmd_strdup_printf (N_
496 ("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?\n"),
497 (char *) data, host, host);
499 if (no_pinentry && !isatty (STDIN_FILENO))
501 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
502 pwmd_free (buf);
503 return GPG_ERR_ENOTTY;
505 else if (no_pinentry)
507 for (char *p = buf, len = 0; *p; p++, len++)
509 if (*p == '\n')
510 len = 0;
512 if (len == 78)
514 char *t = p;
516 while (len && !isspace (*(--p)))
517 len--;
519 if (len)
520 *p = '\n';
521 len = 78 - len;
522 p = t;
525 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_PROMPT, N_("Accept [y/N]:"));
528 if (!rc)
529 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, buf);
531 pwmd_free (buf);
532 if (rc)
533 return rc;
535 return pwmd_getpin (pwm, NULL, NULL, NULL, PWMD_PINENTRY_CONFIRM);
537 #endif
539 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
540 static pwmd_socket_t
541 is_remote_url (const char *str)
543 if (!str)
544 return PWMD_SOCKET_LOCAL;
546 #ifdef WITH_SSH
547 if (strstr (str, "ssh://") || strstr (str, "ssh4://")
548 || strstr (str, "ssh6://"))
549 return PWMD_SOCKET_SSH;
550 #endif
552 #ifdef WITH_GNUTLS
553 if (strstr (str, "tls://") || strstr (str, "tls4://")
554 || strstr (str, "tls6://"))
555 return PWMD_SOCKET_TLS;
556 #endif
558 return PWMD_SOCKET_LOCAL;
560 #endif
562 static char *
563 escape (const char *str)
565 const char *p;
566 char *buf = pwmd_malloc (ASSUAN_LINELENGTH + 1), *b = buf;
567 size_t len = 0;
569 for (p = str; *p; p++, len++)
571 if (len == ASSUAN_LINELENGTH)
572 break;
574 if (*p == '\\')
576 switch (*++p)
578 case 't':
579 *b++ = '\t';
580 break;
581 case 'n':
582 *b++ = '\n';
583 break;
584 case 'v':
585 *b++ = '\v';
586 break;
587 case 'b':
588 *b++ = '\b';
589 break;
590 case 'f':
591 *b++ = '\f';
592 break;
593 case 'r':
594 *b++ = '\r';
595 break;
596 default:
597 *b++ = *p;
598 break;
601 if (!*p)
602 break;
604 continue;
607 *b++ = *p;
610 *b = 0;
611 return buf;
614 static void
615 free_inquire (struct inquire_s *inq)
617 if (!inq)
618 return;
620 pwmd_free (inq->line);
622 if (inq->fd != -1 && inq->fd != STDIN_FILENO)
623 close (inq->fd);
625 pwmd_free (inq->last_keyword);
626 pwmd_free (inq);
629 /* When *result is not NULL it is updated to the new values and not
630 * reallocated. */
631 static gpg_error_t
632 set_inquire (int fd, const char *line, struct inquire_s **result)
634 struct inquire_s inq = { 0 };
635 struct stat st = { 0 };
636 gpg_error_t rc;
638 if (fd != -1)
640 if (fstat (fd, &st) == -1)
641 return gpg_error_from_syserror ();
643 inq.size = st.st_size;
646 inq.fd = fd;
647 inq.line = pwmd_calloc (1, ASSUAN_LINELENGTH);
648 if (!inq.line)
649 return GPG_ERR_ENOMEM;
651 if (line)
653 char *s = escape (line);
655 if (!s)
657 pwmd_free (inq.line);
658 return GPG_ERR_ENOMEM;
661 if (strlen (s) >= ASSUAN_LINELENGTH)
663 pwmd_free (inq.line);
664 pwmd_free (s);
665 return GPG_ERR_LINE_TOO_LONG;
668 strncpy (inq.line, s, ASSUAN_LINELENGTH - 1);
669 inq.len = strlen (s);
670 pwmd_free (s);
673 rc = pwmd_setopt (pwm, PWMD_OPTION_INQUIRE_TOTAL,
674 st.st_size ? st.st_size + strlen (inq.line) : 0);
675 if (rc)
677 pwmd_free (inq.line);
678 return rc;
681 if (*result == NULL)
682 *result = pwmd_malloc (sizeof (struct inquire_s));
683 else
685 if ((*result)->fd != -1 && (*result)->fd != STDIN_FILENO)
686 close ((*result)->fd);
688 pwmd_free ((*result)->line);
689 (*result)->line = NULL;
690 (*result)->fd = -1;
691 (*result)->len = 0;
694 memcpy (*result, &inq, sizeof (struct inquire_s));
695 memset (&inq, 0, sizeof (struct inquire_s));
696 return rc;
699 #ifdef HAVE_LIBREADLINE
700 static int
701 interactive_hook (void)
703 interactive_error = process_cmd ();
705 if (interactive_error)
706 rl_event_hook = NULL;
708 return 0;
711 static int
712 get_readline_char (FILE *fp)
714 if (rl_line_buffer
715 && (!strncmp (rl_line_buffer, ".set passphrase-file ", 16)
716 || !strncmp (rl_line_buffer, ".set new-passphrase-file ", 20)
717 || !strncmp (rl_line_buffer, ".set sign-passphrase-file ", 21)))
718 rl_inhibit_completion = 0;
719 else if (rl_line_buffer
720 && !strncmp (rl_line_buffer, ".redir ", 7))
722 char *p = strchr (rl_line_buffer, ' ');
724 if (strchr (++p, ' '))
725 rl_inhibit_completion = 1;
726 else
727 rl_inhibit_completion = 0;
729 else if (rl_line_buffer
730 && !strncmp (rl_line_buffer, ".read ", 6))
732 char *p = rl_line_buffer + 6;
734 if (strstr (p, "--prefix "))
736 p = strstr (p, "--prefix ");
737 p += 9;
738 p = strchr (p, ' ');
739 if (p)
740 p++;
743 if (!p || strchr (p, ' '))
744 rl_inhibit_completion = 1;
745 else
746 rl_inhibit_completion = 0;
748 else
749 rl_inhibit_completion = 1;
751 return fgetc (fp);
754 static void
755 print_help ()
757 fprintf (stderr,
759 ("------------------------------------------------------------\n"
760 "Elements are TAB delimited. Type HELP for protocol commands.\n"
761 "Type .help for pwmc commands. Press CTRL-D to quit.\n"
762 "------------------------------------------------------------\n"));
764 #endif
766 static char *
767 parse_arg (const char *src, char *dst, size_t len)
769 char *p = dst;
770 const char *s = src;
771 size_t n = 0;
773 for (; s && *s && *s != ' ' && n < len; s++, n++)
774 *p++ = *s;
776 *p = 0;
777 return dst;
780 static char *
781 parse_opt (char **line, const char *opt, gpg_error_t * rc)
783 static char result[ASSUAN_LINELENGTH] = { 0 }, *r = result;
784 char *s = strstr (*line, opt);
786 *rc = 0;
787 result[0] = 0;
788 r = result;
790 if (s)
792 size_t len = 0;
793 int quote = 0;
794 size_t rlen = strlen (opt);
795 char *p = s + rlen;
796 int lastc = 0;
798 while (*p && *p == ' ')
800 rlen++;
801 p++;
804 for (; *p && len < sizeof (result) - 1; p++, rlen++)
806 if (isspace (*p) && !quote)
807 break;
809 if (*p == '\"' && lastc != '\\')
811 quote = !quote;
812 lastc = *p;
813 continue;
816 *r++ = lastc = *p;
817 len++;
820 *r = 0;
822 if (len >= sizeof (result) - 1)
823 *rc = GPG_ERR_LINE_TOO_LONG;
824 else
826 p = s + rlen;
828 while (*p && *p == ' ')
829 p++;
831 *line = p;
835 return result;
838 static gpg_error_t
839 read_command (const char *line, char **result, size_t * len)
841 int fd;
842 gpg_error_t rc = 0;
843 char *file = NULL;
844 struct inquire_s *inq = NULL;
845 char *p = (char *) line;
846 const char *prefix = parse_opt (&p, "--prefix", &rc);
847 char filebuf[ASSUAN_LINELENGTH];
849 if (rc)
850 return rc;
852 rc = GPG_ERR_SYNTAX;
854 if (p && *p)
856 while (*p && isspace (*p))
857 p++;
859 file = parse_arg (p, filebuf, sizeof (filebuf));
860 if (file && *file)
862 p += strlen (file) + 1;
864 while (*p && isspace (*p))
865 p++;
867 if (*p)
868 rc = 0;
872 if (rc)
874 fprintf (stderr,
876 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
877 fprintf (stderr,
879 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\\ = \\)\n"));
880 return rc;
883 fd = open (file, O_RDONLY);
884 if (fd == -1)
885 return gpg_error_from_syserror ();
887 rc = set_inquire (fd, prefix && *prefix ? prefix : NULL, &inq);
888 if (rc)
890 close (fd);
891 return rc;
894 rc = pwmd_command (pwm, result, len, inquire_cb, inq, "%s", p);
895 free_inquire (inq);
896 return rc;
899 static gpg_error_t
900 redir_command (const char *line)
902 const char *p = line;
903 int fd;
904 gpg_error_t rc = GPG_ERR_SYNTAX;
905 char *file = NULL;
906 struct inquire_s *inq = NULL;
907 char *result = NULL;
908 size_t len = 0;
909 char filebuf[ASSUAN_LINELENGTH];
911 if (p && *p && *++p)
913 file = parse_arg (p, filebuf, sizeof (filebuf));
914 if (file && *file)
916 p += strlen (file) + 1;
918 while (*p && isspace (*p))
919 p++;
921 if (*p)
922 rc = 0;
926 if (rc)
928 fprintf (stderr, N_("Usage: .redir <filename> <command> [args]\n"));
929 return rc;
932 fd = open (file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
933 if (fd == -1)
934 return gpg_error_from_syserror ();
936 #ifdef HAVE_LIBREADLINE
937 rc = set_inquire (interactive ? STDIN_FILENO : inquirefd, NULL, &inq);
938 #else
939 rc = set_inquire (inquirefd, NULL, &inq);
940 #endif
941 if (rc)
943 close (fd);
944 return rc;
947 rc = parse_dotcommand (p, &result, &len, inq);
948 if (!rc && result && len--)
949 { // null byte which is always appended
950 if (write (fd, result, len) != len)
951 rc = GPG_ERR_TOO_SHORT;
952 pwmd_free (result);
955 free_inquire (inq);
956 close (fd);
957 return rc;
960 static gpg_error_t
961 help_command (const char *line)
963 fprintf (stderr,
964 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
965 " .redir <filename> <command>\n"
966 " redirect the output of a command to the specified file\n"
967 "\n"
968 " .open <filename>\n"
969 " open the specified filename losing any changes to the current one\n"
970 "\n"
971 " .read [--prefix <string>] <filename> <command> [args]\n"
972 " obtain data from the specified filename for an inquire command\n"
973 "\n"
974 " .set help | <name> [<value>]\n"
975 " set option <name> to <value>\n"
976 "\n"
977 " .save [args]\n"
978 " write changes of the file to disk\n"
979 "\n"
980 " .passwd [args]\n"
981 " change the passphrase of a data file\n"
982 "\n"
983 " .help\n"
984 " this help text\n"));
985 return 0;
988 static gpg_error_t
989 open_command (char *line)
991 struct inquire_s *inq = NULL;
992 const char *file = line;
993 gpg_error_t rc;
994 int local;
996 while (file && isspace (*file))
997 file++;
999 if (!file || !*file)
1001 fprintf (stderr, N_("Usage: .open <filename>\n"));
1002 return GPG_ERR_SYNTAX;
1005 #ifdef HAVE_LIBREADLINE
1006 if (interactive || !quiet)
1007 #else
1008 if (!quiet)
1009 #endif
1010 fprintf (stderr, N_("Opening data file \"%s\" ...\n"), file);
1012 #ifdef HAVE_LIBREADLINE
1013 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1014 #else
1015 rc = set_inquire (-1, NULL, &inq);
1016 #endif
1017 if (rc)
1018 return rc;
1020 pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local);
1022 if (keyfile)
1024 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1025 if (!rc)
1026 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, 1);
1028 else
1029 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1031 if (!rc)
1032 rc = pwmd_open (pwm, file, inquire_cb, inq);
1034 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local);
1036 #ifdef HAVE_LIBREADLINE
1037 if (interactive)
1038 reset_keyfiles ();
1039 #endif
1041 free_inquire (inq);
1042 if (!rc && file != filename)
1044 pwmd_free (filename);
1045 filename = pwmd_strdup (file);
1048 return rc;
1051 static gpg_error_t
1052 set_command (const char *line)
1054 gpg_error_t rc = 0;
1055 char name[256] = { 0 };
1056 char value[512] = { 0 };
1057 char *namep;
1058 char *valuep;
1059 const char *p = line;
1061 while (p && *p && isspace (*p))
1062 p++;
1064 namep = parse_arg (p, name, sizeof (name));
1065 if (!namep || !*namep)
1067 fprintf (stderr, N_("Usage: .set help | <name> [<value>]\n"));
1068 return GPG_ERR_SYNTAX;
1071 p += strlen (namep);
1072 while (p && *p && isspace (*p))
1073 p++;
1075 valuep = parse_arg (p, value, sizeof (value));
1077 if (!strcmp (name, "passphrase-file") || !strcmp (name, "new-passphrase-file")
1078 || !strcmp (name, "sign-passphrase-file"))
1080 int is_newkeyfile = 1;
1081 int sign = !strcmp (name, "sign-passphrase-file");
1083 if (!strcmp (name, "passphrase-file") || sign)
1084 is_newkeyfile = 0;
1086 if (is_newkeyfile)
1088 pwmd_free (new_keyfile);
1089 new_keyfile = NULL;
1091 else if (sign)
1093 pwmd_free (sign_keyfile);
1094 sign_keyfile = NULL;
1096 else
1098 pwmd_free (keyfile);
1099 keyfile = NULL;
1102 if (!rc && *valuep)
1104 if (is_newkeyfile)
1105 new_keyfile = pwmd_strdup (value);
1106 else if (sign)
1107 sign_keyfile = pwmd_strdup (value);
1108 else
1109 keyfile = pwmd_strdup (value);
1111 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1113 else if (!local_pin && !no_pinentry)
1115 pwmd_socket_t t;
1117 pwmd_socket_type (pwm, &t);
1118 if (t == PWMD_SOCKET_LOCAL)
1119 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1122 else if (!strcmp(name, "pinentry-timeout"))
1124 char *e = NULL;
1125 int n = strtol(valuep, &e, 10);
1127 if (e && *e)
1128 return gpg_error (GPG_ERR_INV_VALUE);
1130 if (!*valuep)
1131 n = DEFAULT_PIN_TIMEOUT;
1133 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, n);
1135 else if (!strcmp (name, "help"))
1137 fprintf (stderr,
1139 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1140 "delimited. When no value is specified the option is unset.\n\n"
1141 "passphrase-file [<filename>]\n"
1142 " set or unset the file to be used when a passphrase is required (*)\n"
1143 "\n"
1144 "new-passphrase-file [<filename>]\n"
1145 " set or unset the file to be used when a new passphrase is required (*)\n"
1146 "\n"
1147 "sign-passphrase-file [<filename>]\n"
1148 " set or unset the file to be used when a passphrase is required for\n"
1149 " signing (symmetric) (*)\n"
1150 "\n"
1151 "pinentry-timeout <seconds>\n"
1152 " the amount of seconds before pinentry gives up waiting for input\n"
1153 "\n"
1154 "* = the next protocol command will unset this value\n"
1157 else
1158 rc = GPG_ERR_UNKNOWN_OPTION;
1160 return rc;
1163 static gpg_error_t
1164 do_save_passwd_command (const char *line, int save)
1166 struct inquire_s *inq = NULL;
1167 gpg_error_t rc;
1168 int local;
1170 #ifdef HAVE_LIBREADLINE
1171 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1172 #else
1173 rc = set_inquire (-1, NULL, &inq);
1174 #endif
1175 if (rc)
1176 return rc;
1178 pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local);
1180 if (new_keyfile || keyfile || sign_keyfile)
1182 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1183 if (!rc)
1184 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, 1);
1186 else
1187 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1189 if (!rc)
1191 if (save)
1192 rc = pwmd_save (pwm, line, inquire_cb, inq);
1193 else
1194 rc = pwmd_passwd (pwm, line, inquire_cb, inq);
1197 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local);
1199 #ifdef HAVE_LIBREADLINE
1200 if (interactive)
1201 reset_keyfiles ();
1202 #endif
1204 free_inquire (inq);
1205 return rc;
1208 static gpg_error_t
1209 save_command (const char *line)
1211 return do_save_passwd_command (line, 1);
1214 static gpg_error_t
1215 parse_dotcommand (const char *line, char **result,
1216 size_t * len, struct inquire_s *inq)
1218 const char *p = line;
1219 gpg_error_t rc = 0;
1221 if (!strncmp (p, ".read", 5))
1222 rc = read_command (p + 5, result, len);
1223 else if (!strncmp (p, ".redir", 6))
1224 rc = redir_command (p + 6);
1225 else if (!strncmp (p, ".help", 5))
1226 rc = help_command (p + 5);
1227 else if (!strncmp (p, ".open", 5))
1228 rc = open_command ((char *)p + 5);
1229 else if (!strncmp (p, ".set", 4))
1230 rc = set_command (p + 4);
1231 else if (!strncmp (p, ".save", 5))
1232 rc = do_save_passwd_command (p + 5, 1);
1233 else if (!strncmp (p, ".passwd", 7))
1234 rc = do_save_passwd_command (p + 7, 0);
1235 else
1237 rc = pwmd_command (pwm, result, len, inquire_cb, inq, "%s", line);
1238 #ifdef HAVE_LIBREADLINE
1239 if (interactive)
1241 #endif
1242 reset_keyfiles ();
1243 #ifdef HAVE_LIBREADLINE
1245 #endif
1248 return FINISH (rc);
1251 #ifdef HAVE_LIBREADLINE
1252 static gpg_error_t
1253 do_interactive ()
1255 gpg_error_t rc;
1256 struct inquire_s *inq = NULL;
1258 rl_initialize ();
1259 rc = process_cmd ();
1260 if (rc)
1261 return rc;
1263 rc = set_inquire (STDIN_FILENO, NULL, &inq);
1264 if (rc)
1265 return rc;
1267 fprintf (stderr,
1268 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1269 print_help ();
1270 rl_event_hook = &interactive_hook;
1271 rl_getc_function = get_readline_char;
1272 rl_set_keyboard_input_timeout (100000);
1274 for (;;)
1276 char *line;
1277 char *result = NULL;
1278 size_t len;
1280 rc = 0;
1281 line = readline ("pwmc> ");
1282 if (interactive_error)
1284 free (line);
1285 rc = interactive_error;
1286 break;
1289 if (!line)
1291 rc = finalize ();
1292 if (!rc)
1293 break;
1295 if (gpg_err_code (rc) != GPG_ERR_CANCELED &&
1296 gpg_err_code (rc) != GPG_ERR_EOF)
1297 fprintf (stderr, "ERR %i: %s\n", rc, gpg_strerror (rc));
1299 continue;
1301 else if (!*line)
1303 free (line);
1304 continue;
1307 #ifdef HAVE_READLINE_HISTORY
1308 add_history (line);
1309 #endif
1310 rc = parse_dotcommand (line, &result, &len, inq);
1311 free (line);
1312 if (rc)
1314 char *tmp = NULL;
1316 if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
1317 (void) pwmd_command (pwm, &tmp, NULL, NULL, NULL,
1318 "GETINFO last_error");
1320 show_error (pwm, rc, tmp);
1321 pwmd_free (tmp);
1323 else if (result && len)
1324 printf ("%s%s", result, result[len - 1] != '\n' ? "\n" : "");
1326 pwmd_free (result);
1329 free_inquire (inq);
1330 return rc;
1332 #endif
1334 static gpg_error_t
1335 finalize ()
1337 gpg_error_t rc = 0;
1338 #ifdef HAVE_LIBREADLINE
1339 int quit = 0;
1341 if (interactive)
1343 int finished = 0;
1345 fprintf (stderr, "\n");
1349 char *p, buf[16];
1351 fprintf (stderr,
1353 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1354 p = fgets (buf, sizeof (buf), stdin);
1356 if (feof (stdin))
1358 clearerr (stdin);
1359 return GPG_ERR_EOF;
1362 switch (*p)
1364 case 'h':
1365 print_help ();
1366 break;
1367 case 'c':
1368 return GPG_ERR_CANCELED;
1369 case 'Q':
1370 return 0;
1371 case 'f':
1372 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1373 "CLEARCACHE %s", filename);
1374 if (rc)
1375 return rc;
1377 interactive_hook ();
1378 break;
1379 case 'S':
1380 quit = 1;
1381 case 's':
1382 save = 1;
1383 finished = 1;
1384 break;
1385 default:
1386 break;
1389 while (!finished);
1391 #endif
1393 if (save && !filename)
1395 fprintf (stderr,
1397 ("No filename was specified on the command line. Aborting.\n"));
1398 return GPG_ERR_CANCELED;
1401 if (save && filename)
1403 char *args =
1404 pwmd_strdup_printf ("%s %s%s %s%s %s",
1405 symmetric ? "--symmetric" : "",
1406 keyid ? "--keyid=" : "",
1407 keyid ? keyid : "",
1408 sign_keyid ? "--sign-keyid=" : "",
1409 sign_keyid ? sign_keyid : "",
1410 keyparams ? "--inquire-keyparam" : "");
1412 #ifdef HAVE_LIBREADLINE
1413 if (!quiet || interactive)
1415 #else
1416 if (!quiet)
1418 #endif
1419 fprintf (stderr, "\n");
1420 fprintf (stderr, N_("Saving changes ...\n"));
1423 rc = save_command (args);
1424 pwmd_free (args);
1427 #ifdef HAVE_LIBREADLINE
1428 if (interactive)
1429 return rc ? rc : quit ? 0 : GPG_ERR_CANCELED;
1430 #endif
1432 return rc;
1435 static void
1436 parse_status_ignore (char *str)
1438 size_t n = 0;
1439 char **p, *s;
1441 for (p = status_ignore; p && *p; p++)
1442 pwmd_free (*p);
1444 pwmd_free (status_ignore);
1445 status_ignore = NULL;
1446 if (!str || !*str)
1447 return;
1449 while ((s = strsep (&str, ",")))
1451 p = pwmd_realloc (status_ignore, (n + 2) * sizeof (char *));
1452 p[n++] = pwmd_strdup (s);
1453 p[n] = NULL;
1454 status_ignore = p;
1459 main (int argc, char *argv[])
1461 int connected = 0;
1462 gpg_error_t rc;
1463 int opt;
1464 char command[ASSUAN_LINELENGTH], *p = NULL;
1465 char *result = NULL;
1466 size_t len = 0;
1467 char *pinentry_path = NULL;
1468 char *display = NULL, *tty = NULL, *ttytype = NULL;
1469 char *lcctype = NULL, *lcmessages = NULL;
1470 int outfd = STDOUT_FILENO;
1471 FILE *outfp = stdout;
1472 FILE *inquirefp = stdin;
1473 int show_status = 1;
1474 char *clientname = "pwmc";
1475 char *inquire = NULL;
1476 char *inquire_line = NULL;
1477 int timeout = 0;
1478 #ifdef WITH_SSH
1479 int use_ssh_agent = 1;
1480 char *knownhosts = NULL;
1481 char *identity = NULL;
1482 #endif
1483 #ifdef WITH_GNUTLS
1484 char *cacert = NULL;
1485 char *clientcert = NULL;
1486 char *clientkey = NULL;
1487 char *prio = NULL;
1488 int tls_verify = 0;
1489 char *tls_fingerprint = NULL;
1490 #endif
1491 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1492 pwmd_socket_t socktype;
1493 long socket_timeout = 300;
1494 int connect_timeout = 120;
1495 int needs_passphrase = 0;
1496 #endif
1497 int lock_on_open = 1;
1498 long lock_timeout = 50;
1499 char *url = NULL;
1500 char *tmp = NULL;
1501 /* The order is important. */
1502 enum
1504 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1505 OPT_SOCKET_TIMEOUT, OPT_CONNECT_TIMEOUT,
1506 #endif
1507 #ifdef WITH_SSH
1508 OPT_USE_SSH_AGENT, OPT_IDENTITY, OPT_KNOWNHOSTS, OPT_SSH_NEEDS_PASSPHRASE,
1509 #endif
1510 #ifdef WITH_GNUTLS
1511 OPT_CACERT, OPT_CLIENTCERT, OPT_CLIENTKEY, OPT_PRIORITY, OPT_VERIFY,
1512 OPT_SERVER_FP,
1513 #endif
1514 OPT_URL, OPT_LOCAL, OPT_TTYNAME, OPT_TTYTYPE, OPT_DISPLAY, OPT_LC_CTYPE,
1515 OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES, OPT_PINENTRY, OPT_KEYFILE,
1516 OPT_PASSPHRASE_FILE, OPT_NEW_KEYFILE, OPT_NEW_PASSPHRASE_FILE,
1517 OPT_SIGN_KEYFILE, OPT_SIGN_PASSPHRASE_FILE, OPT_NOLOCK, OPT_LOCK_TIMEOUT,
1518 OPT_SAVE, OPT_OUTPUT_FD, OPT_INQUIRE, OPT_INQUIRE_FD, OPT_INQUIRE_FILE,
1519 OPT_INQUIRE_LINE, OPT_NO_STATUS, OPT_STATUS_IGNORE, OPT_STATUSFD, OPT_NAME,
1520 OPT_VERSION, OPT_HELP, OPT_KEYID, OPT_SIGN_KEYID, OPT_SYMMETRIC,
1521 OPT_KEYPARAMS, OPT_NO_PINENTRY, OPT_QUIET,
1522 #ifdef HAVE_LIBREADLINE
1523 OPT_INTERACTIVE,
1524 #endif
1526 const struct option long_opts[] = {
1527 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1528 {"socket-timeout", 1, 0, 0},
1529 {"connect-timeout", 1, 0, 0},
1530 #endif
1532 #ifdef WITH_SSH
1533 {"no-ssh-agent", 0, 0, 0},
1534 {"identity", 1, 0, 'i'},
1535 {"knownhosts", 1, 0, 'k'},
1536 {"ssh-needs-passphrase", 0, 0, 0},
1537 #endif
1538 #ifdef WITH_GNUTLS
1539 {"ca-cert", 1, 0, 0},
1540 {"client-cert", 1, 0, 0},
1541 {"client-key", 1, 0, 0},
1542 {"tls-priority", 1, 0, 0},
1543 {"tls-verify", 0, 0, 0},
1544 {"tls-fingerprint", 1, 0, 0},
1545 #endif
1546 {"url", 1, 0, 0},
1547 {"local-pinentry", 0, 0},
1548 {"ttyname", 1, 0, 'y'},
1549 {"ttytype", 1, 0, 't'},
1550 {"display", 1, 0, 'd'},
1551 {"lc-ctype", 1, 0, 0},
1552 {"lc-messages", 1, 0, 0},
1553 {"timeout", 1, 0, 0},
1554 {"tries", 1, 0, 0},
1555 {"pinentry", 1, 0, 0},
1556 {"key-file", 1, 0, 0},
1557 {"passphrase-file", 1, 0, 0},
1558 {"new-key-file", 1, 0, 0},
1559 {"new-passphrase-file", 1, 0, 0},
1560 {"sign-key-file", 1, 0, 0},
1561 {"sign-passphrase-file", 1, 0, 0},
1562 {"no-lock", 0, 0, 0},
1563 {"lock-timeout", 1, 0, 0},
1564 {"save", 0, 0, 'S'},
1565 {"output-fd", 1, 0, 0},
1566 {"inquire", 1, 0, 0},
1567 {"inquire-fd", 1, 0, 0},
1568 {"inquire-file", 1, 0, 0},
1569 {"inquire-line", 1, 0, 'L'},
1570 {"no-status", 0, 0, 0},
1571 {"status-ignore", 1, 0, 0},
1572 {"status-fd", 1, 0, 0},
1573 {"name", 1, 0, 'n'},
1574 {"version", 0, 0, 0},
1575 {"help", 0, 0, 0},
1576 {"keyid", 1, 0, 0},
1577 {"sign-keyid", 1, 0, 0},
1578 {"symmetric", 0, 0, 0},
1579 {"key-params", 1, 0, 0},
1580 {"no-pinentry", 0, 0, 0},
1581 {"quiet", 0, 0, 0},
1582 #ifdef HAVE_LIBREADLINE
1583 {"interactive", 0, 0},
1584 #endif
1585 {0, 0, 0, 0}
1587 #ifdef WITH_SSH
1588 const char *optstring = "L:y:t:d:P:I:Sn:i:k:s";
1589 #else
1590 const char *optstring = "L:y:t:d:P:I:Sn:s";
1591 #endif
1592 int opt_index = 0;
1594 #ifdef ENABLE_NLS
1595 setlocale (LC_ALL, "");
1596 bindtextdomain ("libpwmd", LOCALEDIR);
1597 #endif
1599 tries = DEFAULT_PIN_TRIES;
1600 inquirefd = STDIN_FILENO;
1601 statusfd = STDERR_FILENO;
1602 statusfp = fdopen (statusfd, "w");
1603 tmp = pwmd_strdup (DEFAULT_STATUS_IGNORE);
1604 parse_status_ignore (tmp);
1605 pwmd_free (tmp);
1607 while ((opt =
1608 getopt_long (argc, argv, optstring, long_opts, &opt_index)) != -1)
1610 switch (opt)
1612 /* Handle long options without a short option part. */
1613 case 0:
1614 switch (opt_index)
1616 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1617 case OPT_SOCKET_TIMEOUT:
1618 socket_timeout = strtol (optarg, &p, 10);
1619 break;
1620 case OPT_CONNECT_TIMEOUT:
1621 connect_timeout = strtol (optarg, &p, 10);
1622 break;
1623 #endif
1624 #ifdef WITH_SSH
1625 case OPT_USE_SSH_AGENT:
1626 use_ssh_agent = 0;
1627 break;
1628 case OPT_SSH_NEEDS_PASSPHRASE:
1629 needs_passphrase = 1;
1630 break;
1631 #endif
1632 #ifdef WITH_GNUTLS
1633 case OPT_CACERT:
1634 cacert = optarg;
1635 break;
1636 case OPT_CLIENTCERT:
1637 clientcert = optarg;
1638 break;
1639 case OPT_CLIENTKEY:
1640 clientkey = optarg;
1641 break;
1642 case OPT_PRIORITY:
1643 prio = optarg;
1644 break;
1645 case OPT_VERIFY:
1646 tls_verify = 1;
1647 break;
1648 case OPT_SERVER_FP:
1649 tls_fingerprint = optarg;
1650 break;
1651 #endif
1652 case OPT_SYMMETRIC:
1653 symmetric = 1;
1654 break;
1655 case OPT_KEYPARAMS:
1656 keyparams = optarg;
1657 break;
1658 case OPT_KEYFILE:
1659 case OPT_PASSPHRASE_FILE:
1660 keyfile = pwmd_strdup (optarg);
1661 break;
1662 case OPT_NEW_KEYFILE:
1663 case OPT_NEW_PASSPHRASE_FILE:
1664 new_keyfile = pwmd_strdup (optarg);
1665 break;
1666 case OPT_SIGN_KEYFILE:
1667 case OPT_SIGN_PASSPHRASE_FILE:
1668 sign_keyfile = pwmd_strdup (optarg);
1669 break;
1670 case OPT_NOLOCK:
1671 lock_on_open = 0;
1672 break;
1673 case OPT_LOCK_TIMEOUT:
1674 lock_timeout = strtol (optarg, &p, 10);
1675 break;
1676 case OPT_URL:
1677 url = optarg;
1678 break;
1679 case OPT_LOCAL:
1680 local_pin = 1;
1681 break;
1682 case OPT_LC_CTYPE:
1683 lcctype = pwmd_strdup (optarg);
1684 break;
1685 case OPT_LC_MESSAGES:
1686 lcmessages = pwmd_strdup (optarg);
1687 break;
1688 case OPT_TIMEOUT:
1689 timeout = strtol (optarg, &p, 10);
1690 break;
1691 case OPT_TRIES:
1692 tries = strtol (optarg, &p, 10);
1693 break;
1694 case OPT_INQUIRE:
1695 inquire = escape (optarg);
1696 break;
1697 case OPT_INQUIRE_FD:
1698 inquirefd = strtol (optarg, &p, 10);
1699 if (!p)
1701 inquirefp = fdopen (inquirefd, "r");
1702 if (!inquirefp)
1703 err (EXIT_FAILURE, "%i", inquirefd);
1705 break;
1706 case OPT_INQUIRE_FILE:
1707 inquirefd = open (optarg, O_RDONLY);
1708 if (inquirefd == -1)
1709 err (EXIT_FAILURE, "%s", optarg);
1710 inquirefp = fdopen (inquirefd, "r");
1711 break;
1712 case OPT_OUTPUT_FD:
1713 outfd = strtol (optarg, &p, 10);
1714 if (!p || !*p)
1716 outfp = fdopen (outfd, "w");
1717 if (!outfp)
1718 err (EXIT_FAILURE, "%i", outfd);
1720 break;
1721 case OPT_NO_STATUS:
1722 show_status = 0;
1723 break;
1724 case OPT_STATUSFD:
1725 statusfd = strtol (optarg, &p, 10);
1726 if (!p || !*p)
1728 statusfp = fdopen (statusfd, "w");
1729 if (!statusfp)
1730 err (EXIT_FAILURE, "%i", statusfd);
1732 break;
1733 case OPT_STATUS_IGNORE:
1734 parse_status_ignore (optarg);
1735 break;
1736 case OPT_VERSION:
1737 printf ("%s (pwmc)\n\n"
1738 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016\n"
1739 "%s\n"
1740 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1741 "Compile-time features:\n"
1742 #ifdef HAVE_LIBREADLINE
1743 "+INTERACTIVE "
1744 #else
1745 "-INTERACTIVE "
1746 #endif
1747 #ifdef WITH_SSH
1748 "+SSH "
1749 #else
1750 "-SSH "
1751 #endif
1752 #ifdef WITH_GNUTLS
1753 "+GNUTLS "
1754 #else
1755 "-GNUTLS "
1756 #endif
1757 #ifdef WITH_PINENTRY
1758 "+PINENTRY "
1759 #else
1760 "-PINENTRY "
1761 #endif
1762 #ifdef WITH_QUALITY
1763 "+CRACK "
1764 #else
1765 "-CRACK "
1766 #endif
1767 #ifdef MEM_DEBUG
1768 "+MEM_DEBUG "
1769 #else
1770 "-MEM_DEBUG "
1771 #endif
1772 "\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1773 exit (EXIT_SUCCESS);
1774 case OPT_PINENTRY:
1775 pinentry_path = optarg;
1776 break;
1777 case OPT_HELP:
1778 usage (argv[0], EXIT_SUCCESS);
1779 case OPT_KEYID:
1780 keyid = optarg;
1781 break;
1782 case OPT_SIGN_KEYID:
1783 sign_keyid = optarg;
1784 break;
1785 case OPT_QUIET:
1786 quiet = 1;
1787 show_status = 0;
1788 break;
1789 case OPT_NO_PINENTRY:
1790 no_pinentry = 1;
1791 break;
1792 #ifdef HAVE_LIBREADLINE
1793 case OPT_INTERACTIVE:
1794 interactive = 1;
1795 break;
1796 #endif
1797 default:
1798 usage (argv[0], EXIT_FAILURE);
1801 if (p && *p)
1803 fprintf (stderr, N_("%s: invalid argument for option '--%s'\n"),
1804 argv[0], long_opts[opt_index].name);
1805 usage (argv[0], EXIT_FAILURE);
1808 break;
1809 #ifdef WITH_SSH
1810 case 'i':
1811 identity = optarg;
1812 break;
1813 case 'k':
1814 knownhosts = optarg;
1815 break;
1816 #endif
1817 case 'L':
1818 inquire_line = optarg;
1819 break;
1820 case 'y':
1821 tty = optarg;
1822 break;
1823 case 't':
1824 ttytype = optarg;
1825 break;
1826 case 'd':
1827 display = optarg;
1828 break;
1829 case 'S':
1830 save = 1;
1831 break;
1832 case 'n':
1833 clientname = optarg;
1834 break;
1835 default:
1836 usage (argv[0], EXIT_FAILURE);
1840 #ifdef HAVE_LIBREADLINE
1841 if (interactive && !isatty (STDIN_FILENO))
1842 usage (argv[0], EXIT_FAILURE);
1843 else if (isatty (STDIN_FILENO) && !inquire && !inquire_line)
1844 interactive = 1;
1845 #endif
1847 pwmd_init ();
1848 rc = pwmd_new (clientname, &pwm);
1849 if (rc)
1850 goto done;
1852 filename = argv[optind] ? pwmd_strdup (argv[optind]) : NULL;
1853 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1854 if (rc)
1855 goto done;
1857 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local_pin);
1858 if (rc)
1859 goto done;
1861 pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
1862 if (!quiet)
1863 fprintf (stderr, N_("Connecting ...\n"));
1865 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1866 socktype = is_remote_url (url);
1867 if (socktype != PWMD_SOCKET_LOCAL)
1869 local_pin = 1;
1870 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1871 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, connect_timeout);
1872 if (rc)
1873 goto done;
1874 #endif
1876 if (socktype == PWMD_SOCKET_SSH)
1878 #ifdef WITH_SSH
1879 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_CB, knownhost_cb);
1880 if (rc)
1881 goto done;
1883 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_DATA, clientname);
1884 if (rc)
1885 goto done;
1887 if (!getenv ("SSH_AUTH_SOCK") || identity)
1888 use_ssh_agent = 0;
1890 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_AGENT, use_ssh_agent);
1891 if (rc)
1892 goto done;
1894 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_NEEDS_PASSPHRASE,
1895 needs_passphrase);
1896 if (rc)
1897 goto done;
1899 rc = pwmd_connect (pwm, url, identity, knownhosts);
1900 #endif
1902 #ifdef WITH_GNUTLS
1903 else
1905 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_VERIFY, tls_verify);
1906 if (rc)
1907 goto done;
1909 rc = pwmd_connect (pwm, url, clientcert, clientkey, cacert, prio,
1910 tls_fingerprint);
1912 #endif
1914 else
1915 rc = pwmd_connect (pwm, url);
1916 #else
1917 rc = pwmd_connect (pwm, url);
1918 #endif
1919 if (rc)
1920 goto done;
1922 if (!quiet)
1923 fprintf (stderr, N_("Connected.\n"));
1925 connected = 1;
1926 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1927 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, socket_timeout);
1928 if (rc)
1929 goto done;
1930 #endif
1932 if (lock_timeout)
1934 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1935 "OPTION LOCK-TIMEOUT=%li", lock_timeout);
1936 if (rc)
1937 goto done;
1940 if (lock_on_open)
1942 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCK_ON_OPEN, 1);
1943 if (rc)
1944 goto done;
1947 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, NULL, NULL);
1948 if (rc)
1949 goto done;
1951 if (timeout > 0)
1953 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
1954 if (rc)
1955 goto done;
1958 if (pinentry_path)
1960 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
1961 if (rc)
1962 goto done;
1965 if (display)
1967 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
1968 if (rc)
1969 goto done;
1972 if (tty)
1974 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, tty);
1975 if (rc)
1976 goto done;
1979 if (ttytype)
1981 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
1982 if (rc)
1983 goto done;
1986 if (lcctype)
1988 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
1989 if (rc)
1990 goto done;
1993 if (lcmessages)
1995 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES, lcmessages);
1996 if (rc)
1997 goto done;
2000 if (show_status)
2002 rc = pwmd_setopt (pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
2003 if (rc)
2004 goto done;
2007 if (filename)
2009 rc = open_command (filename);
2010 if (rc)
2011 goto done;
2014 #ifdef HAVE_LIBREADLINE
2015 if (interactive)
2017 rc = do_interactive ();
2018 result = NULL;
2019 goto do_exit;
2021 #endif
2023 if (inquire)
2025 struct inquire_s *inq = NULL;
2027 rc = set_inquire (inquirefd, inquire_line, &inq);
2028 if (!rc)
2029 rc = pwmd_command (pwm, &result, &len, inquire_cb, inq, "%s", inquire);
2031 free_inquire (inq);
2032 goto done;
2035 if (fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1)
2037 rc = gpg_error_from_errno (errno);
2038 goto done;
2041 ssize_t n;
2043 for (;;)
2045 rc = process_cmd ();
2047 if (rc)
2048 goto done;
2050 n = read (STDIN_FILENO, command, sizeof (command)-1);
2051 if (n == -1)
2053 if (errno == EAGAIN)
2055 usleep (100000);
2056 continue;
2059 rc = gpg_error_from_errno (errno);
2060 goto done;
2062 else if (!n)
2063 goto done;
2065 p = command;
2066 command[n] = 0;
2067 break;
2070 if (!p || !*p || !strcasecmp (p, "BYE"))
2071 goto done;
2074 struct inquire_s *inq = NULL;
2075 rc = set_inquire (inquirefd, inquire_line, &inq);
2076 if (!rc)
2078 rc = parse_dotcommand (command, &result, &len, inq);
2079 free_inquire (inq);
2082 if (rc)
2083 goto done;
2085 done:
2086 if (result)
2088 fwrite (result, 1, result[len - 1] == 0 ? len - 1 : len, outfp);
2089 fflush (outfp);
2090 pwmd_free (result);
2093 result = NULL;
2094 if (!rc)
2095 rc = finalize ();
2096 else if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
2097 (void) pwmd_command (pwm, &result, NULL, NULL, NULL,
2098 "GETINFO last_error");
2100 #ifdef HAVE_LIBREADLINE
2101 do_exit:
2102 #endif
2103 wipememory (command, 0, sizeof (command));
2105 if (rc && !quiet)
2106 show_error (pwm, rc, result);
2108 pwmd_close (pwm);
2109 reset_keyfiles ();
2110 pwmd_deinit ();
2111 pwmd_free (result);
2112 pwmd_free (filename);
2113 parse_status_ignore (NULL);
2114 if (connected && !quiet)
2115 fprintf (stderr, N_("Connection closed.\n"));
2117 exit (rc ? EXIT_FAILURE : EXIT_SUCCESS);