pwmc: Fix usage text.
[libpwmd.git] / src / pwmc.c
blobd5a2af9d3369769b25fee056a41c0cd0f6a52c89
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015,
3 2016
4 Ben Kibbey <bjk@luxsci.net>
6 This file is part of libpwmd.
8 Libpwmd is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
13 Libpwmd is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Libpwmd. If not, see <http://www.gnu.org/licenses/>.
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <stdint.h>
29 #include <err.h>
30 #include <errno.h>
31 #include <string.h>
32 #include <libpwmd.h>
33 #include <assuan.h>
34 #include <sys/select.h>
35 #include <fcntl.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <libgen.h>
39 #include <termios.h>
40 #include <limits.h>
41 #include <ctype.h>
42 #include <time.h>
44 #include "util-string.h"
45 #include "util-slist.h"
47 #ifdef WITH_GNUTLS
48 #include <gnutls/gnutls.h>
49 #endif
51 #ifdef HAVE_LOCALE_H
52 #include <locale.h>
53 #endif
55 #ifdef HAVE_GETOPT_LONG
56 #ifdef HAVE_GETOPT_H
57 #include <getopt.h>
58 #endif
59 #else
60 #include "getopt_long.h"
61 #endif
63 #ifdef HAVE_LIBREADLINE
64 #if defined(HAVE_READLINE_READLINE_H)
65 #include <readline/readline.h>
66 #elif defined(HAVE_READLINE_H)
67 #include <readline.h>
68 #endif /* !defined(HAVE_READLINE_H) */
69 static int interactive_error;
70 static int interactive;
71 #endif /* HAVE_LIBREADLINE */
73 #ifdef HAVE_READLINE_HISTORY
74 #if defined(HAVE_READLINE_HISTORY_H)
75 #include <readline/history.h>
76 #elif defined(HAVE_HISTORY_H)
77 #include <history.h>
78 #endif
79 #endif /* HAVE_READLINE_HISTORY */
81 #ifndef LINE_MAX
82 #define LINE_MAX 2048
83 #endif
85 #include "gettext.h"
86 #define N_(msgid) gettext(msgid)
88 #include "mem.h"
91 #define DEFAULT_STATUS_IGNORE "KEEPALIVE,GPGME,PASSPHRASE_INFO,PASSPHRASE_HINT"
92 #define DEFAULT_PIN_TIMEOUT 30
93 #define DEFAULT_PIN_TRIES 3
94 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
95 ? gpg_error(rc) : rc
97 static int no_pinentry;
98 static pwm_t *pwm;
99 static char *filename;
100 static int save;
101 static char *keyid;
102 static char *sign_keyid;
103 static int symmetric;
104 static char *keyparams;
105 static char *keyfile;
106 static char *new_keyfile;
107 static char *sign_keyfile;
108 static int tries;
109 static int local_pin;
110 static int inquirefd;
111 static int statusfd;
112 FILE *statusfp;
113 static int quiet;
114 static char **status_ignore;
116 struct inquire_s
118 int fd;
119 char *line;
120 size_t len;
121 size_t size; // from stat(2).
122 char *last_keyword;
125 struct userid_s {
126 char *userid;
127 char *name;
128 char *email;
129 char *comment;
132 struct keyid_s {
133 char *keyid;
134 char *fpr;
135 char *card;
136 int can_sign;
137 int can_encrypt;
138 int can_certify;
139 int can_auth;
140 int expired;
141 time_t expires;
142 time_t created;
143 int secret;
144 int revoked;
145 int algo;
146 unsigned bits;
147 char *curve;
148 struct slist_s *userids;
149 struct slist_s *subkeys;
152 static gpg_error_t finalize ();
153 static gpg_error_t set_inquire (int fd, const char *line,
154 struct inquire_s **result);
155 static gpg_error_t parse_dotcommand (const char *line, char **result,
156 size_t * len, struct inquire_s *inq);
157 static gpg_error_t open_command (char *line);
159 static void
160 show_error (pwm_t *h, gpg_error_t rc, const char *str)
162 #ifdef WITH_GNUTLS
163 const char *tlsstr;
164 int e = pwmd_gnutls_error (h, &tlsstr);
166 if (e)
167 fprintf(stderr, "TLS: %s\n", tlsstr);
168 #else
169 (void)h;
170 #endif
171 fprintf (stderr, "ERR %i: %s%s%s%s", rc, gpg_strerror (rc),
172 str ? ": " : "", str ? str : "", str ? "" : "\n");
175 static void
176 reset_keyfiles ()
178 pwmd_free (keyfile);
179 pwmd_free (new_keyfile);
180 pwmd_free (sign_keyfile);
181 keyfile = new_keyfile = sign_keyfile = NULL;
184 static void
185 usage (const char *pn, int status)
187 fprintf (status == EXIT_FAILURE ? stderr : stdout,
188 N_("Usage: %s [options] [file]\n"
189 " --url <string>\n"
190 " a url string to connect to (%s, see below)\n"
191 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
192 " --connect-timeout <seconds>\n"
193 " seconds before connecting to a remote host fails (0=disabled, 120)\n"
194 " --socket-timeout <seconds>\n"
195 " seconds before a remote command fails (0=disabled, 300)\n"
196 #endif
197 #ifdef WITH_GNUTLS
198 " --ca-cert <filename>\n"
199 " certificate authority (CA) used to sign the server cert\n"
200 " --client-cert <filename>\n"
201 " client certificate to use for authentication\n"
202 " --client-key <filename>\n"
203 " key file used to protect the client certificate\n"
204 " --tls-priority <string>\n"
205 " compression, cipher and hash algorithm string\n"
206 " (SECURE256:SECURE192:SECURE128:-VERS-SSL3.0:-VERS-TLS1.0)\n"
207 " --no-tls-verify\n"
208 " disable verifying the hostname against the server certificate\n"
209 " --tls-fingerprint <string>\n"
210 " a SHA-256 hash of the server fingerprint to verify against\n"
211 #endif
212 #ifdef WITH_SSH
213 " --no-ssh-agent\n"
214 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
215 " --identity, -i <filename>\n"
216 " the ssh identity file to use for authentication\n"
217 " --knownhosts, -k <filename>\n"
218 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
219 " --ssh-needs-passphrase\n"
220 " prompt for a passphrase for the SSH identity file\n"
221 " --ssh-passphrase-file <filename>\n"
222 " read the SSH private key passphrase from filename\n"
223 #endif
224 " --no-lock\n"
225 " do not lock the data file upon opening it\n"
226 " --lock-timeout <N>\n"
227 " time in tenths of a second to wait for a locked data file (50)\n"
228 " --name, -n <string>\n"
229 " set the client name\n"
230 " --pinentry <path>\n"
231 " the full path to the pinentry binary\n"
232 " --local-pinentry\n"
233 " force using a local pinentry\n"
234 " --no-pinentry\n"
235 " disable pinentry both remotely and locally\n"
236 " --ttyname, -y <path>\n"
237 " tty that pinentry will use\n"
238 " --ttytype, -t <string>\n"
239 " pinentry terminal type (default is $TERM)\n"
240 " --display, -d\n"
241 " pinentry display (default is $DISPLAY)\n"
242 " --lc-ctype <string>\n"
243 " locale setting for pinentry\n"
244 " --lc-messages <string>\n"
245 " locale setting for pinentry\n"
246 " --tries <N>\n"
247 " number of pinentry tries before failing (3)\n"
248 " --timeout <seconds>\n"
249 " pinentry timeout\n"
250 " --inquire <COMMAND>\n"
251 " the specified command (with any options) uses a server inquire while\n"
252 " command data is read via the inquire file descriptor (stdin)\n"
253 " --inquire-line, -L <STRING>\n"
254 " the initial line to send (i.e., element path) before the inquire data\n"
255 " --inquire-fd <FD>\n"
256 " read inquire data from the specified file descriptor (stdin)\n"
257 " --inquire-file <filename>\n"
258 " read inquire data from the specified filename\n"
259 " --output-fd <FD>\n"
260 " redirect command output to the specified file descriptor\n"
261 " --save, -S\n"
262 " send the SAVE command before exiting\n"
263 " --passphrase-file <filename>\n"
264 " obtain the passphrase from the specified filename\n"
265 " --new-passphrase-file <filename>\n"
266 " obtain the passphrase to save with from the specified filename\n"
267 " --sign-passphrase-file <filename>\n"
268 " obtain the passphrase to sign with from the specified filename\n"
269 " --key-params <filename>\n"
270 " key parameters to use for key generation (pwmd default)\n"
271 " --keyid <recipient>[,<recipient>]\n"
272 " the public key ID to u\n"
273 " --sign-keyid <string>\n"
274 " the key ID to sign the data file with\n"
275 " --symmetric\n"
276 " use conventional encryption with optional signer(s) for new files\n"
277 " --no-status\n"
278 " disable showing of status messages from the server\n"
279 " --status-state\n"
280 " enable receiving of client STATE status messages\n"
281 " --status-fd <FD>\n"
282 " redirect status messages to the specified file descriptor\n"
283 " --status-ignore <string[,...]>\n"
284 " prevent parsing of the specified status message keywords\n"
285 " --quiet\n"
286 " disable showing of extra messages (implies --no-status)\n"
287 #ifdef HAVE_LIBREADLINE
288 " --no-interactive\n"
289 " disable interactive mode\n"
290 #endif
291 " --version\n"
292 " --help\n"),
294 #ifdef DEFAULT_PWMD_SOCKET
295 DEFAULT_PWMD_SOCKET
296 #else
297 "~/.pwmd/socket"
298 #endif
300 fprintf (status == EXIT_FAILURE ? stderr : stdout,
301 N_("\n"
302 "An optional url may be in the form of:\n"
303 " --url /path/to/socket\n"
304 " --url file://[/path/to/socket]\n"
305 #ifdef WITH_SSH
306 " or\n"
307 " --url ssh[46]://[username@]hostname[:port] (uses ssh-agent)\n"
308 " -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
309 #endif
310 #ifdef WITH_GNUTLS
311 " or\n"
312 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
313 " --client-key filename\n"
314 #endif
315 #ifdef HAVE_LIBREADLINE
316 "\n"
317 "Interactive mode is used when input is from a terminal.\n"
318 #endif
320 exit (status);
323 static gpg_error_t
324 inquire_cb (void *user, const char *keyword, gpg_error_t rc,
325 char **data, size_t * size)
327 struct inquire_s *inq = user;
328 int is_password = 0;
329 int is_newpassword = 0;
330 int sign = 0;
331 int is_keyparam = 0;
333 *data = NULL;
334 *size = 0;
336 if (rc)
337 return rc;
339 if (!strcmp (keyword, "PASSPHRASE"))
340 is_password = 1;
341 else if (!strcmp (keyword, "SIGN_PASSPHRASE"))
342 sign = 1;
343 else if (!strcmp (keyword, "NEW_PASSPHRASE"))
344 is_newpassword = 1;
345 #ifdef HAVE_LIBREADLINE
346 else if (!strcmp (keyword, "KEYPARAM") && !interactive)
348 #else
349 else if (!strcmp (keyword, "KEYPARAM"))
351 #endif
352 int fd;
353 if (!keyparams || !*keyparams)
354 return gpg_error (GPG_ERR_INV_PARAMETER);
356 fd = open (keyparams, O_RDONLY);
357 if (fd == -1)
359 fprintf (stderr, "%s: %s\n", keyparams, strerror (errno));
360 return gpg_error_from_syserror ();
363 rc = set_inquire (fd, NULL, &inq);
364 if (rc)
366 close (fd);
367 return rc;
370 if (!quiet)
371 fprintf (stderr, N_("Using file '%s' as %s.\n"), keyparams, keyword);
373 is_keyparam = 1;
376 if ((is_password && !keyfile) || (is_newpassword && !new_keyfile)
377 || (sign && !sign_keyfile))
379 char *tmp;
380 int local;
382 /* Try to use the local pinentry between inquires (new/sign/passphrase).
383 * If --no-pinentry was specified then the passphrase is read from the
384 * terminal as usual. */
385 pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local);
386 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, 1);
387 rc = pwmd_password (pwm, keyword, &tmp, &inq->len);
388 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local);
389 if (rc && gpg_err_code (rc) != GPG_ERR_EOF)
390 return rc;
392 pwmd_free (inq->line);
393 inq->line = tmp;
394 *data = inq->line;
395 *size = inq->len;
396 return gpg_error (GPG_ERR_EOF);
398 else if ((is_newpassword && new_keyfile) || (is_password && keyfile)
399 || (sign && sign_keyfile))
401 int fd;
403 if (sign)
404 fd = open (sign_keyfile, O_RDONLY);
405 else
406 fd = open (is_password || sign ? keyfile : new_keyfile, O_RDONLY);
408 if (fd == -1)
410 if (sign)
411 fprintf (stderr, "%s: %s\n", sign_keyfile, strerror (errno));
412 else
413 fprintf (stderr, "%s: %s\n", is_newpassword ? new_keyfile
414 : keyfile, strerror (errno));
415 return gpg_error_from_syserror ();
418 rc = set_inquire (fd, NULL, &inq);
419 if (rc)
421 close (fd);
422 return rc;
425 if (!quiet)
426 fprintf (stderr, N_("Using keyfile '%s' as %s.\n"),
427 sign ? sign_keyfile : is_newpassword ? new_keyfile
428 : keyfile, keyword);
430 #ifdef HAVE_LIBREADLINE
431 else if ((!inq->last_keyword || strcmp (keyword, inq->last_keyword))
432 && interactive && inq->fd == STDIN_FILENO)
434 fprintf (stderr,
436 ("%sPress CTRL-D to send the current line. Press twice to end. %s:\n"),
437 inq->last_keyword ? "\n" : "", keyword);
438 pwmd_free (inq->last_keyword);
439 inq->last_keyword = pwmd_strdup (keyword);
441 #endif
443 /* The first part of the command data. */
444 if (inq->len)
446 *data = inq->line;
447 *size = inq->len;
448 inq->len = 0;
449 return inq->fd == -1 ? gpg_error (GPG_ERR_EOF) : 0;
452 *size = read (inq->fd, inq->line, ASSUAN_LINELENGTH);
453 if (*size == -1)
455 *size = 0;
456 return gpg_error (gpg_error_from_syserror ());
458 else if (*size)
459 *data = inq->line;
460 else if (inq->fd != STDIN_FILENO &&
461 (is_newpassword || is_password || sign || is_keyparam))
463 *inq->line = 0;
464 inq->size = 1;
465 *data = inq->line;
466 *size = 1;
469 if (((is_newpassword && new_keyfile) || (is_password && keyfile)
470 || (sign && sign_keyfile) || (keyparams && is_keyparam))
471 && *size == inq->size)
472 return gpg_error (GPG_ERR_EOF);
474 return *size ? 0 : gpg_error (GPG_ERR_EOF);
477 static int
478 status_msg_cb (void *data, const char *line)
480 char *p = strchr (line, ' ');
481 char **s;
483 (void)data;
485 /* Ignore status messages specified by the client via --status-ignore. */
486 for (s = status_ignore; s && *s; s++)
488 char *tmp = strchr (line, ' ');
489 size_t len = tmp ? strlen (line) - strlen (tmp) : strlen (line);
491 if (!strncmp (line, *s, len) && len == strlen (*s))
492 return 0;
495 #ifdef HAVE_LIBREADLINE
496 if (interactive && !strncmp (line, "XFER ", 5)
497 #else
498 if (!strncmp (line, "XFER ", 5)
499 #endif
500 && *line != '#' && p && strchr (p, ' ') && *++p)
502 char *p1 = strchr (p, ' ');
503 int a = strtol (p, NULL, 10);
505 if (isdigit (*p) && p1)
507 int b = strtol (p1, NULL, 10);
508 char l[64] = { 0 };
509 int t = a && b ? a * 100 / b : 0;
511 strncpy (l, line, strlen (line) - strlen (p) - 1);
512 fprintf (statusfp, "\rS:%s %i/%i %i%%%s", l, a, b, t,
513 a == b ? "\n" : "");
514 fflush (statusfp);
515 return 0;
519 fprintf (statusfp, "S:%s\n", line);
520 fflush (statusfp);
521 #ifdef HAVE_LIBREADLINE
522 rl_on_new_line ();
523 #endif
524 return 0;
527 static gpg_error_t
528 process_cmd ()
530 return pwmd_process (pwm);
533 #ifdef WITH_SSH
534 static gpg_error_t
535 knownhost_cb (void *data, const char *host, const char *key, size_t len)
537 gpg_error_t rc = 0;
538 char *buf =
539 pwmd_strdup_printf (N_
540 ("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"),
541 (char *) data, host, host);
543 (void)key;
544 if (no_pinentry && !isatty (STDIN_FILENO))
546 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
547 pwmd_free (buf);
548 return GPG_ERR_ENOTTY;
550 else if (no_pinentry)
552 len = 0;
553 for (char *p = buf; *p; p++, len++)
555 if (*p == '\n')
556 len = 0;
558 if (len == 78)
560 char *t = p;
562 while (len && !isspace (*(--p)))
563 len--;
565 if (len)
566 *p = '\n';
567 len = 78 - len;
568 p = t;
571 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_PROMPT, N_("Accept [y/N]:"));
574 if (!rc)
575 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, buf);
577 pwmd_free (buf);
578 if (rc)
579 return rc;
581 return pwmd_getpin (pwm, NULL, NULL, NULL, PWMD_PINENTRY_CONFIRM);
583 #endif
585 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
586 static pwmd_socket_t
587 is_remote_url (const char *str)
589 if (!str)
590 return PWMD_SOCKET_LOCAL;
592 #ifdef WITH_SSH
593 if (strstr (str, "ssh://") || strstr (str, "ssh4://")
594 || strstr (str, "ssh6://"))
595 return PWMD_SOCKET_SSH;
596 #endif
598 #ifdef WITH_GNUTLS
599 if (strstr (str, "tls://") || strstr (str, "tls4://")
600 || strstr (str, "tls6://"))
601 return PWMD_SOCKET_TLS;
602 #endif
604 return PWMD_SOCKET_LOCAL;
606 #endif
608 static char *
609 escape (const char *str)
611 const char *p;
612 char *buf = pwmd_malloc (ASSUAN_LINELENGTH + 1), *b = buf;
613 size_t len = 0;
615 for (p = str; *p; p++, len++)
617 if (len == ASSUAN_LINELENGTH)
618 break;
620 if (*p == '\\')
622 switch (*++p)
624 case 't':
625 *b++ = '\t';
626 break;
627 case 'n':
628 *b++ = '\n';
629 break;
630 case 'v':
631 *b++ = '\v';
632 break;
633 case 'b':
634 *b++ = '\b';
635 break;
636 case 'f':
637 *b++ = '\f';
638 break;
639 case 'r':
640 *b++ = '\r';
641 break;
642 default:
643 *b++ = *p;
644 break;
647 if (!*p)
648 break;
650 continue;
653 *b++ = *p;
656 *b = 0;
657 return buf;
660 static void
661 free_inquire (struct inquire_s *inq)
663 if (!inq)
664 return;
666 pwmd_free (inq->line);
668 if (inq->fd != -1 && inq->fd != STDIN_FILENO)
669 close (inq->fd);
671 pwmd_free (inq->last_keyword);
672 pwmd_free (inq);
675 /* When *result is not NULL it is updated to the new values and not
676 * reallocated. */
677 static gpg_error_t
678 set_inquire (int fd, const char *line, struct inquire_s **result)
680 struct inquire_s inq = { 0 };
681 struct stat st = { 0 };
682 gpg_error_t rc;
684 if (fd != -1)
686 if (fstat (fd, &st) == -1)
687 return gpg_error_from_syserror ();
689 inq.size = st.st_size;
692 inq.fd = fd;
693 inq.line = pwmd_calloc (1, ASSUAN_LINELENGTH);
694 if (!inq.line)
695 return GPG_ERR_ENOMEM;
697 if (line)
699 char *s = escape (line);
701 if (!s)
703 pwmd_free (inq.line);
704 return GPG_ERR_ENOMEM;
707 if (strlen (s) >= ASSUAN_LINELENGTH)
709 pwmd_free (inq.line);
710 pwmd_free (s);
711 return GPG_ERR_LINE_TOO_LONG;
714 strncpy (inq.line, s, ASSUAN_LINELENGTH - 1);
715 inq.len = strlen (s);
716 pwmd_free (s);
719 rc = pwmd_setopt (pwm, PWMD_OPTION_INQUIRE_TOTAL,
720 st.st_size ? st.st_size + strlen (inq.line) : 0);
721 if (rc)
723 pwmd_free (inq.line);
724 return rc;
727 if (*result == NULL)
728 *result = pwmd_malloc (sizeof (struct inquire_s));
729 else
731 if ((*result)->fd != -1 && (*result)->fd != STDIN_FILENO)
732 close ((*result)->fd);
734 pwmd_free ((*result)->line);
735 (*result)->line = NULL;
736 (*result)->fd = -1;
737 (*result)->len = 0;
740 memcpy (*result, &inq, sizeof (struct inquire_s));
741 memset (&inq, 0, sizeof (struct inquire_s));
742 return rc;
745 #ifdef HAVE_LIBREADLINE
746 static int
747 interactive_hook (void)
749 interactive_error = process_cmd ();
751 if (interactive_error)
752 rl_event_hook = NULL;
754 return 0;
757 static int
758 get_readline_char (FILE *fp)
760 if (rl_line_buffer
761 && (!strncmp (rl_line_buffer, ".set passphrase-file ", 16)
762 || !strncmp (rl_line_buffer, ".set new-passphrase-file ", 20)
763 || !strncmp (rl_line_buffer, ".set sign-passphrase-file ", 21)))
764 rl_inhibit_completion = 0;
765 else if (rl_line_buffer
766 && !strncmp (rl_line_buffer, ".redir ", 7))
768 char *p = strchr (rl_line_buffer, ' ');
770 if (p && strchr (++p, ' '))
771 rl_inhibit_completion = 1;
772 else
773 rl_inhibit_completion = 0;
775 else if (rl_line_buffer
776 && !strncmp (rl_line_buffer, ".read ", 6))
778 char *p = rl_line_buffer + 6;
780 if (strstr (p, "--prefix "))
782 p = strstr (p, "--prefix ");
783 p += 9;
784 p = strchr (p, ' ');
785 if (p)
786 p++;
789 if (!p || strchr (p, ' '))
790 rl_inhibit_completion = 1;
791 else
792 rl_inhibit_completion = 0;
794 else
795 rl_inhibit_completion = 1;
797 return fgetc (fp);
800 static void
801 print_help ()
803 fprintf (stderr,
805 ("------------------------------------------------------------\n"
806 "Elements are TAB delimited. Type HELP for protocol commands.\n"
807 "Type .help for pwmc commands. Press CTRL-D to quit.\n"
808 "------------------------------------------------------------\n"));
810 #endif
812 static char *
813 parse_arg (const char *src, char *dst, size_t len)
815 char *p = dst;
816 const char *s = src;
817 size_t n = 0;
819 for (; s && *s && *s != ' ' && n < len; s++, n++)
820 *p++ = *s;
822 *p = 0;
823 return dst;
826 static char *
827 parse_opt (char **line, const char *opt, gpg_error_t * rc)
829 static char result[ASSUAN_LINELENGTH] = { 0 }, *r = result;
830 char *s = strstr (*line, opt);
832 *rc = 0;
833 result[0] = 0;
834 r = result;
836 if (s)
838 size_t len = 0;
839 int quote = 0;
840 size_t rlen = strlen (opt);
841 char *p = s + rlen;
842 int lastc = 0;
844 while (*p && *p == ' ')
846 rlen++;
847 p++;
850 for (; *p && len < sizeof (result) - 1; p++, rlen++)
852 if (isspace (*p) && !quote)
853 break;
855 if (*p == '\"' && lastc != '\\')
857 quote = !quote;
858 lastc = *p;
859 continue;
862 *r++ = lastc = *p;
863 len++;
866 *r = 0;
868 if (len >= sizeof (result) - 1)
869 *rc = GPG_ERR_LINE_TOO_LONG;
870 else
872 p = s + rlen;
874 while (*p && *p == ' ')
875 p++;
877 *line = p;
881 return result;
884 static gpg_error_t
885 read_command (const char *line, char **result, size_t * len)
887 int fd;
888 gpg_error_t rc = 0;
889 char *file = NULL;
890 struct inquire_s *inq = NULL;
891 char *p = (char *) line;
892 const char *prefix = parse_opt (&p, "--prefix", &rc);
893 char filebuf[ASSUAN_LINELENGTH];
895 if (rc)
896 return rc;
898 rc = GPG_ERR_SYNTAX;
900 if (p && *p)
902 while (*p && isspace (*p))
903 p++;
905 file = parse_arg (p, filebuf, sizeof (filebuf));
906 if (file && *file)
908 p += strlen (file) + 1;
910 while (*p && isspace (*p))
911 p++;
913 if (*p)
914 rc = 0;
918 if (rc)
920 fprintf (stderr,
922 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
923 fprintf (stderr,
925 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\\ = \\)\n"));
926 return rc;
929 fd = open (file, O_RDONLY);
930 if (fd == -1)
931 return gpg_error_from_syserror ();
933 rc = set_inquire (fd, prefix && *prefix ? prefix : NULL, &inq);
934 if (rc)
936 close (fd);
937 return rc;
940 rc = pwmd_command (pwm, result, len, inquire_cb, inq, "%s", p);
941 free_inquire (inq);
942 return rc;
945 static gpg_error_t
946 redir_command (const char *line)
948 const char *p = line;
949 int fd;
950 gpg_error_t rc = GPG_ERR_SYNTAX;
951 char *file = NULL;
952 struct inquire_s *inq = NULL;
953 char *result = NULL;
954 size_t len = 0;
955 char filebuf[ASSUAN_LINELENGTH];
957 if (p && *p && *++p)
959 file = parse_arg (p, filebuf, sizeof (filebuf));
960 if (file && *file)
962 p += strlen (file) + 1;
964 while (*p && isspace (*p))
965 p++;
967 if (*p)
968 rc = 0;
972 if (rc)
974 fprintf (stderr, N_("Usage: .redir <filename> <command> [args]\n"));
975 return rc;
978 fd = open (file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
979 if (fd == -1)
980 return gpg_error_from_syserror ();
982 #ifdef HAVE_LIBREADLINE
983 rc = set_inquire (interactive ? STDIN_FILENO : inquirefd, NULL, &inq);
984 #else
985 rc = set_inquire (inquirefd, NULL, &inq);
986 #endif
987 if (rc)
989 close (fd);
990 return rc;
993 rc = parse_dotcommand (p, &result, &len, inq);
994 if (!rc && result && len--)
995 { // null byte which is always appended
996 if (write (fd, result, len) != len)
997 rc = GPG_ERR_TOO_SHORT;
998 pwmd_free (result);
1001 free_inquire (inq);
1002 close (fd);
1003 return rc;
1006 static gpg_error_t
1007 help_command (const char *line)
1009 (void)line;
1010 fprintf (stderr,
1011 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
1012 " .redir <filename> <command>\n"
1013 " redirect the output of a command to the specified file\n"
1014 "\n"
1015 " .open <filename>\n"
1016 " open the specified filename losing any changes to the current one\n"
1017 "\n"
1018 " .read [--prefix <string>] <filename> <command> [args]\n"
1019 " obtain data from the specified filename for an inquire command\n"
1020 "\n"
1021 " .set help | <name> [<value>]\n"
1022 " set option <name> to <value>\n"
1023 "\n"
1024 " .save [args]\n"
1025 " write changes of the file to disk\n"
1026 "\n"
1027 " .passwd [args]\n"
1028 " change the passphrase of a data file\n"
1029 "\n"
1030 " .listkeys [--options] [pattern[,..]]\n"
1031 " show human readable output of the LISTKEYS command\n"
1032 "\n"
1033 " .help\n"
1034 " this help text\n"));
1035 return 0;
1038 static gpg_error_t
1039 open_command (char *line)
1041 struct inquire_s *inq = NULL;
1042 const char *file = line;
1043 gpg_error_t rc;
1044 int local;
1046 while (file && isspace (*file))
1047 file++;
1049 if (!file || !*file)
1051 fprintf (stderr, N_("Usage: .open <filename>\n"));
1052 return GPG_ERR_SYNTAX;
1055 #ifdef HAVE_LIBREADLINE
1056 if (interactive || !quiet)
1057 #else
1058 if (!quiet)
1059 #endif
1060 fprintf (stderr, N_("Opening data file \"%s\" ...\n"), file);
1062 #ifdef HAVE_LIBREADLINE
1063 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1064 #else
1065 rc = set_inquire (-1, NULL, &inq);
1066 #endif
1067 if (rc)
1068 return rc;
1070 pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local);
1072 if (keyfile)
1074 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1075 if (!rc)
1076 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, 1);
1078 else
1079 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1081 if (!rc)
1082 rc = pwmd_open (pwm, file, inquire_cb, inq);
1084 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local);
1086 #ifdef HAVE_LIBREADLINE
1087 if (interactive)
1088 reset_keyfiles ();
1089 #endif
1091 free_inquire (inq);
1092 if (!rc && file != filename)
1094 pwmd_free (filename);
1095 filename = pwmd_strdup (file);
1098 return rc;
1101 static gpg_error_t
1102 set_command (const char *line)
1104 gpg_error_t rc = 0;
1105 char name[256] = { 0 };
1106 char value[512] = { 0 };
1107 char *namep;
1108 char *valuep;
1109 const char *p = line;
1111 while (p && *p && isspace (*p))
1112 p++;
1114 namep = parse_arg (p, name, sizeof (name));
1115 if (!namep || !*namep)
1117 fprintf (stderr, N_("Usage: .set help | <name> [<value>]\n"));
1118 return GPG_ERR_SYNTAX;
1121 p += strlen (namep);
1122 while (p && *p && isspace (*p))
1123 p++;
1125 valuep = parse_arg (p, value, sizeof (value));
1127 if (!strcmp (name, "passphrase-file") || !strcmp (name, "new-passphrase-file")
1128 || !strcmp (name, "sign-passphrase-file"))
1130 int is_newkeyfile = 1;
1131 int sign = !strcmp (name, "sign-passphrase-file");
1133 if (!strcmp (name, "passphrase-file") || sign)
1134 is_newkeyfile = 0;
1136 if (is_newkeyfile)
1138 pwmd_free (new_keyfile);
1139 new_keyfile = NULL;
1141 else if (sign)
1143 pwmd_free (sign_keyfile);
1144 sign_keyfile = NULL;
1146 else
1148 pwmd_free (keyfile);
1149 keyfile = NULL;
1152 if (!rc && *valuep)
1154 if (is_newkeyfile)
1155 new_keyfile = pwmd_strdup (value);
1156 else if (sign)
1157 sign_keyfile = pwmd_strdup (value);
1158 else
1159 keyfile = pwmd_strdup (value);
1161 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1163 else if (!local_pin && !no_pinentry)
1165 pwmd_socket_t t;
1167 pwmd_socket_type (pwm, &t);
1168 if (t == PWMD_SOCKET_LOCAL)
1169 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1172 else if (!strcmp(name, "pinentry-timeout"))
1174 char *e = NULL;
1175 int n = strtol(valuep, &e, 10);
1177 if (e && *e)
1178 return gpg_error (GPG_ERR_INV_VALUE);
1180 if (!*valuep)
1181 n = DEFAULT_PIN_TIMEOUT;
1183 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, n);
1185 else if (!strcmp (name, "help"))
1187 fprintf (stderr,
1189 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1190 "delimited. When no value is specified the option is unset.\n\n"
1191 "passphrase-file [<filename>]\n"
1192 " set or unset the file to be used when a passphrase is required (*)\n"
1193 "\n"
1194 "new-passphrase-file [<filename>]\n"
1195 " set or unset the file to be used when a new passphrase is required (*)\n"
1196 "\n"
1197 "sign-passphrase-file [<filename>]\n"
1198 " set or unset the file to be used when a passphrase is required for\n"
1199 " signing (symmetric) (*)\n"
1200 "\n"
1201 "pinentry-timeout <seconds>\n"
1202 " the amount of seconds before pinentry gives up waiting for input\n"
1203 "\n"
1204 "* = the next protocol command will unset this value\n"
1207 else
1208 rc = GPG_ERR_UNKNOWN_OPTION;
1210 return rc;
1213 static gpg_error_t
1214 do_save_passwd_command (const char *line, int do_save)
1216 struct inquire_s *inq = NULL;
1217 gpg_error_t rc;
1218 int local;
1220 #ifdef HAVE_LIBREADLINE
1221 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1222 #else
1223 rc = set_inquire (-1, NULL, &inq);
1224 #endif
1225 if (rc)
1226 return rc;
1228 pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local);
1230 if (new_keyfile || keyfile || sign_keyfile)
1232 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1233 if (!rc)
1234 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, 1);
1236 else
1237 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1239 if (!rc)
1241 if (do_save)
1242 rc = pwmd_save (pwm, line, inquire_cb, inq);
1243 else
1244 rc = pwmd_passwd (pwm, line, inquire_cb, inq);
1247 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local);
1249 #ifdef HAVE_LIBREADLINE
1250 if (interactive)
1251 reset_keyfiles ();
1252 #endif
1254 free_inquire (inq);
1255 return rc;
1258 static gpg_error_t
1259 save_command (const char *line)
1261 return do_save_passwd_command (line, 1);
1264 static void
1265 search_and_replace (char *str, const char *s, const char r)
1267 char *p;
1269 p = strstr (str, s);
1270 if (p)
1272 *p = r;
1273 while (*++p)
1274 *p = *(p+1);
1275 search_and_replace (str, s, r);
1276 return;
1280 static char *
1281 openpgp_unescape (char *str)
1283 search_and_replace (str, "\\x3a", ':');
1284 search_and_replace (str, "\\x5c", '\\');
1285 return str;
1288 static void
1289 free_listkeys (struct slist_s *keys)
1291 unsigned i, t;
1293 t = slist_length (keys);
1294 for (i = 0; i < t; i++)
1296 struct keyid_s *key = slist_nth_data (keys, i);
1297 unsigned n, nt;
1299 nt = slist_length (key->userids);
1300 for (n = 0; n < nt; n++)
1302 struct userid_s *userid = slist_nth_data (key->userids, n);
1304 pwmd_free (userid->userid);
1305 pwmd_free (userid->name);
1306 pwmd_free (userid->email);
1307 pwmd_free (userid->comment);
1308 pwmd_free (userid);
1311 slist_free (key->userids);
1312 nt = slist_length (key->subkeys);
1313 for (n = 0; n < nt; n++)
1315 struct keyid_s *sub = slist_nth_data (key->subkeys, n);
1317 pwmd_free (sub->keyid);
1318 pwmd_free (sub->fpr);
1319 pwmd_free (sub->card);
1320 pwmd_free (sub->curve);
1321 pwmd_free (sub);
1324 slist_free (key->subkeys);
1325 pwmd_free (key);
1328 slist_free (keys);
1331 static const char *
1332 openpgp_algorithm (struct keyid_s *key)
1334 switch (key->algo)
1336 case 1:
1337 case 2:
1338 case 3:
1339 return "RSA";
1340 case 16:
1341 case 20:
1342 return "ELG";
1343 case 17:
1344 return "DSA";
1345 case 301:
1346 case 302:
1347 case 18:
1348 return "ECC";
1349 default:
1350 break;
1353 return N_("Unknown");
1356 static void
1357 display_listkeys (struct slist_s *keys)
1359 unsigned i, t;
1361 t = slist_length (keys);
1362 for (i = 0; i < t; i++)
1364 struct keyid_s *key = slist_nth_data (keys, i);
1365 unsigned st = slist_length (key->subkeys);
1366 unsigned s;
1367 unsigned ut = slist_length (key->userids);
1368 unsigned u;
1370 for (u = 0; u < ut; u++)
1372 struct userid_s *userid = slist_nth_data (key->userids, u);
1374 fprintf(stdout, N_("User ID: %s\n"), userid->userid);
1377 for (s = 0; s < st; s++)
1379 struct keyid_s *sub = slist_nth_data (key->subkeys, s);
1380 struct tm *tmp;
1381 const char *caps = NULL;
1382 char expires[11] = { 0 };
1383 char created[11] = { 0 };
1385 if (sub->expires)
1387 tmp = localtime (&sub->expires);
1388 strftime (expires, sizeof (expires), "%F", tmp);
1391 tmp = localtime (&sub->created);
1392 strftime (created, sizeof (created), "%F", tmp);
1394 if (sub->can_encrypt)
1395 caps = "E";
1396 else if (sub->can_sign)
1397 caps = "S";
1398 else if (sub->can_auth)
1399 caps = "A";
1400 else if (sub->can_certify)
1401 caps = "C";
1403 fprintf(stdout, N_(
1404 " Subkey %u: %s [%s]%s%s %s-%u%s%s\n"
1405 " Created: %s %s%s\n"
1406 " Fingerprint: %s\n"
1407 "%s%s%s"),
1408 s+1,
1409 sub->keyid,
1410 caps,
1411 sub->secret || sub->card ? "[P]" : "",
1412 sub->revoked ? "[R]" : "",
1413 openpgp_algorithm (sub),
1414 sub->bits,
1415 sub->curve ? "-" : "",
1416 sub->curve ? sub->curve : "",
1417 created,
1418 sub->expired ? N_("Expired: ") : expires[0] ? N_("Expires: ") : "",
1419 sub->expired || expires[0] ? expires : "",
1420 sub->fpr,
1421 sub->card ? N_(" Card: ") : "",
1422 sub->card ? sub->card : "",
1423 sub->card ? "\n" : "");
1426 if (i+1 < t)
1427 fprintf (stdout, "\n");
1431 static gpg_error_t
1432 listkeys_command (const char *pattern)
1434 gpg_error_t rc;
1435 char *result;
1436 char **lines = NULL, **p;
1437 struct slist_s *keys = NULL;
1439 rc = pwmd_command (pwm, &result, NULL, NULL, NULL, "LISTKEYS %s", pattern);
1440 if (rc)
1441 return rc;
1443 lines = str_split (result, "\n", 0);
1444 pwmd_free (result);
1445 if (!lines)
1446 return GPG_ERR_ENOMEM;
1448 for (p = lines; *p; p++)
1450 struct keyid_s *key;
1451 char **fields = str_split (*p, ":", 0);
1452 int i, f;
1453 unsigned s;
1454 unsigned n_subkeys = 0;
1455 struct slist_s *tlist;
1457 if (!fields)
1459 rc = GPG_ERR_ENOMEM;
1460 break;
1463 key = pwmd_calloc (1, sizeof (struct keyid_s));
1464 if (!key)
1466 strv_free (fields);
1467 rc = GPG_ERR_ENOMEM;
1468 break;
1471 for (f = i = 0; i < 17; i++, f++)
1473 int b = 0;
1475 if (i < 10)
1476 b = atoi (fields[f]) != 0;
1478 switch (i)
1480 case 0: key->revoked = b; break;
1481 case 1: key->expired = b; break;
1482 case 4: key->can_encrypt = b; break;
1483 case 5: key->can_sign = b; break;
1484 case 7: key->secret = b; break;
1485 case 16: n_subkeys = strtoul (fields[f], NULL, 10); break;
1486 default:
1487 break;
1491 for (s = 0; s < n_subkeys; s++)
1493 struct keyid_s *sub;
1494 int b = 0;
1496 sub = pwmd_calloc (1, sizeof (struct keyid_s));
1497 if (!sub)
1499 strv_free (fields);
1500 rc = GPG_ERR_ENOMEM;
1501 break;
1504 for (i = 0; i < 20; i++, f++)
1506 if (i < 11)
1507 b = atoi (fields[f]) != 0;
1509 switch (i)
1511 case 0: sub->revoked = b; break;
1512 case 1: sub->expired = b; break;
1513 case 4: sub->can_encrypt = b; break;
1514 case 5: sub->can_sign = b; break;
1515 case 6: sub->can_certify = b; break;
1516 case 7: sub->secret = b; break;
1517 case 8: sub->can_auth = b; break;
1518 case 11: sub->algo = atoi (fields[f]); break;
1519 case 12: sub->bits = atoi (fields[f]); break;
1520 case 13: sub->keyid = pwmd_strdup (fields[f]); break;
1521 case 14: sub->fpr = pwmd_strdup (fields[f]); break;
1522 case 16: sub->created = strtoul (fields[f], NULL, 10); break;
1523 case 17: sub->expires = strtoul (fields[f], NULL, 10); break;
1524 case 18: sub->card = fields[f] && strlen(fields[f]) > 1
1525 ? pwmd_strdup (fields[f]) : NULL; break;
1526 case 19: sub->curve = strlen (fields[f]) > 1 ? pwmd_strdup (openpgp_unescape(fields[f])) : NULL; break;
1527 default:
1528 break;
1532 tlist = slist_append (key->subkeys, sub);
1533 if (!tlist)
1535 rc = GPG_ERR_ENOMEM;
1536 break;
1539 key->subkeys = tlist;
1542 if (rc)
1544 strv_free (fields);
1545 break;
1548 // Re-create a line containing the userIds.
1549 for (; f < strv_length (fields); f++)
1551 struct userid_s *userid;
1553 userid = pwmd_calloc (1, sizeof (struct userid_s));
1554 if (!userid)
1556 rc = GPG_ERR_ENOMEM;
1557 break;
1560 // Revoked.
1561 f++;
1562 // Invalid.
1563 f++;
1564 // Validity.
1565 f++;
1567 userid->userid = pwmd_strdup (openpgp_unescape (fields[f++]));
1568 userid->name = pwmd_strdup (openpgp_unescape (fields[f++]));
1569 userid->email = pwmd_strdup (openpgp_unescape (fields[f++]));
1570 userid->comment = pwmd_strdup (openpgp_unescape (fields[f]));
1572 tlist = slist_append (key->userids, userid);
1573 if (!tlist)
1575 rc = GPG_ERR_ENOMEM;
1576 break;
1579 key->userids = tlist;
1582 strv_free (fields);
1583 if (rc)
1584 break;
1586 tlist = slist_append (keys, key);
1587 if (!tlist)
1589 rc = GPG_ERR_ENOMEM;
1590 break;
1593 keys = tlist;
1596 strv_free (lines);
1598 if (!rc)
1599 display_listkeys (keys);
1601 free_listkeys (keys);
1602 return rc;
1605 static gpg_error_t
1606 parse_dotcommand (const char *line, char **result,
1607 size_t * len, struct inquire_s *inq)
1609 const char *p = line;
1610 gpg_error_t rc = 0;
1612 if (!strncmp (p, ".read", 5))
1613 rc = read_command (p + 5, result, len);
1614 else if (!strncmp (p, ".redir", 6))
1615 rc = redir_command (p + 6);
1616 else if (!strncmp (p, ".help", 5))
1617 rc = help_command (p + 5);
1618 else if (!strncmp (p, ".open", 5))
1619 rc = open_command ((char *)p + 5);
1620 else if (!strncmp (p, ".set", 4))
1621 rc = set_command (p + 4);
1622 else if (!strncmp (p, ".save", 5))
1623 rc = do_save_passwd_command (p + 5, 1);
1624 else if (!strncmp (p, ".passwd", 7))
1625 rc = do_save_passwd_command (p + 7, 0);
1626 else if (!strncmp (p, ".listkeys", 9))
1627 rc = listkeys_command (p+9);
1628 else
1630 rc = pwmd_command (pwm, result, len, inquire_cb, inq, "%s", line);
1631 #ifdef HAVE_LIBREADLINE
1632 if (interactive)
1634 #endif
1635 reset_keyfiles ();
1636 #ifdef HAVE_LIBREADLINE
1638 #endif
1640 if (!rc && !strncasecmp (line, "RESET", 5))
1642 pwmd_free (filename);
1643 filename = NULL;
1647 return FINISH (rc);
1650 #ifdef HAVE_LIBREADLINE
1651 #ifdef HAVE_READLINE_HISTORY
1652 static void
1653 add_history_item (const char *line)
1655 HIST_ENTRY **list, *p = NULL;
1656 int i;
1658 list = history_list ();
1659 for (i = 0; list && list[i]; i++)
1661 if (!strcmp (list[i]->line, line))
1663 p = list[i];
1664 break;
1668 if (p)
1670 char *s;
1672 p = remove_history (i);
1673 #ifdef HAVE_FREE_HISTORY_ENTRY
1674 s = free_history_entry (p);
1675 #endif
1676 free (s);
1679 add_history (line);
1681 #endif
1683 static gpg_error_t
1684 do_interactive ()
1686 gpg_error_t rc;
1687 struct inquire_s *inq = NULL;
1689 rl_initialize ();
1690 rc = process_cmd ();
1691 if (rc)
1692 return rc;
1694 rc = set_inquire (STDIN_FILENO, NULL, &inq);
1695 if (rc)
1696 return rc;
1698 fprintf (stderr,
1699 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1700 print_help ();
1701 rl_event_hook = &interactive_hook;
1702 rl_getc_function = get_readline_char;
1703 rl_set_keyboard_input_timeout (100000);
1705 for (;;)
1707 char *line;
1708 char *result = NULL;
1709 size_t len;
1710 char buf[255];
1712 rc = 0;
1713 snprintf (buf, sizeof (buf), "pwmc%s%s> ",
1714 filename ? ":" : "", filename ? filename : "");
1715 line = readline (buf);
1716 if (interactive_error)
1718 free (line);
1719 rc = interactive_error;
1720 break;
1723 if (!line)
1725 rc = finalize ();
1726 if (!rc)
1727 break;
1729 if (gpg_err_code (rc) != GPG_ERR_CANCELED &&
1730 gpg_err_code (rc) != GPG_ERR_EOF)
1731 fprintf (stderr, "ERR %i: %s\n", rc, gpg_strerror (rc));
1733 continue;
1735 else if (!*line)
1737 free (line);
1738 continue;
1741 #ifdef HAVE_READLINE_HISTORY
1742 add_history_item (line);
1743 #endif
1744 rc = parse_dotcommand (line, &result, &len, inq);
1745 free (line);
1746 if (rc)
1748 char *tmp = NULL;
1750 if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
1751 (void) pwmd_command (pwm, &tmp, NULL, NULL, NULL,
1752 "GETINFO last_error");
1754 show_error (pwm, rc, tmp);
1755 pwmd_free (tmp);
1757 else if (result && len)
1758 printf ("%s%s", result, result[len - 1] != '\n' ? "\n" : "");
1760 pwmd_free (result);
1763 free_inquire (inq);
1764 return rc;
1766 #endif
1768 static gpg_error_t
1769 finalize ()
1771 gpg_error_t rc = 0;
1772 #ifdef HAVE_LIBREADLINE
1773 int quit = 0;
1775 if (interactive)
1777 int finished = 0;
1779 fprintf (stderr, "\n");
1783 char *p, buf[16];
1785 fprintf (stderr,
1787 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1788 p = fgets (buf, sizeof (buf), stdin);
1790 if (feof (stdin))
1792 clearerr (stdin);
1793 return GPG_ERR_EOF;
1796 switch (*p)
1798 case 'h':
1799 print_help ();
1800 break;
1801 case 'c':
1802 return GPG_ERR_CANCELED;
1803 case 'Q':
1804 return 0;
1805 case 'f':
1806 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1807 "CLEARCACHE %s", filename);
1808 if (rc)
1809 return rc;
1811 interactive_hook ();
1812 break;
1813 case 'S':
1814 quit = 1;
1815 case 's':
1816 save = 1;
1817 finished = 1;
1818 break;
1819 default:
1820 break;
1823 while (!finished);
1825 #endif
1827 if (save && !filename)
1829 fprintf (stderr,
1831 ("No filename was specified on the command line. Aborting.\n"));
1832 return GPG_ERR_CANCELED;
1835 if (save && filename)
1837 char *args =
1838 pwmd_strdup_printf ("%s %s%s %s%s %s",
1839 symmetric ? "--symmetric" : "",
1840 keyid ? "--keyid=" : "",
1841 keyid ? keyid : "",
1842 sign_keyid ? "--sign-keyid=" : "",
1843 sign_keyid ? sign_keyid : "",
1844 keyparams ? "--inquire-keyparam" : "");
1846 #ifdef HAVE_LIBREADLINE
1847 if (!quiet || interactive)
1849 #else
1850 if (!quiet)
1852 #endif
1853 fprintf (stderr, "\n");
1854 fprintf (stderr, N_("Saving changes ...\n"));
1857 rc = save_command (args);
1858 pwmd_free (args);
1861 #ifdef HAVE_LIBREADLINE
1862 if (interactive)
1863 return rc ? rc : quit ? 0 : GPG_ERR_CANCELED;
1864 #endif
1866 return rc;
1869 static void
1870 parse_status_ignore (char *str)
1872 size_t n = 0;
1873 char **p, *s;
1875 for (p = status_ignore; p && *p; p++)
1876 pwmd_free (*p);
1878 pwmd_free (status_ignore);
1879 status_ignore = NULL;
1880 if (!str || !*str)
1881 return;
1883 while ((s = strsep (&str, ",")))
1885 p = pwmd_realloc (status_ignore, (n + 2) * sizeof (char *));
1886 p[n++] = pwmd_strdup (s);
1887 p[n] = NULL;
1888 status_ignore = p;
1893 main (int argc, char *argv[])
1895 int connected = 0;
1896 int status_state = 0;
1897 gpg_error_t rc;
1898 int opt;
1899 char command[ASSUAN_LINELENGTH], *p = NULL;
1900 char *result = NULL;
1901 size_t len = 0;
1902 char *pinentry_path = NULL;
1903 char *display = NULL, *tty = NULL, *ttytype = NULL;
1904 char *lcctype = NULL, *lcmessages = NULL;
1905 int outfd = STDOUT_FILENO;
1906 FILE *outfp = stdout;
1907 FILE *inquirefp = stdin;
1908 int show_status = 1;
1909 const char *clientname = "pwmc";
1910 char *inquire = NULL;
1911 char *inquire_line = NULL;
1912 int timeout = 0;
1913 #ifdef WITH_SSH
1914 int use_ssh_agent = -1;
1915 char *knownhosts = NULL;
1916 char *identity = NULL;
1917 int needs_passphrase = 0;
1918 char *ssh_passphrase_file = NULL;
1919 #endif
1920 #ifdef WITH_GNUTLS
1921 char *cacert = NULL;
1922 char *clientcert = NULL;
1923 char *clientkey = NULL;
1924 char *prio = NULL;
1925 int tls_verify = -1;
1926 char *tls_fingerprint = NULL;
1927 #endif
1928 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1929 pwmd_socket_t socktype;
1930 long socket_timeout = 300;
1931 int connect_timeout = 120;
1932 #endif
1933 #ifdef HAVE_LIBREADLINE
1934 int no_interactive = 0;
1935 #endif
1936 int lock_on_open = -1;
1937 long lock_timeout = 50;
1938 char *url = NULL;
1939 char *tmp = NULL;
1940 /* The order is important. */
1941 enum
1943 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1944 OPT_SOCKET_TIMEOUT, OPT_CONNECT_TIMEOUT,
1945 #endif
1946 #ifdef WITH_SSH
1947 OPT_USE_SSH_AGENT, OPT_IDENTITY, OPT_KNOWNHOSTS, OPT_SSH_NEEDS_PASSPHRASE,
1948 OPT_SSH_PASSPHRASE_FILE,
1949 #endif
1950 #ifdef WITH_GNUTLS
1951 OPT_CACERT, OPT_CLIENTCERT, OPT_CLIENTKEY, OPT_PRIORITY, OPT_VERIFY,
1952 OPT_SERVER_FP,
1953 #endif
1954 OPT_URL, OPT_LOCAL, OPT_TTYNAME, OPT_TTYTYPE, OPT_DISPLAY, OPT_LC_CTYPE,
1955 OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES, OPT_PINENTRY, OPT_KEYFILE,
1956 OPT_PASSPHRASE_FILE, OPT_NEW_KEYFILE, OPT_NEW_PASSPHRASE_FILE,
1957 OPT_SIGN_KEYFILE, OPT_SIGN_PASSPHRASE_FILE, OPT_NOLOCK, OPT_LOCK_TIMEOUT,
1958 OPT_SAVE, OPT_OUTPUT_FD, OPT_INQUIRE, OPT_INQUIRE_FD, OPT_INQUIRE_FILE,
1959 OPT_INQUIRE_LINE, OPT_NO_STATUS, OPT_STATUS_IGNORE, OPT_STATUSFD, OPT_NAME,
1960 OPT_VERSION, OPT_HELP, OPT_KEYID, OPT_SIGN_KEYID, OPT_SYMMETRIC,
1961 OPT_KEYPARAMS, OPT_NO_PINENTRY, OPT_QUIET, OPT_STATUS_STATE,
1962 #ifdef HAVE_LIBREADLINE
1963 OPT_NO_INTERACTIVE,
1964 #endif
1966 const struct option long_opts[] = {
1967 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1968 {"socket-timeout", 1, 0, 0},
1969 {"connect-timeout", 1, 0, 0},
1970 #endif
1972 #ifdef WITH_SSH
1973 {"no-ssh-agent", 0, 0, 0},
1974 {"identity", 1, 0, 'i'},
1975 {"knownhosts", 1, 0, 'k'},
1976 {"ssh-needs-passphrase", 0, 0, 0},
1977 {"ssh-passphrase-file", 1, 0, 0},
1978 #endif
1979 #ifdef WITH_GNUTLS
1980 {"ca-cert", 1, 0, 0},
1981 {"client-cert", 1, 0, 0},
1982 {"client-key", 1, 0, 0},
1983 {"tls-priority", 1, 0, 0},
1984 {"no-tls-verify", 0, 0, 0},
1985 {"tls-fingerprint", 1, 0, 0},
1986 #endif
1987 {"url", 1, 0, 0},
1988 {"local-pinentry", 0, 0},
1989 {"ttyname", 1, 0, 'y'},
1990 {"ttytype", 1, 0, 't'},
1991 {"display", 1, 0, 'd'},
1992 {"lc-ctype", 1, 0, 0},
1993 {"lc-messages", 1, 0, 0},
1994 {"timeout", 1, 0, 0},
1995 {"tries", 1, 0, 0},
1996 {"pinentry", 1, 0, 0},
1997 {"key-file", 1, 0, 0},
1998 {"passphrase-file", 1, 0, 0},
1999 {"new-key-file", 1, 0, 0},
2000 {"new-passphrase-file", 1, 0, 0},
2001 {"sign-key-file", 1, 0, 0},
2002 {"sign-passphrase-file", 1, 0, 0},
2003 {"no-lock", 0, 0, 0},
2004 {"lock-timeout", 1, 0, 0},
2005 {"save", 0, 0, 'S'},
2006 {"output-fd", 1, 0, 0},
2007 {"inquire", 1, 0, 0},
2008 {"inquire-fd", 1, 0, 0},
2009 {"inquire-file", 1, 0, 0},
2010 {"inquire-line", 1, 0, 'L'},
2011 {"no-status", 0, 0, 0},
2012 {"status-ignore", 1, 0, 0},
2013 {"status-fd", 1, 0, 0},
2014 {"name", 1, 0, 'n'},
2015 {"version", 0, 0, 0},
2016 {"help", 0, 0, 0},
2017 {"keyid", 1, 0, 0},
2018 {"sign-keyid", 1, 0, 0},
2019 {"symmetric", 0, 0, 0},
2020 {"key-params", 1, 0, 0},
2021 {"no-pinentry", 0, 0, 0},
2022 {"quiet", 0, 0, 0},
2023 {"status-state", 0, 0, 0},
2024 #ifdef HAVE_LIBREADLINE
2025 {"no-interactive", 0, 0},
2026 #endif
2027 {0, 0, 0, 0}
2029 #ifdef WITH_SSH
2030 const char *optstring = "L:y:t:d:P:I:Sn:i:k:s";
2031 #else
2032 const char *optstring = "L:y:t:d:P:I:Sn:s";
2033 #endif
2034 int opt_index = 0;
2036 #ifdef ENABLE_NLS
2037 setlocale (LC_ALL, "");
2038 bindtextdomain ("libpwmd", LOCALEDIR);
2039 #endif
2041 tries = DEFAULT_PIN_TRIES;
2042 inquirefd = STDIN_FILENO;
2043 statusfd = STDERR_FILENO;
2044 statusfp = stderr;
2045 tmp = pwmd_strdup (DEFAULT_STATUS_IGNORE);
2046 parse_status_ignore (tmp);
2047 pwmd_free (tmp);
2048 no_pinentry = -1;
2049 local_pin = -1;
2051 while ((opt =
2052 getopt_long (argc, argv, optstring, long_opts, &opt_index)) != -1)
2054 switch (opt)
2056 /* Handle long options without a short option part. */
2057 case 0:
2058 switch (opt_index)
2060 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2061 case OPT_SOCKET_TIMEOUT:
2062 socket_timeout = strtol (optarg, &p, 10);
2063 break;
2064 case OPT_CONNECT_TIMEOUT:
2065 connect_timeout = strtol (optarg, &p, 10);
2066 break;
2067 #endif
2068 #ifdef WITH_SSH
2069 case OPT_USE_SSH_AGENT:
2070 use_ssh_agent = 0;
2071 break;
2072 case OPT_SSH_NEEDS_PASSPHRASE:
2073 needs_passphrase = 1;
2074 break;
2075 case OPT_SSH_PASSPHRASE_FILE:
2076 ssh_passphrase_file = optarg;
2077 break;
2078 #endif
2079 #ifdef WITH_GNUTLS
2080 case OPT_CACERT:
2081 cacert = optarg;
2082 break;
2083 case OPT_CLIENTCERT:
2084 clientcert = optarg;
2085 break;
2086 case OPT_CLIENTKEY:
2087 clientkey = optarg;
2088 break;
2089 case OPT_PRIORITY:
2090 prio = optarg;
2091 break;
2092 case OPT_VERIFY:
2093 tls_verify = 0;
2094 break;
2095 case OPT_SERVER_FP:
2096 tls_fingerprint = optarg;
2097 break;
2098 #endif
2099 case OPT_SYMMETRIC:
2100 symmetric = 1;
2101 break;
2102 case OPT_KEYPARAMS:
2103 keyparams = optarg;
2104 break;
2105 case OPT_KEYFILE:
2106 case OPT_PASSPHRASE_FILE:
2107 keyfile = pwmd_strdup (optarg);
2108 break;
2109 case OPT_NEW_KEYFILE:
2110 case OPT_NEW_PASSPHRASE_FILE:
2111 new_keyfile = pwmd_strdup (optarg);
2112 break;
2113 case OPT_SIGN_KEYFILE:
2114 case OPT_SIGN_PASSPHRASE_FILE:
2115 sign_keyfile = pwmd_strdup (optarg);
2116 break;
2117 case OPT_NOLOCK:
2118 lock_on_open = 0;
2119 break;
2120 case OPT_LOCK_TIMEOUT:
2121 lock_timeout = strtol (optarg, &p, 10);
2122 break;
2123 case OPT_URL:
2124 url = optarg;
2125 break;
2126 case OPT_LOCAL:
2127 local_pin = 1;
2128 break;
2129 case OPT_LC_CTYPE:
2130 lcctype = pwmd_strdup (optarg);
2131 break;
2132 case OPT_LC_MESSAGES:
2133 lcmessages = pwmd_strdup (optarg);
2134 break;
2135 case OPT_TIMEOUT:
2136 timeout = strtol (optarg, &p, 10);
2137 break;
2138 case OPT_TRIES:
2139 tries = strtol (optarg, &p, 10);
2140 break;
2141 case OPT_INQUIRE:
2142 inquire = escape (optarg);
2143 break;
2144 case OPT_INQUIRE_FD:
2145 inquirefd = strtol (optarg, &p, 10);
2146 if (!p)
2148 inquirefp = fdopen (inquirefd, "r");
2149 if (!inquirefp)
2150 err (EXIT_FAILURE, "%i", inquirefd);
2152 break;
2153 case OPT_INQUIRE_FILE:
2154 inquirefd = open (optarg, O_RDONLY);
2155 if (inquirefd == -1)
2156 err (EXIT_FAILURE, "%s", optarg);
2157 inquirefp = fdopen (inquirefd, "r");
2158 break;
2159 case OPT_OUTPUT_FD:
2160 outfd = strtol (optarg, &p, 10);
2161 if (!p || !*p)
2163 outfp = fdopen (outfd, "w");
2164 if (!outfp)
2165 err (EXIT_FAILURE, "%i", outfd);
2167 break;
2168 case OPT_NO_STATUS:
2169 show_status = 0;
2170 break;
2171 case OPT_STATUSFD:
2172 statusfd = strtol (optarg, &p, 10);
2173 if (!p || !*p)
2175 statusfp = fdopen (statusfd, "w");
2176 if (!statusfp)
2177 err (EXIT_FAILURE, "%i", statusfd);
2179 break;
2180 case OPT_STATUS_IGNORE:
2181 parse_status_ignore (optarg);
2182 break;
2183 case OPT_VERSION:
2184 printf ("%s (pwmc)\n\n"
2185 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016\n"
2186 "%s\n"
2187 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
2188 "Compile-time features:\n"
2189 #ifdef HAVE_LIBREADLINE
2190 "+INTERACTIVE "
2191 #else
2192 "-INTERACTIVE "
2193 #endif
2194 #ifdef WITH_SSH
2195 "+SSH "
2196 #else
2197 "-SSH "
2198 #endif
2199 #ifdef WITH_GNUTLS
2200 "+GNUTLS "
2201 #else
2202 "-GNUTLS "
2203 #endif
2204 #ifdef WITH_PINENTRY
2205 "+PINENTRY "
2206 #else
2207 "-PINENTRY "
2208 #endif
2209 #ifdef WITH_QUALITY
2210 "+QUALITY "
2211 #else
2212 "-QUALITY "
2213 #endif
2214 #ifdef MEM_DEBUG
2215 "+MEM_DEBUG "
2216 #else
2217 "-MEM_DEBUG "
2218 #endif
2219 "\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
2220 exit (EXIT_SUCCESS);
2221 case OPT_PINENTRY:
2222 pinentry_path = optarg;
2223 break;
2224 case OPT_HELP:
2225 usage (argv[0], EXIT_SUCCESS);
2226 case OPT_KEYID:
2227 keyid = optarg;
2228 break;
2229 case OPT_SIGN_KEYID:
2230 sign_keyid = optarg;
2231 break;
2232 case OPT_QUIET:
2233 quiet = 1;
2234 show_status = 0;
2235 break;
2236 case OPT_STATUS_STATE:
2237 status_state = 1;
2238 break;
2239 case OPT_NO_PINENTRY:
2240 no_pinentry = 1;
2241 break;
2242 #ifdef HAVE_LIBREADLINE
2243 case OPT_NO_INTERACTIVE:
2244 no_interactive = 1;
2245 break;
2246 #endif
2247 default:
2248 usage (argv[0], EXIT_FAILURE);
2251 if (p && *p)
2253 fprintf (stderr, N_("%s: invalid argument for option '--%s'\n"),
2254 argv[0], long_opts[opt_index].name);
2255 usage (argv[0], EXIT_FAILURE);
2258 break;
2259 #ifdef WITH_SSH
2260 case 'i':
2261 identity = optarg;
2262 break;
2263 case 'k':
2264 knownhosts = optarg;
2265 break;
2266 #endif
2267 case 'L':
2268 inquire_line = optarg;
2269 break;
2270 case 'y':
2271 tty = optarg;
2272 break;
2273 case 't':
2274 ttytype = optarg;
2275 break;
2276 case 'd':
2277 display = optarg;
2278 break;
2279 case 'S':
2280 save = 1;
2281 break;
2282 case 'n':
2283 clientname = optarg;
2284 break;
2285 default:
2286 usage (argv[0], EXIT_FAILURE);
2290 #ifdef HAVE_LIBREADLINE
2291 if (isatty (STDIN_FILENO) && !inquire && !inquire_line && !no_interactive)
2292 interactive = 1;
2293 #endif
2295 pwmd_init ();
2296 rc = pwmd_new (clientname, &pwm);
2297 if (rc)
2298 goto done;
2300 filename = argv[optind] ? pwmd_strdup (argv[optind]) : NULL;
2301 if (no_pinentry != -1)
2302 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
2303 else
2304 rc = pwmd_getopt (pwm, PWMD_OPTION_NO_PINENTRY, &no_pinentry);
2305 if (rc)
2306 goto done;
2308 if (local_pin != -1)
2309 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local_pin);
2310 else
2311 rc = pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local_pin);
2312 if (rc)
2313 goto done;
2315 pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
2316 if (!quiet)
2317 fprintf (stderr, N_("Connecting ...\n"));
2319 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
2320 socktype = is_remote_url (url);
2321 if (socktype != PWMD_SOCKET_LOCAL)
2323 local_pin = 1;
2324 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2325 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, connect_timeout);
2326 if (rc)
2327 goto done;
2328 #endif
2330 if (socktype == PWMD_SOCKET_SSH)
2332 #ifdef WITH_SSH
2333 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_CB, knownhost_cb);
2334 if (rc)
2335 goto done;
2337 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_DATA, clientname);
2338 if (rc)
2339 goto done;
2341 if (use_ssh_agent == -1)
2342 rc = pwmd_getopt (pwm, PWMD_OPTION_SSH_AGENT, &use_ssh_agent);
2344 if (!rc)
2346 if (!getenv ("SSH_AUTH_SOCK") || identity)
2347 use_ssh_agent = 0;
2349 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_AGENT, use_ssh_agent);
2350 if (rc)
2351 goto done;
2353 else
2354 goto done;
2356 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_NEEDS_PASSPHRASE,
2357 needs_passphrase);
2358 if (rc)
2359 goto done;
2361 if (ssh_passphrase_file)
2363 struct stat st;
2364 int fd;
2366 if (stat (ssh_passphrase_file, &st) == -1)
2368 rc = gpg_error_from_syserror ();
2369 fprintf(stderr, "%s: %s\n", ssh_passphrase_file,
2370 gpg_strerror (rc));
2371 goto done;
2374 result = pwmd_calloc (1, st.st_size+1);
2375 if (!result)
2377 rc = GPG_ERR_ENOMEM;
2378 goto done;
2381 fd = open (ssh_passphrase_file, O_RDONLY);
2382 if (fd != -1)
2384 len = read (fd, result, st.st_size);
2385 if (len == st.st_size)
2386 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_PASSPHRASE, result);
2387 else
2388 rc = gpg_error_from_syserror ();
2390 close (fd);
2392 else
2393 rc = gpg_error_from_syserror ();
2395 pwmd_free (result);
2396 result = NULL;
2397 len = 0;
2399 if (rc)
2401 fprintf(stderr, "%s: %s\n", ssh_passphrase_file,
2402 gpg_strerror (rc));
2403 goto done;
2407 rc = pwmd_connect (pwm, url, identity, knownhosts);
2408 #endif
2410 #ifdef WITH_GNUTLS
2411 else
2413 if (tls_verify != -1)
2415 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_VERIFY, tls_verify);
2416 if (rc)
2417 goto done;
2420 if (prio)
2421 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_PRIORITY, prio);
2423 if (!rc)
2424 rc = pwmd_connect (pwm, url, clientcert, clientkey, cacert,
2425 tls_fingerprint);
2427 #endif
2429 else
2430 rc = pwmd_connect (pwm, url);
2431 #else
2432 rc = pwmd_connect (pwm, url);
2433 #endif
2434 if (rc)
2435 goto done;
2437 if (!quiet)
2438 fprintf (stderr, N_("Connected.\n"));
2440 connected = 1;
2441 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2442 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, socket_timeout);
2443 if (rc)
2444 goto done;
2445 #endif
2447 if (lock_timeout)
2449 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
2450 "OPTION LOCK-TIMEOUT=%li", lock_timeout);
2451 if (rc)
2452 goto done;
2455 if (status_state)
2457 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION CLIENT-STATE=1");
2458 if (rc)
2459 goto done;
2462 if (lock_on_open != -1)
2464 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCK_ON_OPEN, lock_on_open);
2465 if (rc)
2466 goto done;
2469 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, NULL, NULL);
2470 if (rc)
2471 goto done;
2473 if (timeout > 0)
2475 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
2476 if (rc)
2477 goto done;
2480 if (pinentry_path)
2482 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
2483 if (rc)
2484 goto done;
2487 if (display)
2489 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
2490 if (rc)
2491 goto done;
2494 if (tty)
2496 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, tty);
2497 if (rc)
2498 goto done;
2501 if (ttytype)
2503 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
2504 if (rc)
2505 goto done;
2508 if (lcctype)
2510 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
2511 if (rc)
2512 goto done;
2515 if (lcmessages)
2517 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES, lcmessages);
2518 if (rc)
2519 goto done;
2522 if (show_status)
2524 rc = pwmd_setopt (pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
2525 if (rc)
2526 goto done;
2529 if (filename)
2531 rc = open_command (filename);
2532 if (rc)
2533 goto done;
2536 #ifdef HAVE_LIBREADLINE
2537 if (interactive)
2539 rc = do_interactive ();
2540 result = NULL;
2541 goto do_exit;
2543 #endif
2545 if (inquire)
2547 struct inquire_s *inq = NULL;
2549 rc = set_inquire (inquirefd, inquire_line, &inq);
2550 if (!rc)
2551 rc = pwmd_command (pwm, &result, &len, inquire_cb, inq, "%s", inquire);
2553 free_inquire (inq);
2554 goto done;
2557 if (fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1)
2559 rc = gpg_error_from_errno (errno);
2560 goto done;
2563 ssize_t n;
2565 for (;;)
2567 rc = process_cmd ();
2569 if (rc)
2570 goto done;
2572 n = read (STDIN_FILENO, command, sizeof (command)-1);
2573 if (n == -1)
2575 if (errno == EAGAIN)
2577 usleep (100000);
2578 continue;
2581 rc = gpg_error_from_errno (errno);
2582 goto done;
2584 else if (!n)
2585 goto done;
2587 p = command;
2588 command[n] = 0;
2589 break;
2592 if (!p || !*p || !strcasecmp (p, "BYE"))
2593 goto done;
2596 struct inquire_s *inq = NULL;
2597 rc = set_inquire (inquirefd, inquire_line, &inq);
2598 if (!rc)
2600 rc = parse_dotcommand (command, &result, &len, inq);
2601 free_inquire (inq);
2604 if (rc)
2605 goto done;
2607 done:
2608 if (result)
2610 fwrite (result, 1, result[len - 1] == 0 ? len - 1 : len, outfp);
2611 fflush (outfp);
2612 pwmd_free (result);
2615 result = NULL;
2616 if (!rc)
2617 rc = finalize ();
2618 else if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
2619 (void) pwmd_command (pwm, &result, NULL, NULL, NULL,
2620 "GETINFO last_error");
2622 #ifdef HAVE_LIBREADLINE
2623 do_exit:
2624 #endif
2625 wipememory (command, 0, sizeof (command));
2627 if (rc && !quiet)
2628 show_error (pwm, rc, result);
2630 pwmd_close (pwm);
2631 reset_keyfiles ();
2632 pwmd_deinit ();
2633 pwmd_free (result);
2634 pwmd_free (filename);
2635 parse_status_ignore (NULL);
2636 if (connected && !quiet)
2637 fprintf (stderr, N_("Connection closed.\n"));
2639 exit (rc ? EXIT_FAILURE : EXIT_SUCCESS);