Add pwmd_gnutls_error().
[libpwmd.git] / src / pwmc.c
blobc7490eab1b2a60de1315bbcba6e963db23200fe1
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015,
3 2016
4 Ben Kibbey <bjk@luxsci.net>
6 This file is part of libpwmd.
8 Libpwmd is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
13 Libpwmd is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Libpwmd. If not, see <http://www.gnu.org/licenses/>.
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <stdint.h>
29 #include <err.h>
30 #include <errno.h>
31 #include <string.h>
32 #include <libpwmd.h>
33 #include <assuan.h>
34 #include <sys/select.h>
35 #include <fcntl.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <libgen.h>
39 #include <termios.h>
40 #include <limits.h>
41 #include <ctype.h>
43 #ifdef WITH_GNUTLS
44 #include <gnutls/gnutls.h>
45 #endif
47 #ifdef HAVE_LOCALE_H
48 #include <locale.h>
49 #endif
51 #ifdef HAVE_GETOPT_LONG
52 #ifdef HAVE_GETOPT_H
53 #include <getopt.h>
54 #endif
55 #else
56 #include "getopt_long.h"
57 #endif
59 #ifdef HAVE_LIBREADLINE
60 #if defined(HAVE_READLINE_READLINE_H)
61 #include <readline/readline.h>
62 #elif defined(HAVE_READLINE_H)
63 #include <readline.h>
64 #endif /* !defined(HAVE_READLINE_H) */
65 static int interactive_error;
66 static int interactive;
67 #endif /* HAVE_LIBREADLINE */
69 #ifdef HAVE_READLINE_HISTORY
70 #if defined(HAVE_READLINE_HISTORY_H)
71 #include <readline/history.h>
72 #elif defined(HAVE_HISTORY_H)
73 #include <history.h>
74 #endif
75 #endif /* HAVE_READLINE_HISTORY */
77 #ifndef LINE_MAX
78 #define LINE_MAX 2048
79 #endif
81 #include "gettext.h"
82 #define N_(msgid) gettext(msgid)
84 #include "mem.h"
87 #define DEFAULT_STATUS_IGNORE "KEEPALIVE,STATE,GPGME,PASSPHRASE_INFO,PASSPHRASE_HINT"
88 #define DEFAULT_PIN_TIMEOUT 30
89 #define DEFAULT_PIN_TRIES 3
90 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
91 ? gpg_error(rc) : rc
93 static int no_pinentry;
94 static pwm_t *pwm;
95 static char *filename;
96 static int save;
97 static char *keyid;
98 static char *sign_keyid;
99 static int symmetric;
100 static char *keyparams;
101 static char *keyfile;
102 static char *new_keyfile;
103 static char *sign_keyfile;
104 static int tries;
105 static int local_pin;
106 static int inquirefd;
107 static int statusfd;
108 FILE *statusfp;
109 static int quiet;
110 static char **status_ignore;
112 struct inquire_s
114 int fd;
115 char *line;
116 size_t len;
117 size_t size; // from stat(2).
118 char *last_keyword;
121 static gpg_error_t finalize ();
122 static gpg_error_t set_inquire (int fd, const char *line,
123 struct inquire_s **result);
124 static gpg_error_t parse_dotcommand (const char *line, char **result,
125 size_t * len, struct inquire_s *inq);
126 static gpg_error_t open_command (char *line);
127 #ifdef WITH_SSH
128 static gpg_error_t get_password (char **result, pwmd_pinentry_t w, int echo);
129 #endif
131 static void
132 show_error (pwm_t *pwm, gpg_error_t rc, const char *str)
134 #ifdef WITH_GNUTLS
135 const char *tlsstr;
136 int e = pwmd_gnutls_error (pwm, &tlsstr);
138 if (e)
139 fprintf(stderr, "TLS: %s\n", tlsstr);
140 #endif
141 fprintf (stderr, "ERR %i: %s%s%s%s", rc, gpg_strerror (rc),
142 str ? ": " : "", str ? str : "", str ? "" : "\n");
145 static void
146 reset_keyfiles ()
148 pwmd_free (keyfile);
149 pwmd_free (new_keyfile);
150 pwmd_free (sign_keyfile);
151 keyfile = new_keyfile = sign_keyfile = NULL;
154 static void
155 usage (const char *pn, int status)
157 fprintf (status == EXIT_FAILURE ? stderr : stdout,
158 N_("Usage: pwmc [options] [file]\n"
159 " --url <string>\n"
160 " a url string to connect to (%s, see below)\n"
161 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
162 " --connect-timeout <seconds>\n"
163 " seconds before connecting to a remote host fails (0=disabled, 120)\n"
164 " --socket-timeout <seconds>\n"
165 " seconds before a remote command fails (0=disabled, 300)\n"
166 #endif
167 #ifdef WITH_GNUTLS
168 " --ca-cert <filename>\n"
169 " certificate authority (CA) used to sign the server cert\n"
170 " --client-cert <filename>\n"
171 " client certificate to use for authentication\n"
172 " --client-key <filename>\n"
173 " key file used to protect the client certificate\n"
174 " --tls-priority <string>\n"
175 " compression, cipher and hash algorithm string\n"
176 " (SECURE256:SECURE192:SECURE128:-VERS-SSL3.0)\n"
177 " --tls-verify\n"
178 " verify the hostname against the server certificate\n"
179 " --tls-fingerprint <string>\n"
180 " a SHA-256 hash of the server fingerprint to verify against\n"
181 #endif
182 #ifdef WITH_SSH
183 " --no-ssh-agent\n"
184 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
185 " --identity, -i <filename>\n"
186 " the ssh identity file to use for authentication\n"
187 " --knownhosts, -k <filename>\n"
188 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
189 " --ssh-needs-passphrase\n"
190 " prompt for a passphrase for the SSH identity file\n"
191 #endif
192 " --no-lock\n"
193 " do not lock the data file upon opening it\n"
194 " --lock-timeout <N>\n"
195 " time in tenths of a second to wait for a locked data file (50)\n"
196 " --name, -n <string>\n"
197 " set the client name\n"
198 " --pinentry <path>\n"
199 " the full path to the pinentry binary\n"
200 " --local-pinentry\n"
201 " force using a local pinentry\n"
202 " --no-pinentry\n"
203 " disable pinentry both remotely and locally\n"
204 " --ttyname, -y <path>\n"
205 " tty that pinentry will use\n"
206 " --ttytype, -t <string>\n"
207 " pinentry terminal type (default is $TERM)\n"
208 " --display, -d\n"
209 " pinentry display (default is $DISPLAY)\n"
210 " --lc-ctype <string>\n"
211 " locale setting for pinentry\n"
212 " --lc-messages <string>\n"
213 " locale setting for pinentry\n"
214 " --tries <N>\n"
215 " number of pinentry tries before failing (3)\n"
216 " --timeout <seconds>\n"
217 " pinentry timeout\n"
218 " --inquire <COMMAND>\n"
219 " the specified command (with any options) uses a server inquire while\n"
220 " command data is read via the inquire file descriptor (stdin)\n"
221 " --inquire-line, -L <STRING>\n"
222 " the initial line to send (i.e., element path) before the inquire data\n"
223 " --inquire-fd <FD>\n"
224 " read inquire data from the specified file descriptor (stdin)\n"
225 " --inquire-file <filename>\n"
226 " read inquire data from the specified filename\n"
227 " --output-fd <FD>\n"
228 " redirect command output to the specified file descriptor\n"
229 " --save, -S\n"
230 " send the SAVE command before exiting\n"
231 " --passphrase-file <filename>\n"
232 " obtain the passphrase from the specified filename\n"
233 " --new-passphrase-file <filename>\n"
234 " obtain the passphrase to save with from the specified filename\n"
235 " --sign-passphrase-file <filename>\n"
236 " obtain the passphrase to sign with (symmetric) from the specified filename\n"
237 " --key-params <filename>\n"
238 " key parameters to use for key generation (pwmd default)\n"
239 " --keyid <recipient>[,<recipient>]\n"
240 " the public key ID to u\n"
241 " --sign-keyid <string>\n"
242 " the key ID to sign the data file with\n"
243 " --symmetric\n"
244 " use conventional encryption with optional signer(s) for new files\n"
245 " --no-status\n"
246 " disable showing of status messages from the server\n"
247 " --status-fd <FD>\n"
248 " redirect status messages to the specified file descriptor\n"
249 " --status-ignore <string[,...]>\n"
250 " prevent parsing of the specified status message keywords\n"
251 " --quiet\n"
252 " disable showing of extra messages (implies --no-status)\n"
253 #ifdef HAVE_LIBREADLINE
254 " --interactive\n"
255 " use a shell like interface to pwmd (allows more than one command)\n"
256 #endif
257 " --version\n"
258 " --help\n"),
259 #ifdef DEFAULT_PWMD_SOCKET
260 DEFAULT_PWMD_SOCKET
261 #else
262 "~/.pwmd/socket"
263 #endif
265 fprintf (status == EXIT_FAILURE ? stderr : stdout,
266 N_("\n"
267 "An optional url may be in the form of:\n"
268 " --url /path/to/socket\n"
269 " --url file://[path/to/socket]\n"
270 #ifdef WITH_SSH
271 " or\n"
272 " --url ssh[46]://[username@]hostname[:port]\n"
273 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
274 #endif
275 #ifdef WITH_GNUTLS
276 " or\n"
277 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
278 " --client-key filename\n"
279 #endif
280 #ifdef HAVE_LIBREADLINE
281 "\n"
282 "Interactive mode is used when input is from a terminal.\n"
283 #endif
285 exit (status);
288 static gpg_error_t
289 inquire_cb (void *user, const char *keyword, gpg_error_t rc,
290 char **data, size_t * size)
292 struct inquire_s *inq = user;
293 int is_password = 0;
294 int is_newpassword = 0;
295 int sign = 0;
296 int is_keyparam = 0;
298 *data = NULL;
299 *size = 0;
301 if (rc)
302 return rc;
304 if (!strcmp (keyword, "PASSPHRASE"))
305 is_password = 1;
306 else if (!strcmp (keyword, "SIGN_PASSPHRASE"))
307 sign = 1;
308 else if (!strcmp (keyword, "NEW_PASSPHRASE"))
309 is_newpassword = 1;
310 #ifdef HAVE_LIBREADLINE
311 else if (!strcmp (keyword, "KEYPARAM") && !interactive)
313 #else
314 else if (!strcmp (keyword, "KEYPARAM"))
316 #endif
317 int fd;
318 if (!keyparams || !*keyparams)
319 return gpg_error (GPG_ERR_INV_PARAMETER);
321 fd = open (keyparams, O_RDONLY);
322 if (fd == -1)
324 fprintf (stderr, "%s: %s\n", keyparams, strerror (errno));
325 return gpg_error_from_syserror ();
328 rc = set_inquire (fd, NULL, &inq);
329 if (rc)
331 close (fd);
332 return rc;
335 if (!quiet)
336 fprintf (stderr, N_("Using file '%s' as %s.\n"), keyparams, keyword);
338 is_keyparam = 1;
341 if ((is_password && !keyfile) || (is_newpassword && !new_keyfile)
342 || (sign && !sign_keyfile))
344 char *tmp;
345 int local;
347 /* Try to use the local pinentry between inquires (new/sign/passphrase).
348 * If --no-pinentry was specified then the passphrase is read from the
349 * terminal as usual. */
350 pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local);
351 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, 1);
352 rc = pwmd_password (pwm, keyword, &tmp, &inq->len);
353 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local);
354 if (rc && gpg_err_code (rc) != GPG_ERR_EOF)
355 return rc;
357 pwmd_free (inq->line);
358 inq->line = tmp;
359 *data = inq->line;
360 *size = inq->len;
361 return gpg_error (GPG_ERR_EOF);
363 else if ((is_newpassword && new_keyfile) || (is_password && keyfile)
364 || (sign && sign_keyfile))
366 int fd;
368 if (sign)
369 fd = open (sign_keyfile, O_RDONLY);
370 else
371 fd = open (is_password || sign ? keyfile : new_keyfile, O_RDONLY);
373 if (fd == -1)
375 if (sign)
376 fprintf (stderr, "%s: %s\n", sign_keyfile, strerror (errno));
377 else
378 fprintf (stderr, "%s: %s\n", is_newpassword ? new_keyfile
379 : keyfile, strerror (errno));
380 return gpg_error_from_syserror ();
383 rc = set_inquire (fd, NULL, &inq);
384 if (rc)
386 close (fd);
387 return rc;
390 if (!quiet)
391 fprintf (stderr, N_("Using keyfile '%s' as %s.\n"),
392 sign ? sign_keyfile : is_newpassword ? new_keyfile
393 : keyfile, keyword);
395 #ifdef HAVE_LIBREADLINE
396 else if ((!inq->last_keyword || strcmp (keyword, inq->last_keyword))
397 && interactive)
399 fprintf (stderr,
401 ("%sPress CTRL-D to send the current line. Press twice to end. %s:\n"),
402 inq->last_keyword ? "\n" : "", keyword);
403 pwmd_free (inq->last_keyword);
404 inq->last_keyword = pwmd_strdup (keyword);
406 #endif
408 /* The first part of the command data. */
409 if (inq->len)
411 *data = inq->line;
412 *size = inq->len;
413 inq->len = 0;
414 return inq->fd == -1 ? gpg_error (GPG_ERR_EOF) : 0;
417 *size = read (inq->fd, inq->line, ASSUAN_LINELENGTH);
418 if (*size == -1)
420 *size = 0;
421 return gpg_error (gpg_error_from_syserror ());
423 else if (*size)
424 *data = inq->line;
425 else if (inq->fd != STDIN_FILENO &&
426 (is_newpassword || is_password || sign || is_keyparam))
428 *inq->line = 0;
429 inq->size = 1;
430 *data = inq->line;
431 *size = 1;
434 if (((is_newpassword && new_keyfile) || (is_password && keyfile)
435 || (sign && sign_keyfile) || (keyparams && is_keyparam))
436 && *size == inq->size)
437 return gpg_error (GPG_ERR_EOF);
439 return *size ? 0 : gpg_error (GPG_ERR_EOF);
442 static int
443 status_msg_cb (void *data, const char *line)
445 char *p = strchr (line, ' ');
446 char **s;
448 /* Ignore status messages specified by the client via --status-ignore. */
449 for (s = status_ignore; s && *s; s++)
451 char *tmp = strchr (line, ' ');
452 size_t len = tmp ? strlen (line) - strlen (tmp) : strlen (line);
454 if (!strncmp (line, *s, len) && len == strlen (*s))
455 return 0;
458 if (interactive && !strncmp (line, "XFER ", 5) && *line != '#' && p
459 && strchr (p, ' ') && *++p)
461 char *p1 = strchr (p, ' ');
462 int a = strtol (p, NULL, 10);
464 if (isdigit (*p) && p1)
466 int b = strtol (p1, NULL, 10);
467 char l[64] = { 0 };
468 int t = a && b ? a * 100 / b : 0;
470 strncpy (l, line, strlen (line) - strlen (p) - 1);
471 fprintf (statusfp, "\rS:%s %i/%i %i%%%s", l, a, b, t,
472 a == b ? "\n" : "");
473 fflush (statusfp);
474 return 0;
478 fprintf (statusfp, "S:%s\n", line);
479 fflush (statusfp);
480 #ifdef HAVE_LIBREADLINE
481 rl_on_new_line ();
482 #endif
483 return 0;
486 static gpg_error_t
487 process_cmd ()
489 return pwmd_process (pwm);
492 #ifdef WITH_SSH
493 static gpg_error_t
494 get_password (char **result, pwmd_pinentry_t w, int echo)
496 char buf[LINE_MAX] = { 0 }, *p;
497 struct termios told, tnew;
498 char *key = NULL;
500 *result = NULL;
502 if (!isatty (STDIN_FILENO))
504 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
505 return GPG_ERR_ENOTTY;
508 if (!echo)
510 if (tcgetattr (STDIN_FILENO, &told) == -1)
511 return gpg_error_from_syserror ();
513 memcpy (&tnew, &told, sizeof (struct termios));
514 tnew.c_lflag &= ~(ECHO);
515 tnew.c_lflag |= ICANON | ECHONL;
517 if (tcsetattr (STDIN_FILENO, TCSANOW, &tnew) == -1)
519 int n = errno;
521 tcsetattr (STDIN_FILENO, TCSANOW, &told);
522 return gpg_error_from_errno (n);
526 switch (w)
528 case PWMD_PINENTRY_OPEN:
529 fprintf (stderr, N_("Password for %s: "), filename);
530 break;
531 case PWMD_PINENTRY_OPEN_FAILED:
532 fprintf (stderr, N_("Invalid password. Password for %s: "), filename);
533 break;
534 case PWMD_PINENTRY_SAVE:
535 fprintf (stderr, N_("New password for %s: "), filename);
536 break;
537 case PWMD_PINENTRY_SAVE_CONFIRM:
538 fprintf (stderr, N_("Confirm password: "));
539 break;
540 default:
541 break;
544 if ((p = fgets (buf, sizeof (buf), stdin)) == NULL)
546 if (!echo)
547 tcsetattr (STDIN_FILENO, TCSANOW, &told);
549 return 0;
552 if (!echo)
553 tcsetattr (STDIN_FILENO, TCSANOW, &told);
555 if (feof (stdin))
557 clearerr (stdin);
558 return GPG_ERR_CANCELED;
561 p[strlen (p) - 1] = 0;
563 if (buf[0])
565 key = pwmd_strdup_printf ("%s", p);
566 memset (&buf, 0, sizeof (buf));
568 if (!key)
569 return GPG_ERR_ENOMEM;
572 *result = key;
573 return 0;
576 static gpg_error_t
577 knownhost_cb (void *data, const char *host, const char *key, size_t len)
579 gpg_error_t rc;
580 char *buf =
581 pwmd_strdup_printf (N_
582 ("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?"),
583 (char *) data, host, host);
585 if (no_pinentry && !isatty (STDIN_FILENO))
587 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
588 pwmd_free (buf);
589 return GPG_ERR_ENOTTY;
591 else if (no_pinentry)
593 for (char *p = buf, len = 0; *p; p++, len++)
595 if (*p == '\n')
596 len = 0;
598 if (len == 78)
600 char *t = p;
602 while (!isspace (*(--p)));
603 *p = '\n';
604 p = t;
605 len = 0;
609 fprintf (stderr, "%s\n\n", buf);
610 pwmd_free (buf);
614 char *result;
616 fprintf (stderr, N_("Trust this connection [y/N]: "));
617 fflush (stderr);
618 rc = get_password (&result, PWMD_PINENTRY_CONFIRM, 1);
620 if (rc)
621 return rc;
623 if (!result || !*result || *result == 'n' || *result == 'N')
625 if (result && *result)
626 pwmd_free (result);
628 return GPG_ERR_NOT_CONFIRMED;
631 if ((*result == 'y' || *result == 'Y') && *(result + 1) == 0)
633 pwmd_free (result);
634 return 0;
637 while (1);
640 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, buf);
641 pwmd_free (buf);
643 if (rc)
644 return rc;
646 return pwmd_getpin (pwm, NULL, NULL, NULL, PWMD_PINENTRY_CONFIRM);
648 #endif
650 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
651 static pwmd_socket_t
652 is_remote_url (const char *str)
654 if (!str)
655 return PWMD_SOCKET_LOCAL;
657 #ifdef WITH_SSH
658 if (strstr (str, "ssh://") || strstr (str, "ssh4://")
659 || strstr (str, "ssh6://"))
660 return PWMD_SOCKET_SSH;
661 #endif
663 #ifdef WITH_GNUTLS
664 if (strstr (str, "tls://") || strstr (str, "tls4://")
665 || strstr (str, "tls6://"))
666 return PWMD_SOCKET_TLS;
667 #endif
669 return PWMD_SOCKET_LOCAL;
671 #endif
673 static char *
674 escape (const char *str)
676 const char *p;
677 char *buf = pwmd_malloc (ASSUAN_LINELENGTH + 1), *b = buf;
678 size_t len = 0;
680 for (p = str; *p; p++, len++)
682 if (len == ASSUAN_LINELENGTH)
683 break;
685 if (*p == '\\')
687 switch (*++p)
689 case 't':
690 *b++ = '\t';
691 break;
692 case 'n':
693 *b++ = '\n';
694 break;
695 case 'v':
696 *b++ = '\v';
697 break;
698 case 'b':
699 *b++ = '\b';
700 break;
701 case 'f':
702 *b++ = '\f';
703 break;
704 case 'r':
705 *b++ = '\r';
706 break;
707 default:
708 *b++ = *p;
709 break;
712 if (!*p)
713 break;
715 continue;
718 *b++ = *p;
721 *b = 0;
722 return buf;
725 static void
726 free_inquire (struct inquire_s *inq)
728 if (!inq)
729 return;
731 pwmd_free (inq->line);
733 if (inq->fd != -1 && inq->fd != STDIN_FILENO)
734 close (inq->fd);
736 pwmd_free (inq->last_keyword);
737 pwmd_free (inq);
740 /* When *result is not NULL it is updated to the new values and not
741 * reallocated. */
742 static gpg_error_t
743 set_inquire (int fd, const char *line, struct inquire_s **result)
745 struct inquire_s inq = { 0 };
746 struct stat st = { 0 };
747 gpg_error_t rc;
749 if (fd != -1)
751 if (fstat (fd, &st) == -1)
752 return gpg_error_from_syserror ();
754 inq.size = st.st_size;
757 inq.fd = fd;
758 inq.line = pwmd_calloc (1, ASSUAN_LINELENGTH);
759 if (!inq.line)
760 return GPG_ERR_ENOMEM;
762 if (line)
764 char *s = escape (line);
766 if (!s)
768 pwmd_free (inq.line);
769 return GPG_ERR_ENOMEM;
772 if (strlen (s) >= ASSUAN_LINELENGTH)
774 pwmd_free (inq.line);
775 pwmd_free (s);
776 return GPG_ERR_LINE_TOO_LONG;
779 strncpy (inq.line, s, ASSUAN_LINELENGTH - 1);
780 inq.len = strlen (s);
781 pwmd_free (s);
784 rc = pwmd_setopt (pwm, PWMD_OPTION_INQUIRE_TOTAL,
785 st.st_size ? st.st_size + strlen (inq.line) : 0);
786 if (rc)
788 pwmd_free (inq.line);
789 return rc;
792 if (*result == NULL)
793 *result = pwmd_malloc (sizeof (struct inquire_s));
794 else
796 if ((*result)->fd != -1 && (*result)->fd != STDIN_FILENO)
797 close ((*result)->fd);
799 pwmd_free ((*result)->line);
800 (*result)->line = NULL;
801 (*result)->fd = -1;
802 (*result)->len = 0;
805 memcpy (*result, &inq, sizeof (struct inquire_s));
806 memset (&inq, 0, sizeof (struct inquire_s));
807 return rc;
810 #ifdef HAVE_LIBREADLINE
811 static int
812 interactive_hook (void)
814 interactive_error = process_cmd ();
816 if (interactive_error)
817 rl_event_hook = NULL;
819 return 0;
822 static int
823 get_readline_char (FILE *fp)
825 if (rl_line_buffer
826 && (!strncmp (rl_line_buffer, ".set passphrase-file ", 16)
827 || !strncmp (rl_line_buffer, ".set new-passphrase-file ", 20)
828 || !strncmp (rl_line_buffer, ".set sign-passphrase-file ", 21)))
829 rl_inhibit_completion = 0;
830 else if (rl_line_buffer
831 && !strncmp (rl_line_buffer, ".redir ", 7))
833 char *p = strchr (rl_line_buffer, ' ');
835 if (strchr (++p, ' '))
836 rl_inhibit_completion = 1;
837 else
838 rl_inhibit_completion = 0;
840 else if (rl_line_buffer
841 && !strncmp (rl_line_buffer, ".read ", 6))
843 char *p = rl_line_buffer + 6;
845 if (strstr (p, "--prefix "))
847 p = strstr (p, "--prefix ");
848 p += 9;
849 p = strchr (p, ' ');
850 if (p)
851 p++;
854 if (!p || strchr (p, ' '))
855 rl_inhibit_completion = 1;
856 else
857 rl_inhibit_completion = 0;
859 else
860 rl_inhibit_completion = 1;
862 return fgetc (fp);
865 static void
866 print_help ()
868 fprintf (stderr,
870 ("------------------------------------------------------------\n"
871 "Elements are TAB delimited. Type HELP for protocol commands.\n"
872 "Type .help for pwmc commands. Press CTRL-D to quit.\n"
873 "------------------------------------------------------------\n"));
875 #endif
877 static char *
878 parse_arg (const char *src, char *dst, size_t len)
880 char *p = dst;
881 const char *s = src;
882 size_t n = 0;
884 for (; s && *s && *s != ' ' && n < len; s++, n++)
885 *p++ = *s;
887 *p = 0;
888 return dst;
891 static char *
892 parse_opt (char **line, const char *opt, gpg_error_t * rc)
894 static char result[ASSUAN_LINELENGTH] = { 0 }, *r = result;
895 char *s = strstr (*line, opt);
897 *rc = 0;
898 result[0] = 0;
899 r = result;
901 if (s)
903 size_t len = 0;
904 int quote = 0;
905 size_t rlen = strlen (opt);
906 char *p = s + rlen;
907 int lastc = 0;
909 while (*p && *p == ' ')
911 rlen++;
912 p++;
915 for (; *p && len < sizeof (result) - 1; p++, rlen++)
917 if (isspace (*p) && !quote)
918 break;
920 if (*p == '\"' && lastc != '\\')
922 quote = !quote;
923 lastc = *p;
924 continue;
927 *r++ = lastc = *p;
928 len++;
931 *r = 0;
933 if (len >= sizeof (result) - 1)
934 *rc = GPG_ERR_LINE_TOO_LONG;
935 else
937 p = s + rlen;
939 while (*p && *p == ' ')
940 p++;
942 *line = p;
946 return result;
949 static gpg_error_t
950 read_command (const char *line, char **result, size_t * len)
952 int fd;
953 gpg_error_t rc = 0;
954 char *file = NULL;
955 struct inquire_s *inq = NULL;
956 char *p = (char *) line;
957 const char *prefix = parse_opt (&p, "--prefix", &rc);
958 char filebuf[ASSUAN_LINELENGTH];
960 if (rc)
961 return rc;
963 rc = GPG_ERR_SYNTAX;
965 if (p && *p)
967 while (*p && isspace (*p))
968 p++;
970 file = parse_arg (p, filebuf, sizeof (filebuf));
971 if (file && *file)
973 p += strlen (file) + 1;
975 while (*p && isspace (*p))
976 p++;
978 if (*p)
979 rc = 0;
983 if (rc)
985 fprintf (stderr,
987 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
988 fprintf (stderr,
990 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\\ = \\)\n"));
991 return rc;
994 fd = open (file, O_RDONLY);
995 if (fd == -1)
996 return gpg_error_from_syserror ();
998 rc = set_inquire (fd, prefix && *prefix ? prefix : NULL, &inq);
999 if (rc)
1001 close (fd);
1002 return rc;
1005 rc = pwmd_command (pwm, result, len, inquire_cb, inq, "%s", p);
1006 free_inquire (inq);
1007 return rc;
1010 static gpg_error_t
1011 redir_command (const char *line)
1013 const char *p = line;
1014 int fd;
1015 gpg_error_t rc = GPG_ERR_SYNTAX;
1016 char *file = NULL;
1017 struct inquire_s *inq = NULL;
1018 char *result = NULL;
1019 size_t len = 0;
1020 char filebuf[ASSUAN_LINELENGTH];
1022 if (p && *p && *++p)
1024 file = parse_arg (p, filebuf, sizeof (filebuf));
1025 if (file && *file)
1027 p += strlen (file) + 1;
1029 while (*p && isspace (*p))
1030 p++;
1032 if (*p)
1033 rc = 0;
1037 if (rc)
1039 fprintf (stderr, N_("Usage: .redir <filename> <command> [args]\n"));
1040 return rc;
1043 fd = open (file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
1044 if (fd == -1)
1045 return gpg_error_from_syserror ();
1047 #ifdef HAVE_LIBREADLINE
1048 rc = set_inquire (interactive ? STDIN_FILENO : inquirefd, NULL, &inq);
1049 #else
1050 rc = set_inquire (inquirefd, NULL, &inq);
1051 #endif
1052 if (rc)
1054 close (fd);
1055 return rc;
1058 rc = parse_dotcommand (p, &result, &len, inq);
1059 if (!rc && result && len--)
1060 { // null byte which is always appended
1061 if (write (fd, result, len) != len)
1062 rc = GPG_ERR_TOO_SHORT;
1063 pwmd_free (result);
1066 free_inquire (inq);
1067 close (fd);
1068 return rc;
1071 static gpg_error_t
1072 help_command (const char *line)
1074 fprintf (stderr,
1075 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
1076 " .redir <filename> <command>\n"
1077 " redirect the output of a command to the specified file\n"
1078 "\n"
1079 " .open <filename>\n"
1080 " open the specified filename losing any changes to the current one\n"
1081 "\n"
1082 " .read [--prefix <string>] <filename> <command> [args]\n"
1083 " obtain data from the specified filename for an inquire command\n"
1084 "\n"
1085 " .set help | <name> [<value>]\n"
1086 " set option <name> to <value>\n"
1087 "\n"
1088 " .save [args]\n"
1089 " write changes of the file to disk\n"
1090 "\n"
1091 " .passwd [args]\n"
1092 " change the passphrase of a data file\n"
1093 "\n"
1094 " .help\n"
1095 " this help text\n"));
1096 return 0;
1099 static gpg_error_t
1100 open_command (char *line)
1102 struct inquire_s *inq = NULL;
1103 const char *file = line;
1104 gpg_error_t rc;
1105 int local;
1107 while (file && isspace (*file))
1108 file++;
1110 if (!file || !*file)
1112 fprintf (stderr, N_("Usage: .open <filename>\n"));
1113 return GPG_ERR_SYNTAX;
1116 #ifdef HAVE_LIBREADLINE
1117 if (interactive || !quiet)
1118 #else
1119 if (!quiet)
1120 #endif
1121 fprintf (stderr, N_("Opening data file \"%s\" ...\n"), file);
1123 #ifdef HAVE_LIBREADLINE
1124 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1125 #else
1126 rc = set_inquire (-1, NULL, &inq);
1127 #endif
1128 if (rc)
1129 return rc;
1131 pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local);
1133 if (keyfile)
1135 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1136 if (!rc)
1137 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, 1);
1139 else
1140 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1142 if (!rc)
1143 rc = pwmd_open (pwm, file, inquire_cb, inq);
1145 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local);
1147 #ifdef HAVE_LIBREADLINE
1148 if (interactive)
1149 reset_keyfiles ();
1150 #endif
1152 free_inquire (inq);
1153 if (!rc && file != filename)
1155 pwmd_free (filename);
1156 filename = pwmd_strdup (file);
1159 return rc;
1162 static gpg_error_t
1163 set_command (const char *line)
1165 gpg_error_t rc = 0;
1166 char name[256] = { 0 };
1167 char value[512] = { 0 };
1168 char *namep;
1169 char *valuep;
1170 const char *p = line;
1172 while (p && *p && isspace (*p))
1173 p++;
1175 namep = parse_arg (p, name, sizeof (name));
1176 if (!namep || !*namep)
1178 fprintf (stderr, N_("Usage: .set help | <name> [<value>]\n"));
1179 return GPG_ERR_SYNTAX;
1182 p += strlen (namep);
1183 while (p && *p && isspace (*p))
1184 p++;
1186 valuep = parse_arg (p, value, sizeof (value));
1188 if (!strcmp (name, "passphrase-file") || !strcmp (name, "new-passphrase-file")
1189 || !strcmp (name, "sign-passphrase-file"))
1191 int is_newkeyfile = 1;
1192 int sign = !strcmp (name, "sign-passphrase-file");
1194 if (!strcmp (name, "passphrase-file") || sign)
1195 is_newkeyfile = 0;
1197 if (is_newkeyfile)
1199 pwmd_free (new_keyfile);
1200 new_keyfile = NULL;
1202 else if (sign)
1204 pwmd_free (sign_keyfile);
1205 sign_keyfile = NULL;
1207 else
1209 pwmd_free (keyfile);
1210 keyfile = NULL;
1213 if (!rc && *valuep)
1215 if (is_newkeyfile)
1216 new_keyfile = pwmd_strdup (value);
1217 else if (sign)
1218 sign_keyfile = pwmd_strdup (value);
1219 else
1220 keyfile = pwmd_strdup (value);
1222 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1224 else if (!local_pin && !no_pinentry)
1226 pwmd_socket_t t;
1228 pwmd_socket_type (pwm, &t);
1229 if (t == PWMD_SOCKET_LOCAL)
1230 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1233 else if (!strcmp(name, "pinentry-timeout"))
1235 char *e = NULL;
1236 int n = strtol(valuep, &e, 10);
1238 if (e && *e)
1239 return gpg_error (GPG_ERR_INV_VALUE);
1241 if (!*valuep)
1242 n = DEFAULT_PIN_TIMEOUT;
1244 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, n);
1246 else if (!strcmp (name, "help"))
1248 fprintf (stderr,
1250 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1251 "delimited. When no value is specified the option is unset.\n\n"
1252 "passphrase-file [<filename>]\n"
1253 " set or unset the file to be used when a passphrase is required (*)\n"
1254 "\n"
1255 "new-passphrase-file [<filename>]\n"
1256 " set or unset the file to be used when a new passphrase is required (*)\n"
1257 "\n"
1258 "sign-passphrase-file [<filename>]\n"
1259 " set or unset the file to be used when a passphrase is required for\n"
1260 " signing (symmetric) (*)\n"
1261 "\n"
1262 "pinentry-timeout <seconds>\n"
1263 " the amount of seconds before pinentry gives up waiting for input\n"
1264 "\n"
1265 "* = the next protocol command will unset this value\n"
1268 else
1269 rc = GPG_ERR_UNKNOWN_OPTION;
1271 return rc;
1274 static gpg_error_t
1275 do_save_passwd_command (const char *line, int save)
1277 struct inquire_s *inq = NULL;
1278 gpg_error_t rc;
1279 int local;
1281 #ifdef HAVE_LIBREADLINE
1282 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1283 #else
1284 rc = set_inquire (-1, NULL, &inq);
1285 #endif
1286 if (rc)
1287 return rc;
1289 pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local);
1291 if (new_keyfile || keyfile || sign_keyfile)
1293 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1294 if (!rc)
1295 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, 1);
1297 else
1298 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1300 if (!rc)
1302 if (save)
1303 rc = pwmd_save (pwm, line, inquire_cb, inq);
1304 else
1305 rc = pwmd_passwd (pwm, line, inquire_cb, inq);
1308 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local);
1310 #ifdef HAVE_LIBREADLINE
1311 if (interactive)
1312 reset_keyfiles ();
1313 #endif
1315 free_inquire (inq);
1316 return rc;
1319 static gpg_error_t
1320 save_command (const char *line)
1322 return do_save_passwd_command (line, 1);
1325 static gpg_error_t
1326 parse_dotcommand (const char *line, char **result,
1327 size_t * len, struct inquire_s *inq)
1329 const char *p = line;
1330 gpg_error_t rc = 0;
1332 if (!strncmp (p, ".read", 5))
1333 rc = read_command (p + 5, result, len);
1334 else if (!strncmp (p, ".redir", 6))
1335 rc = redir_command (p + 6);
1336 else if (!strncmp (p, ".help", 5))
1337 rc = help_command (p + 5);
1338 else if (!strncmp (p, ".open", 5))
1339 rc = open_command ((char *)p + 5);
1340 else if (!strncmp (p, ".set", 4))
1341 rc = set_command (p + 4);
1342 else if (!strncmp (p, ".save", 5))
1343 rc = do_save_passwd_command (p + 5, 1);
1344 else if (!strncmp (p, ".passwd", 7))
1345 rc = do_save_passwd_command (p + 7, 0);
1346 else
1348 rc = pwmd_command (pwm, result, len, inquire_cb, inq, "%s", line);
1349 #ifdef HAVE_LIBREADLINE
1350 if (interactive)
1352 #endif
1353 reset_keyfiles ();
1354 #ifdef HAVE_LIBREADLINE
1356 #endif
1359 return FINISH (rc);
1362 #ifdef HAVE_LIBREADLINE
1363 static gpg_error_t
1364 do_interactive ()
1366 gpg_error_t rc;
1367 struct inquire_s *inq = NULL;
1369 rl_initialize ();
1370 rc = process_cmd ();
1371 if (rc)
1372 return rc;
1374 rc = set_inquire (STDIN_FILENO, NULL, &inq);
1375 if (rc)
1376 return rc;
1378 fprintf (stderr,
1379 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1380 print_help ();
1381 rl_event_hook = &interactive_hook;
1382 rl_getc_function = get_readline_char;
1383 rl_set_keyboard_input_timeout (100000);
1385 for (;;)
1387 char *line;
1388 char *result = NULL;
1389 size_t len;
1391 rc = 0;
1392 line = readline ("pwmc> ");
1393 if (interactive_error)
1395 free (line);
1396 rc = interactive_error;
1397 break;
1400 if (!line)
1402 rc = finalize ();
1403 if (!rc)
1404 break;
1406 if (gpg_err_code (rc) != GPG_ERR_CANCELED &&
1407 gpg_err_code (rc) != GPG_ERR_EOF)
1408 fprintf (stderr, "ERR %i: %s\n", rc, gpg_strerror (rc));
1410 continue;
1412 else if (!*line)
1414 free (line);
1415 continue;
1418 #ifdef HAVE_READLINE_HISTORY
1419 add_history (line);
1420 #endif
1421 rc = parse_dotcommand (line, &result, &len, inq);
1422 free (line);
1423 if (rc)
1425 char *tmp = NULL;
1427 if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
1428 (void) pwmd_command (pwm, &tmp, NULL, NULL, NULL,
1429 "GETINFO last_error");
1431 show_error (pwm, rc, tmp);
1432 pwmd_free (tmp);
1434 else if (result && len)
1435 printf ("%s%s", result, result[len - 1] != '\n' ? "\n" : "");
1437 pwmd_free (result);
1440 free_inquire (inq);
1441 return rc;
1443 #endif
1445 static gpg_error_t
1446 finalize ()
1448 gpg_error_t rc = 0;
1449 #ifdef HAVE_LIBREADLINE
1450 int quit = 0;
1452 if (interactive)
1454 int finished = 0;
1456 fprintf (stderr, "\n");
1460 char *p, buf[16];
1462 fprintf (stderr,
1464 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1465 p = fgets (buf, sizeof (buf), stdin);
1467 if (feof (stdin))
1469 clearerr (stdin);
1470 return GPG_ERR_EOF;
1473 switch (*p)
1475 case 'h':
1476 print_help ();
1477 break;
1478 case 'c':
1479 return GPG_ERR_CANCELED;
1480 case 'Q':
1481 return 0;
1482 case 'f':
1483 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1484 "CLEARCACHE %s", filename);
1485 if (rc)
1486 return rc;
1488 interactive_hook ();
1489 break;
1490 case 'S':
1491 quit = 1;
1492 case 's':
1493 save = 1;
1494 finished = 1;
1495 break;
1496 default:
1497 break;
1500 while (!finished);
1502 #endif
1504 if (save && !filename)
1506 fprintf (stderr,
1508 ("No filename was specified on the command line. Aborting.\n"));
1509 return GPG_ERR_CANCELED;
1512 if (save && filename)
1514 char *args =
1515 pwmd_strdup_printf ("%s %s%s %s%s %s",
1516 symmetric ? "--symmetric" : "",
1517 keyid ? "--keyid=" : "",
1518 keyid ? keyid : "",
1519 sign_keyid ? "--sign-keyid=" : "",
1520 sign_keyid ? sign_keyid : "",
1521 keyparams ? "--inquire-keyparam" : "");
1523 #ifdef HAVE_LIBREADLINE
1524 if (!quiet || interactive)
1526 #else
1527 if (!quiet)
1529 #endif
1530 fprintf (stderr, "\n");
1531 fprintf (stderr, N_("Saving changes ...\n"));
1534 rc = save_command (args);
1535 pwmd_free (args);
1538 #ifdef HAVE_LIBREADLINE
1539 if (interactive)
1540 return rc ? rc : quit ? 0 : GPG_ERR_CANCELED;
1541 #endif
1543 return rc;
1546 static void
1547 parse_status_ignore (char *str)
1549 size_t n = 0;
1550 char **p, *s;
1552 for (p = status_ignore; p && *p; p++)
1553 pwmd_free (*p);
1555 pwmd_free (status_ignore);
1556 status_ignore = NULL;
1557 if (!str || !*str)
1558 return;
1560 while ((s = strsep (&str, ",")))
1562 p = pwmd_realloc (status_ignore, (n + 2) * sizeof (char *));
1563 p[n++] = pwmd_strdup (s);
1564 p[n] = NULL;
1565 status_ignore = p;
1570 main (int argc, char *argv[])
1572 int connected = 0;
1573 gpg_error_t rc;
1574 int opt;
1575 char command[ASSUAN_LINELENGTH], *p = NULL;
1576 char *result = NULL;
1577 size_t len = 0;
1578 char *pinentry_path = NULL;
1579 char *display = NULL, *tty = NULL, *ttytype = NULL;
1580 char *lcctype = NULL, *lcmessages = NULL;
1581 int outfd = STDOUT_FILENO;
1582 FILE *outfp = stdout;
1583 FILE *inquirefp = stdin;
1584 int show_status = 1;
1585 char *clientname = "pwmc";
1586 char *inquire = NULL;
1587 char *inquire_line = NULL;
1588 int timeout = 0;
1589 #ifdef WITH_SSH
1590 int use_ssh_agent = 1;
1591 char *knownhosts = NULL;
1592 char *identity = NULL;
1593 #endif
1594 #ifdef WITH_GNUTLS
1595 char *cacert = NULL;
1596 char *clientcert = NULL;
1597 char *clientkey = NULL;
1598 char *prio = NULL;
1599 int tls_verify = 0;
1600 char *tls_fingerprint = NULL;
1601 #endif
1602 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1603 pwmd_socket_t socktype;
1604 long socket_timeout = 300;
1605 int connect_timeout = 120;
1606 int needs_passphrase = 0;
1607 #endif
1608 int lock_on_open = 1;
1609 long lock_timeout = 50;
1610 char *url = NULL;
1611 char *tmp = NULL;
1612 /* The order is important. */
1613 enum
1615 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1616 OPT_SOCKET_TIMEOUT, OPT_CONNECT_TIMEOUT,
1617 #endif
1618 #ifdef WITH_SSH
1619 OPT_USE_SSH_AGENT, OPT_IDENTITY, OPT_KNOWNHOSTS, OPT_SSH_NEEDS_PASSPHRASE,
1620 #endif
1621 #ifdef WITH_GNUTLS
1622 OPT_CACERT, OPT_CLIENTCERT, OPT_CLIENTKEY, OPT_PRIORITY, OPT_VERIFY,
1623 OPT_SERVER_FP,
1624 #endif
1625 OPT_URL, OPT_LOCAL, OPT_TTYNAME, OPT_TTYTYPE, OPT_DISPLAY, OPT_LC_CTYPE,
1626 OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES, OPT_PINENTRY, OPT_KEYFILE,
1627 OPT_PASSPHRASE_FILE, OPT_NEW_KEYFILE, OPT_NEW_PASSPHRASE_FILE,
1628 OPT_SIGN_KEYFILE, OPT_SIGN_PASSPHRASE_FILE, OPT_NOLOCK, OPT_LOCK_TIMEOUT,
1629 OPT_SAVE, OPT_OUTPUT_FD, OPT_INQUIRE, OPT_INQUIRE_FD, OPT_INQUIRE_FILE,
1630 OPT_INQUIRE_LINE, OPT_NO_STATUS, OPT_STATUS_IGNORE, OPT_STATUSFD, OPT_NAME,
1631 OPT_VERSION, OPT_HELP, OPT_KEYID, OPT_SIGN_KEYID, OPT_SYMMETRIC,
1632 OPT_KEYPARAMS, OPT_NO_PINENTRY, OPT_QUIET,
1633 #ifdef HAVE_LIBREADLINE
1634 OPT_INTERACTIVE,
1635 #endif
1637 const struct option long_opts[] = {
1638 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1639 {"socket-timeout", 1, 0, 0},
1640 {"connect-timeout", 1, 0, 0},
1641 #endif
1643 #ifdef WITH_SSH
1644 {"no-ssh-agent", 0, 0, 0},
1645 {"identity", 1, 0, 'i'},
1646 {"knownhosts", 1, 0, 'k'},
1647 {"ssh-needs-passphrase", 0, 0, 0},
1648 #endif
1649 #ifdef WITH_GNUTLS
1650 {"ca-cert", 1, 0, 0},
1651 {"client-cert", 1, 0, 0},
1652 {"client-key", 1, 0, 0},
1653 {"tls-priority", 1, 0, 0},
1654 {"tls-verify", 0, 0, 0},
1655 {"tls-fingerprint", 1, 0, 0},
1656 #endif
1657 {"url", 1, 0, 0},
1658 {"local-pinentry", 0, 0},
1659 {"ttyname", 1, 0, 'y'},
1660 {"ttytype", 1, 0, 't'},
1661 {"display", 1, 0, 'd'},
1662 {"lc-ctype", 1, 0, 0},
1663 {"lc-messages", 1, 0, 0},
1664 {"timeout", 1, 0, 0},
1665 {"tries", 1, 0, 0},
1666 {"pinentry", 1, 0, 0},
1667 {"key-file", 1, 0, 0},
1668 {"passphrase-file", 1, 0, 0},
1669 {"new-key-file", 1, 0, 0},
1670 {"new-passphrase-file", 1, 0, 0},
1671 {"sign-key-file", 1, 0, 0},
1672 {"sign-passphrase-file", 1, 0, 0},
1673 {"no-lock", 0, 0, 0},
1674 {"lock-timeout", 1, 0, 0},
1675 {"save", 0, 0, 'S'},
1676 {"output-fd", 1, 0, 0},
1677 {"inquire", 1, 0, 0},
1678 {"inquire-fd", 1, 0, 0},
1679 {"inquire-file", 1, 0, 0},
1680 {"inquire-line", 1, 0, 'L'},
1681 {"no-status", 0, 0, 0},
1682 {"status-ignore", 1, 0, 0},
1683 {"status-fd", 1, 0, 0},
1684 {"name", 1, 0, 'n'},
1685 {"version", 0, 0, 0},
1686 {"help", 0, 0, 0},
1687 {"keyid", 1, 0, 0},
1688 {"sign-keyid", 1, 0, 0},
1689 {"symmetric", 0, 0, 0},
1690 {"key-params", 1, 0, 0},
1691 {"no-pinentry", 0, 0, 0},
1692 {"quiet", 0, 0, 0},
1693 #ifdef HAVE_LIBREADLINE
1694 {"interactive", 0, 0},
1695 #endif
1696 {0, 0, 0, 0}
1698 #ifdef WITH_SSH
1699 const char *optstring = "L:y:t:d:P:I:Sn:i:k:s";
1700 #else
1701 const char *optstring = "L:y:t:d:P:I:Sn:s";
1702 #endif
1703 int opt_index = 0;
1705 #ifdef ENABLE_NLS
1706 setlocale (LC_ALL, "");
1707 bindtextdomain ("libpwmd", LOCALEDIR);
1708 #endif
1710 tries = DEFAULT_PIN_TRIES;
1711 inquirefd = STDIN_FILENO;
1712 statusfd = STDERR_FILENO;
1713 statusfp = fdopen (statusfd, "w");
1714 tmp = pwmd_strdup (DEFAULT_STATUS_IGNORE);
1715 parse_status_ignore (tmp);
1716 pwmd_free (tmp);
1718 while ((opt =
1719 getopt_long (argc, argv, optstring, long_opts, &opt_index)) != -1)
1721 switch (opt)
1723 /* Handle long options without a short option part. */
1724 case 0:
1725 switch (opt_index)
1727 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1728 case OPT_SOCKET_TIMEOUT:
1729 socket_timeout = strtol (optarg, &p, 10);
1730 break;
1731 case OPT_CONNECT_TIMEOUT:
1732 connect_timeout = strtol (optarg, &p, 10);
1733 break;
1734 #endif
1735 #ifdef WITH_SSH
1736 case OPT_USE_SSH_AGENT:
1737 use_ssh_agent = 0;
1738 break;
1739 case OPT_SSH_NEEDS_PASSPHRASE:
1740 needs_passphrase = 1;
1741 break;
1742 #endif
1743 #ifdef WITH_GNUTLS
1744 case OPT_CACERT:
1745 cacert = optarg;
1746 break;
1747 case OPT_CLIENTCERT:
1748 clientcert = optarg;
1749 break;
1750 case OPT_CLIENTKEY:
1751 clientkey = optarg;
1752 break;
1753 case OPT_PRIORITY:
1754 prio = optarg;
1755 break;
1756 case OPT_VERIFY:
1757 tls_verify = 1;
1758 break;
1759 case OPT_SERVER_FP:
1760 tls_fingerprint = optarg;
1761 break;
1762 #endif
1763 case OPT_SYMMETRIC:
1764 symmetric = 1;
1765 break;
1766 case OPT_KEYPARAMS:
1767 keyparams = optarg;
1768 break;
1769 case OPT_KEYFILE:
1770 case OPT_PASSPHRASE_FILE:
1771 keyfile = pwmd_strdup (optarg);
1772 break;
1773 case OPT_NEW_KEYFILE:
1774 case OPT_NEW_PASSPHRASE_FILE:
1775 new_keyfile = pwmd_strdup (optarg);
1776 break;
1777 case OPT_SIGN_KEYFILE:
1778 case OPT_SIGN_PASSPHRASE_FILE:
1779 sign_keyfile = pwmd_strdup (optarg);
1780 break;
1781 case OPT_NOLOCK:
1782 lock_on_open = 0;
1783 break;
1784 case OPT_LOCK_TIMEOUT:
1785 lock_timeout = strtol (optarg, &p, 10);
1786 break;
1787 case OPT_URL:
1788 url = optarg;
1789 break;
1790 case OPT_LOCAL:
1791 local_pin = 1;
1792 break;
1793 case OPT_LC_CTYPE:
1794 lcctype = pwmd_strdup (optarg);
1795 break;
1796 case OPT_LC_MESSAGES:
1797 lcmessages = pwmd_strdup (optarg);
1798 break;
1799 case OPT_TIMEOUT:
1800 timeout = strtol (optarg, &p, 10);
1801 break;
1802 case OPT_TRIES:
1803 tries = strtol (optarg, &p, 10);
1804 break;
1805 case OPT_INQUIRE:
1806 inquire = escape (optarg);
1807 break;
1808 case OPT_INQUIRE_FD:
1809 inquirefd = strtol (optarg, &p, 10);
1810 if (!p)
1812 inquirefp = fdopen (inquirefd, "r");
1813 if (!inquirefp)
1814 err (EXIT_FAILURE, "%i", inquirefd);
1816 break;
1817 case OPT_INQUIRE_FILE:
1818 inquirefd = open (optarg, O_RDONLY);
1819 if (inquirefd == -1)
1820 err (EXIT_FAILURE, "%s", optarg);
1821 inquirefp = fdopen (inquirefd, "r");
1822 break;
1823 case OPT_OUTPUT_FD:
1824 outfd = strtol (optarg, &p, 10);
1825 if (!p || !*p)
1827 outfp = fdopen (outfd, "w");
1828 if (!outfp)
1829 err (EXIT_FAILURE, "%i", outfd);
1831 break;
1832 case OPT_NO_STATUS:
1833 show_status = 0;
1834 break;
1835 case OPT_STATUSFD:
1836 statusfd = strtol (optarg, &p, 10);
1837 if (!p || !*p)
1839 statusfp = fdopen (statusfd, "w");
1840 if (!statusfp)
1841 err (EXIT_FAILURE, "%i", statusfd);
1843 break;
1844 case OPT_STATUS_IGNORE:
1845 parse_status_ignore (optarg);
1846 break;
1847 case OPT_VERSION:
1848 printf ("%s (pwmc)\n\n"
1849 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016\n"
1850 "%s\n"
1851 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1852 "Compile-time features:\n"
1853 #ifdef HAVE_LIBREADLINE
1854 "+INTERACTIVE "
1855 #else
1856 "-INTERACTIVE "
1857 #endif
1858 #ifdef WITH_SSH
1859 "+SSH "
1860 #else
1861 "-SSH "
1862 #endif
1863 #ifdef WITH_GNUTLS
1864 "+GNUTLS "
1865 #else
1866 "-GNUTLS "
1867 #endif
1868 #ifdef WITH_PINENTRY
1869 "+PINENTRY "
1870 #else
1871 "-PINENTRY "
1872 #endif
1873 #ifdef WITH_QUALITY
1874 "+CRACK "
1875 #else
1876 "-CRACK "
1877 #endif
1878 #ifdef MEM_DEBUG
1879 "+MEM_DEBUG "
1880 #else
1881 "-MEM_DEBUG "
1882 #endif
1883 "\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1884 exit (EXIT_SUCCESS);
1885 case OPT_PINENTRY:
1886 pinentry_path = optarg;
1887 break;
1888 case OPT_HELP:
1889 usage (argv[0], EXIT_SUCCESS);
1890 case OPT_KEYID:
1891 keyid = optarg;
1892 break;
1893 case OPT_SIGN_KEYID:
1894 sign_keyid = optarg;
1895 break;
1896 case OPT_QUIET:
1897 quiet = 1;
1898 show_status = 0;
1899 break;
1900 case OPT_NO_PINENTRY:
1901 no_pinentry = 1;
1902 break;
1903 #ifdef HAVE_LIBREADLINE
1904 case OPT_INTERACTIVE:
1905 interactive = 1;
1906 break;
1907 #endif
1908 default:
1909 usage (argv[0], EXIT_FAILURE);
1912 if (p && *p)
1914 fprintf (stderr, N_("%s: invalid argument for option '--%s'\n"),
1915 argv[0], long_opts[opt_index].name);
1916 usage (argv[0], EXIT_FAILURE);
1919 break;
1920 #ifdef WITH_SSH
1921 case 'i':
1922 identity = optarg;
1923 break;
1924 case 'k':
1925 knownhosts = optarg;
1926 break;
1927 #endif
1928 case 'L':
1929 inquire_line = optarg;
1930 break;
1931 case 'y':
1932 tty = optarg;
1933 break;
1934 case 't':
1935 ttytype = optarg;
1936 break;
1937 case 'd':
1938 display = optarg;
1939 break;
1940 case 'S':
1941 save = 1;
1942 break;
1943 case 'n':
1944 clientname = optarg;
1945 break;
1946 default:
1947 usage (argv[0], EXIT_FAILURE);
1951 #ifdef HAVE_LIBREADLINE
1952 if (interactive && !isatty (STDIN_FILENO))
1953 usage (argv[0], EXIT_FAILURE);
1954 else if (isatty (STDIN_FILENO) && !inquire && !inquire_line)
1955 interactive = 1;
1956 #endif
1958 pwmd_init ();
1959 rc = pwmd_new (clientname, &pwm);
1960 if (rc)
1961 goto done;
1963 filename = argv[optind] ? pwmd_strdup (argv[optind]) : NULL;
1964 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1965 if (rc)
1966 goto done;
1968 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local_pin);
1969 if (rc)
1970 goto done;
1972 pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
1973 if (!quiet)
1974 fprintf (stderr, N_("Connecting ...\n"));
1976 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1977 socktype = is_remote_url (url);
1978 if (socktype != PWMD_SOCKET_LOCAL)
1980 local_pin = 1;
1981 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1982 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, connect_timeout);
1983 if (rc)
1984 goto done;
1985 #endif
1987 if (socktype == PWMD_SOCKET_SSH)
1989 #ifdef WITH_SSH
1990 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_CB, knownhost_cb);
1991 if (rc)
1992 goto done;
1994 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_DATA, clientname);
1995 if (rc)
1996 goto done;
1998 if (!getenv ("SSH_AUTH_SOCK") || identity)
1999 use_ssh_agent = 0;
2001 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_AGENT, use_ssh_agent);
2002 if (rc)
2003 goto done;
2005 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_NEEDS_PASSPHRASE,
2006 needs_passphrase);
2007 if (rc)
2008 goto done;
2010 rc = pwmd_connect (pwm, url, identity, knownhosts);
2011 #endif
2013 #ifdef WITH_GNUTLS
2014 else
2016 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_VERIFY, tls_verify);
2017 if (rc)
2018 goto done;
2020 rc = pwmd_connect (pwm, url, clientcert, clientkey, cacert, prio,
2021 tls_fingerprint);
2023 #endif
2025 else
2026 rc = pwmd_connect (pwm, url);
2027 #else
2028 rc = pwmd_connect (pwm, url);
2029 #endif
2030 if (rc)
2031 goto done;
2033 if (!quiet)
2034 fprintf (stderr, N_("Connected.\n"));
2036 connected = 1;
2037 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2038 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, socket_timeout);
2039 if (rc)
2040 goto done;
2041 #endif
2043 if (lock_timeout)
2045 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
2046 "OPTION LOCK-TIMEOUT=%li", lock_timeout);
2047 if (rc)
2048 goto done;
2051 if (lock_on_open)
2053 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCK_ON_OPEN, 1);
2054 if (rc)
2055 goto done;
2058 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, NULL, NULL);
2059 if (rc)
2060 goto done;
2062 if (timeout > 0)
2064 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
2065 if (rc)
2066 goto done;
2069 if (pinentry_path)
2071 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
2072 if (rc)
2073 goto done;
2076 if (display)
2078 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
2079 if (rc)
2080 goto done;
2083 if (tty)
2085 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, tty);
2086 if (rc)
2087 goto done;
2090 if (ttytype)
2092 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
2093 if (rc)
2094 goto done;
2097 if (lcctype)
2099 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
2100 if (rc)
2101 goto done;
2104 if (lcmessages)
2106 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES, lcmessages);
2107 if (rc)
2108 goto done;
2111 if (show_status)
2113 rc = pwmd_setopt (pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
2114 if (rc)
2115 goto done;
2118 if (filename)
2120 rc = open_command (filename);
2121 if (rc)
2122 goto done;
2125 #ifdef HAVE_LIBREADLINE
2126 if (interactive)
2128 rc = do_interactive ();
2129 result = NULL;
2130 goto do_exit;
2132 #endif
2134 if (inquire)
2136 struct inquire_s *inq = NULL;
2138 rc = set_inquire (inquirefd, inquire_line, &inq);
2139 if (!rc)
2140 rc = pwmd_command (pwm, &result, &len, inquire_cb, inq, "%s", inquire);
2142 free_inquire (inq);
2143 goto done;
2146 if (fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1)
2148 rc = gpg_error_from_errno (errno);
2149 goto done;
2152 ssize_t n;
2154 for (;;)
2156 rc = process_cmd ();
2158 if (rc)
2159 goto done;
2161 n = read (STDIN_FILENO, command, sizeof (command)-1);
2162 if (n == -1)
2164 if (errno == EAGAIN)
2166 usleep (100000);
2167 continue;
2170 rc = gpg_error_from_errno (errno);
2171 goto done;
2173 else if (!n)
2174 goto done;
2176 p = command;
2177 command[n] = 0;
2178 break;
2181 if (!p || !*p || !strcasecmp (p, "BYE"))
2182 goto done;
2185 struct inquire_s *inq = NULL;
2186 rc = set_inquire (inquirefd, inquire_line, &inq);
2187 if (!rc)
2189 rc = parse_dotcommand (command, &result, &len, inq);
2190 free_inquire (inq);
2193 if (rc)
2194 goto done;
2196 done:
2197 if (result)
2199 fwrite (result, 1, result[len - 1] == 0 ? len - 1 : len, outfp);
2200 fflush (outfp);
2201 pwmd_free (result);
2204 result = NULL;
2205 if (!rc)
2206 rc = finalize ();
2207 else if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
2208 (void) pwmd_command (pwm, &result, NULL, NULL, NULL,
2209 "GETINFO last_error");
2211 #ifdef HAVE_LIBREADLINE
2212 do_exit:
2213 #endif
2214 memset (command, 0, sizeof (command));
2216 if (rc && !quiet)
2217 show_error (pwm, rc, result);
2219 pwmd_close (pwm);
2220 reset_keyfiles ();
2221 pwmd_deinit ();
2222 pwmd_free (result);
2223 pwmd_free (filename);
2224 parse_status_ignore (NULL);
2225 if (connected && !quiet)
2226 fprintf (stderr, N_("Connection closed.\n"));
2228 exit (rc ? EXIT_FAILURE : EXIT_SUCCESS);