pwmc: Reset filename upon .open failure.
[libpwmd.git] / src / pwmc.c
blob808e756683e62ffe65273b4be25d76ecb67c638b
1 /*
2 Copyright (C) 2006-2016 Ben Kibbey <bjk@luxsci.net>
4 This file is part of libpwmd.
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 USA
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
95 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
96 ? gpg_error(rc) : rc
98 enum
100 SAVE_WHICH_SAVE,
101 SAVE_WHICH_PASSWD,
102 SAVE_WHICH_GENKEY
105 static int no_pinentry;
106 static pwm_t *pwm;
107 static char *filename;
108 static int save;
109 static char *keyid;
110 static char *sign_keyid;
111 static int symmetric;
112 static char *keyparams;
113 static char *keyfile;
114 static char *new_keyfile;
115 static char *sign_keyfile;
116 static int tries;
117 static int local_pin;
118 static int inquirefd;
119 static int statusfd;
120 FILE *statusfp;
121 static int quiet;
122 static char **status_ignore;
124 struct inquire_s
126 int fd;
127 char *line;
128 size_t len;
129 size_t size; // from stat(2).
130 char *last_keyword;
133 struct userid_s {
134 char *userid;
135 char *name;
136 char *email;
137 char *comment;
140 struct keyid_s {
141 char *keyid;
142 char *fpr;
143 char *grip;
144 char *card;
145 int can_sign;
146 int can_encrypt;
147 int can_certify;
148 int can_auth;
149 int expired;
150 time_t expires;
151 time_t created;
152 int secret;
153 int revoked;
154 int algo;
155 unsigned bits;
156 char *curve;
157 struct slist_s *userids;
158 struct slist_s *subkeys;
161 static gpg_error_t finalize ();
162 static gpg_error_t set_inquire (int fd, const char *line,
163 struct inquire_s **result);
164 static gpg_error_t parse_dotcommand (const char *line, char **result,
165 size_t * len, struct inquire_s *inq);
166 static gpg_error_t open_command (char *line);
168 static void
169 show_error (pwm_t *h, gpg_error_t rc, const char *str)
171 #ifdef WITH_GNUTLS
172 const char *tlsstr;
173 int e = pwmd_gnutls_error (h, &tlsstr);
175 if (e)
176 fprintf(stderr, "TLS: %s\n", tlsstr);
177 #else
178 (void)h;
179 #endif
180 fprintf (stderr, "ERR %i: %s%s%s%s", rc, gpg_strerror (rc),
181 str ? ": " : "", str ? str : "", str ? "" : "\n");
184 static void
185 reset_keyfiles ()
187 pwmd_free (keyfile);
188 pwmd_free (new_keyfile);
189 pwmd_free (sign_keyfile);
190 keyfile = new_keyfile = sign_keyfile = NULL;
193 static void
194 usage (const char *pn, int status)
196 fprintf (status == EXIT_FAILURE ? stderr : stdout,
197 N_("Usage: %s [options] [file]\n"
198 " --url <string>\n"
199 " a url string to connect to (%s, see below)\n"
200 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
201 " --connect-timeout <seconds>\n"
202 " seconds before connecting to a remote host fails (0=disabled, 120)\n"
203 " --socket-timeout <seconds>\n"
204 " seconds before a remote command fails (0=disabled, 300)\n"
205 #endif
206 #ifdef WITH_GNUTLS
207 " --ca-cert <filename>\n"
208 " certificate authority (CA) used to sign the server cert\n"
209 " --client-cert <filename>\n"
210 " client certificate to use for authentication\n"
211 " --client-key <filename>\n"
212 " key file used to protect the client certificate\n"
213 " --tls-priority <string>\n"
214 " compression, cipher and hash algorithm string\n"
215 " (SECURE256:SECURE192:SECURE128:-VERS-SSL3.0:-VERS-TLS1.0)\n"
216 " --no-tls-verify\n"
217 " disable verifying the hostname against the server certificate\n"
218 " --tls-fingerprint <string>\n"
219 " a SHA-256 hash of the server fingerprint to verify against\n"
220 #endif
221 #ifdef WITH_SSH
222 " --no-ssh-agent\n"
223 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
224 " --identity, -i <filename>\n"
225 " the ssh identity file to use for authentication\n"
226 " --knownhosts, -k <filename>\n"
227 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
228 " --ssh-needs-passphrase\n"
229 " prompt for a passphrase for the SSH identity file\n"
230 " --ssh-passphrase-file <filename>\n"
231 " read the SSH private key passphrase from filename\n"
232 #endif
233 " --no-lock\n"
234 " do not lock the data file upon opening it\n"
235 " --lock-timeout <N>\n"
236 " time in tenths of a second to wait for a locked data file (50)\n"
237 " --name, -n <string>\n"
238 " set the client name\n"
239 " --pinentry <path>\n"
240 " the full path to the pinentry binary\n"
241 " --local-pinentry\n"
242 " force using a local pinentry\n"
243 " --no-pinentry\n"
244 " disable pinentry both remotely and locally\n"
245 " --ttyname, -y <path>\n"
246 " tty that pinentry will use\n"
247 " --ttytype, -t <string>\n"
248 " pinentry terminal type (default is $TERM)\n"
249 " --display, -d\n"
250 " pinentry display (default is $DISPLAY)\n"
251 " --lc-ctype <string>\n"
252 " locale setting for pinentry\n"
253 " --lc-messages <string>\n"
254 " locale setting for pinentry\n"
255 " --tries <N>\n"
256 " number of pinentry tries before failing (3)\n"
257 " --timeout <seconds>\n"
258 " pinentry timeout\n"
259 " --inquire <COMMAND>\n"
260 " the specified command (with any options) uses a server inquire while\n"
261 " command data is read via the inquire file descriptor (stdin)\n"
262 " --inquire-line, -L <STRING>\n"
263 " the initial line to send (i.e., element path) before the inquire data\n"
264 " --inquire-fd <FD>\n"
265 " read inquire data from the specified file descriptor (stdin)\n"
266 " --inquire-file <filename>\n"
267 " read inquire data from the specified filename\n"
268 " --output-fd <FD>\n"
269 " redirect command output to the specified file descriptor\n"
270 " --save, -S\n"
271 " send the SAVE command before exiting\n"
272 " --passphrase-file <filename>\n"
273 " obtain the passphrase from the specified filename\n"
274 " --new-passphrase-file <filename>\n"
275 " obtain the passphrase to save with from the specified filename\n"
276 " --sign-passphrase-file <filename>\n"
277 " obtain the passphrase to sign with from the specified filename\n"
278 " --key-params <filename>\n"
279 " key parameters to use for key generation (pwmd default)\n"
280 " --keyid <recipient>[,<recipient>]\n"
281 " the public key ID to u\n"
282 " --sign-keyid <string>\n"
283 " the key ID to sign the data file with\n"
284 " --symmetric\n"
285 " use conventional encryption with optional signer(s) for new files\n"
286 " --no-status\n"
287 " disable showing of status messages from the server\n"
288 " --status-state\n"
289 " enable receiving of client STATE status messages\n"
290 " --status-fd <FD>\n"
291 " redirect status messages to the specified file descriptor\n"
292 " --status-ignore <string[,...]>\n"
293 " prevent parsing of the specified status message keywords\n"
294 " --quiet\n"
295 " disable showing of extra messages (implies --no-status)\n"
296 #ifdef HAVE_LIBREADLINE
297 " --no-interactive\n"
298 " disable interactive mode\n"
299 #endif
300 " --version\n"
301 " --help\n"),
303 #ifdef DEFAULT_PWMD_SOCKET
304 DEFAULT_PWMD_SOCKET
305 #else
306 "~/.pwmd/socket"
307 #endif
309 fprintf (status == EXIT_FAILURE ? stderr : stdout,
310 N_("\n"
311 "An optional url may be in the form of:\n"
312 " --url /path/to/socket\n"
313 " --url file://[/path/to/socket]\n"
314 #ifdef WITH_SSH
315 " or\n"
316 " --url ssh[46]://[username@]hostname[:port] (uses ssh-agent)\n"
317 " -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
318 #endif
319 #ifdef WITH_GNUTLS
320 " or\n"
321 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
322 " --client-key filename\n"
323 #endif
324 #ifdef HAVE_LIBREADLINE
325 "\n"
326 "Interactive mode is used when input is from a terminal.\n"
327 #endif
329 exit (status);
332 static gpg_error_t
333 inquire_cb (void *user, const char *keyword, gpg_error_t rc,
334 char **data, size_t * size)
336 struct inquire_s *inq = user;
337 int is_password = 0;
338 int is_newpassword = 0;
339 int sign = 0;
340 int is_keyparam = 0;
342 *data = NULL;
343 *size = 0;
345 if (rc)
346 return rc;
348 if (!strcmp (keyword, "PASSPHRASE"))
349 is_password = 1;
350 else if (!strcmp (keyword, "SIGN_PASSPHRASE"))
351 sign = 1;
352 else if (!strcmp (keyword, "NEW_PASSPHRASE"))
353 is_newpassword = 1;
354 #ifdef HAVE_LIBREADLINE
355 else if (!strcmp (keyword, "KEYPARAM") && !interactive)
357 #else
358 else if (!strcmp (keyword, "KEYPARAM"))
360 #endif
361 int fd;
362 if (!keyparams || !*keyparams)
363 return gpg_error (GPG_ERR_INV_PARAMETER);
365 fd = open (keyparams, O_RDONLY);
366 if (fd == -1)
368 fprintf (stderr, "%s: %s\n", keyparams, strerror (errno));
369 return gpg_error_from_syserror ();
372 rc = set_inquire (fd, NULL, &inq);
373 if (rc)
375 close (fd);
376 return rc;
379 if (!quiet)
380 fprintf (stderr, N_("Using file '%s' as %s.\n"), keyparams, keyword);
382 is_keyparam = 1;
385 if ((is_password && !keyfile) || (is_newpassword && !new_keyfile)
386 || (sign && !sign_keyfile))
388 char *tmp;
389 int local;
391 /* Try to use the local pinentry between inquires (new/sign/passphrase).
392 * If --no-pinentry was specified then the passphrase is read from the
393 * terminal as usual. */
394 pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local);
395 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, 1);
396 rc = pwmd_password (pwm, keyword, &tmp, &inq->len);
397 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local);
398 if (rc && gpg_err_code (rc) != GPG_ERR_EOF)
399 return rc;
401 pwmd_free (inq->line);
402 inq->line = tmp;
403 *data = inq->line;
404 *size = inq->len;
405 return gpg_error (GPG_ERR_EOF);
407 else if ((is_newpassword && new_keyfile) || (is_password && keyfile)
408 || (sign && sign_keyfile))
410 int fd;
412 if (sign)
413 fd = open (sign_keyfile, O_RDONLY);
414 else
415 fd = open (is_password || sign ? keyfile : new_keyfile, O_RDONLY);
417 if (fd == -1)
419 if (sign)
420 fprintf (stderr, "%s: %s\n", sign_keyfile, strerror (errno));
421 else
422 fprintf (stderr, "%s: %s\n", is_newpassword ? new_keyfile
423 : keyfile, strerror (errno));
424 return gpg_error_from_syserror ();
427 rc = set_inquire (fd, NULL, &inq);
428 if (rc)
430 close (fd);
431 return rc;
434 if (!quiet)
435 fprintf (stderr, N_("Using keyfile '%s' as %s.\n"),
436 sign ? sign_keyfile : is_newpassword ? new_keyfile
437 : keyfile, keyword);
439 #ifdef HAVE_LIBREADLINE
440 else if ((!inq->last_keyword || strcmp (keyword, inq->last_keyword))
441 && interactive && inq->fd == STDIN_FILENO)
443 fprintf (stderr,
445 ("%sPress CTRL-D to send the current line. Press twice to end. %s:\n"),
446 inq->last_keyword ? "\n" : "", keyword);
447 pwmd_free (inq->last_keyword);
448 inq->last_keyword = pwmd_strdup (keyword);
450 #endif
452 /* The first part of the command data. */
453 if (inq->len)
455 *data = inq->line;
456 *size = inq->len;
457 inq->len = 0;
458 return inq->fd == -1 ? gpg_error (GPG_ERR_EOF) : 0;
461 *size = read (inq->fd, inq->line, ASSUAN_LINELENGTH);
462 if (*size == -1)
464 *size = 0;
465 return gpg_error (gpg_error_from_syserror ());
467 else if (*size)
468 *data = inq->line;
469 else if (inq->fd != STDIN_FILENO &&
470 (is_newpassword || is_password || sign || is_keyparam))
472 *inq->line = 0;
473 inq->size = 1;
474 *data = inq->line;
475 *size = 1;
478 if (((is_newpassword && new_keyfile) || (is_password && keyfile)
479 || (sign && sign_keyfile) || (keyparams && is_keyparam))
480 && *size == inq->size)
481 return gpg_error (GPG_ERR_EOF);
483 return *size ? 0 : gpg_error (GPG_ERR_EOF);
486 static int
487 status_msg_cb (void *data, const char *line)
489 char *p = strchr (line, ' ');
490 char **s;
492 (void)data;
494 /* Ignore status messages specified by the client via --status-ignore. */
495 for (s = status_ignore; s && *s; s++)
497 char *tmp = strchr (line, ' ');
498 size_t len = tmp ? strlen (line) - strlen (tmp) : strlen (line);
500 if (!strncmp (line, *s, len) && len == strlen (*s))
501 return 0;
504 #ifdef HAVE_LIBREADLINE
505 if (interactive && !strncmp (line, "XFER ", 5)
506 #else
507 if (!strncmp (line, "XFER ", 5)
508 #endif
509 && *line != '#' && p && strchr (p, ' ') && *++p)
511 char *p1 = strchr (p, ' ');
512 int a = strtol (p, NULL, 10);
514 if (isdigit (*p) && p1)
516 int b = strtol (p1, NULL, 10);
517 char l[64] = { 0 };
518 int t = a && b ? a * 100 / b : 0;
520 strncpy (l, line, strlen (line) - strlen (p) - 1);
521 fprintf (statusfp, "\rS:%s %i/%i %i%%%s", l, a, b, t,
522 a == b ? "\n" : "");
523 fflush (statusfp);
524 return 0;
528 fprintf (statusfp, "S:%s\n", line);
529 fflush (statusfp);
530 #ifdef HAVE_LIBREADLINE
531 rl_on_new_line ();
532 #endif
533 return 0;
536 static gpg_error_t
537 process_cmd ()
539 return pwmd_process (pwm);
542 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
543 static pwmd_socket_t
544 is_remote_url (const char *str)
546 if (!str)
547 return PWMD_SOCKET_LOCAL;
549 #ifdef WITH_SSH
550 if (strstr (str, "ssh://") || strstr (str, "ssh4://")
551 || strstr (str, "ssh6://"))
552 return PWMD_SOCKET_SSH;
553 #endif
555 #ifdef WITH_GNUTLS
556 if (strstr (str, "tls://") || strstr (str, "tls4://")
557 || strstr (str, "tls6://"))
558 return PWMD_SOCKET_TLS;
559 #endif
561 return PWMD_SOCKET_LOCAL;
563 #endif
565 static char *
566 escape (const char *str)
568 const char *p;
569 char *buf = pwmd_malloc (ASSUAN_LINELENGTH + 1), *b = buf;
570 size_t len = 0;
572 for (p = str; *p; p++, len++)
574 if (len == ASSUAN_LINELENGTH)
575 break;
577 if (*p == '\\')
579 switch (*++p)
581 case 't':
582 *b++ = '\t';
583 break;
584 case 'n':
585 *b++ = '\n';
586 break;
587 case 'v':
588 *b++ = '\v';
589 break;
590 case 'b':
591 *b++ = '\b';
592 break;
593 case 'f':
594 *b++ = '\f';
595 break;
596 case 'r':
597 *b++ = '\r';
598 break;
599 default:
600 *b++ = *p;
601 break;
604 if (!*p)
605 break;
607 continue;
610 *b++ = *p;
613 *b = 0;
614 return buf;
617 static void
618 free_inquire (struct inquire_s *inq)
620 if (!inq)
621 return;
623 pwmd_free (inq->line);
625 if (inq->fd != -1 && inq->fd != STDIN_FILENO)
626 close (inq->fd);
628 pwmd_free (inq->last_keyword);
629 pwmd_free (inq);
632 /* When *result is not NULL it is updated to the new values and not
633 * reallocated. */
634 static gpg_error_t
635 set_inquire (int fd, const char *line, struct inquire_s **result)
637 struct inquire_s inq = { 0 };
638 struct stat st = { 0 };
639 gpg_error_t rc;
641 if (fd != -1)
643 if (fstat (fd, &st) == -1)
644 return gpg_error_from_syserror ();
646 inq.size = st.st_size;
649 inq.fd = fd;
650 inq.line = pwmd_calloc (1, ASSUAN_LINELENGTH);
651 if (!inq.line)
652 return GPG_ERR_ENOMEM;
654 if (line)
656 char *s = escape (line);
658 if (!s)
660 pwmd_free (inq.line);
661 return GPG_ERR_ENOMEM;
664 if (strlen (s) >= ASSUAN_LINELENGTH)
666 pwmd_free (inq.line);
667 pwmd_free (s);
668 return GPG_ERR_LINE_TOO_LONG;
671 strncpy (inq.line, s, ASSUAN_LINELENGTH - 1);
672 inq.len = strlen (s);
673 pwmd_free (s);
676 rc = pwmd_setopt (pwm, PWMD_OPTION_INQUIRE_TOTAL,
677 st.st_size ? st.st_size + strlen (inq.line) : 0);
678 if (rc)
680 pwmd_free (inq.line);
681 return rc;
684 if (*result == NULL)
685 *result = pwmd_malloc (sizeof (struct inquire_s));
686 else
688 if ((*result)->fd != -1 && (*result)->fd != STDIN_FILENO)
689 close ((*result)->fd);
691 pwmd_free ((*result)->line);
692 (*result)->line = NULL;
693 (*result)->fd = -1;
694 (*result)->len = 0;
697 memcpy (*result, &inq, sizeof (struct inquire_s));
698 memset (&inq, 0, sizeof (struct inquire_s));
699 return rc;
702 #ifdef HAVE_LIBREADLINE
703 static int
704 interactive_hook (void)
706 interactive_error = process_cmd ();
708 if (interactive_error)
709 rl_event_hook = NULL;
711 return 0;
714 static int
715 get_readline_char (FILE *fp)
717 if (rl_line_buffer
718 && (!strncmp (rl_line_buffer, ".set passphrase-file ", 16)
719 || !strncmp (rl_line_buffer, ".set new-passphrase-file ", 20)
720 || !strncmp (rl_line_buffer, ".set sign-passphrase-file ", 21)))
721 rl_inhibit_completion = 0;
722 else if (rl_line_buffer
723 && !strncmp (rl_line_buffer, ".redir ", 7))
725 char *p = strchr (rl_line_buffer, ' ');
727 if (p && strchr (++p, ' '))
728 rl_inhibit_completion = 1;
729 else
730 rl_inhibit_completion = 0;
732 else if (rl_line_buffer
733 && !strncmp (rl_line_buffer, ".read ", 6))
735 char *p = rl_line_buffer + 6;
737 if (strstr (p, "--prefix "))
739 p = strstr (p, "--prefix ");
740 p += 9;
741 p = strchr (p, ' ');
742 if (p)
743 p++;
746 if (!p || strchr (p, ' '))
747 rl_inhibit_completion = 1;
748 else
749 rl_inhibit_completion = 0;
751 else
752 rl_inhibit_completion = 1;
754 return fgetc (fp);
757 static void
758 print_help ()
760 fprintf (stderr,
762 ("------------------------------------------------------------\n"
763 "Elements are TAB delimited. Type HELP for protocol commands.\n"
764 "Type .help for pwmc commands. Press CTRL-D to quit.\n"
765 "------------------------------------------------------------\n"));
767 #endif
769 static char *
770 parse_arg (const char *src, char *dst, size_t len)
772 char *p = dst;
773 const char *s = src;
774 size_t n = 0;
776 for (; s && *s && *s != ' ' && n < len; s++, n++)
777 *p++ = *s;
779 *p = 0;
780 return dst;
783 static char *
784 parse_opt (char **line, const char *opt, gpg_error_t * rc)
786 static char result[ASSUAN_LINELENGTH] = { 0 }, *r = result;
787 char *s = strstr (*line, opt);
789 *rc = 0;
790 result[0] = 0;
791 r = result;
793 if (s)
795 size_t len = 0;
796 int quote = 0;
797 size_t rlen = strlen (opt);
798 char *p = s + rlen;
799 int lastc = 0;
801 while (*p && *p == ' ')
803 rlen++;
804 p++;
807 for (; *p && len < sizeof (result) - 1; p++, rlen++)
809 if (isspace (*p) && !quote)
810 break;
812 if (*p == '\"' && lastc != '\\')
814 quote = !quote;
815 lastc = *p;
816 continue;
819 *r++ = lastc = *p;
820 len++;
823 *r = 0;
825 if (len >= sizeof (result) - 1)
826 *rc = GPG_ERR_LINE_TOO_LONG;
827 else
829 p = s + rlen;
831 while (*p && *p == ' ')
832 p++;
834 *line = p;
838 return result;
841 static gpg_error_t
842 read_command (const char *line, char **result, size_t * len)
844 int fd;
845 gpg_error_t rc = 0;
846 char *file = NULL;
847 struct inquire_s *inq = NULL;
848 char *p = (char *) line;
849 const char *prefix = parse_opt (&p, "--prefix", &rc);
850 char filebuf[ASSUAN_LINELENGTH];
852 if (rc)
853 return rc;
855 rc = GPG_ERR_SYNTAX;
857 if (p && *p)
859 while (*p && isspace (*p))
860 p++;
862 file = parse_arg (p, filebuf, sizeof (filebuf));
863 if (file && *file)
865 p += strlen (file) + 1;
867 while (*p && isspace (*p))
868 p++;
870 if (*p)
871 rc = 0;
875 if (rc)
877 fprintf (stderr,
879 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
880 fprintf (stderr,
882 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\\ = \\)\n"));
883 return rc;
886 fd = open (file, O_RDONLY);
887 if (fd == -1)
888 return gpg_error_from_syserror ();
890 rc = set_inquire (fd, prefix && *prefix ? prefix : NULL, &inq);
891 if (rc)
893 close (fd);
894 return rc;
897 rc = pwmd_command (pwm, result, len, inquire_cb, inq, "%s", p);
898 free_inquire (inq);
899 return rc;
902 static gpg_error_t
903 redir_command (const char *line)
905 const char *p = line;
906 int fd;
907 gpg_error_t rc = GPG_ERR_SYNTAX;
908 char *file = NULL;
909 struct inquire_s *inq = NULL;
910 char *result = NULL;
911 size_t len = 0;
912 char filebuf[ASSUAN_LINELENGTH];
914 if (p && *p && *++p)
916 file = parse_arg (p, filebuf, sizeof (filebuf));
917 if (file && *file)
919 p += strlen (file) + 1;
921 while (*p && isspace (*p))
922 p++;
924 if (*p)
925 rc = 0;
929 if (rc)
931 fprintf (stderr, N_("Usage: .redir <filename> <command> [args]\n"));
932 return rc;
935 fd = open (file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
936 if (fd == -1)
937 return gpg_error_from_syserror ();
939 #ifdef HAVE_LIBREADLINE
940 rc = set_inquire (interactive ? STDIN_FILENO : inquirefd, NULL, &inq);
941 #else
942 rc = set_inquire (inquirefd, NULL, &inq);
943 #endif
944 if (rc)
946 close (fd);
947 return rc;
950 rc = parse_dotcommand (p, &result, &len, inq);
951 if (!rc && result && len--)
952 { // null byte which is always appended
953 if (write (fd, result, len) != len)
954 rc = GPG_ERR_TOO_SHORT;
955 pwmd_free (result);
958 free_inquire (inq);
959 close (fd);
960 return rc;
963 static gpg_error_t
964 help_command (const char *line)
966 (void)line;
967 fprintf (stderr,
968 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
969 " .redir <filename> <command>\n"
970 " redirect the output of a command to the specified file\n"
971 "\n"
972 " .open <filename>\n"
973 " open the specified filename losing any changes to the current one\n"
974 "\n"
975 " .read [--prefix <string>] <filename> <command> [args]\n"
976 " obtain data from the specified filename for an inquire command\n"
977 "\n"
978 " .set help | <name> [<value>]\n"
979 " set option <name> to <value>\n"
980 "\n"
981 " .genkey [args]\n"
982 " generate a new key\n"
983 "\n"
984 " .save [args]\n"
985 " write changes of the file to disk\n"
986 "\n"
987 " .passwd [args]\n"
988 " change the passphrase of a data file\n"
989 "\n"
990 " .listkeys [--options] [pattern[,..]]\n"
991 " show human readable output of the LISTKEYS command\n"
992 "\n"
993 " .help\n"
994 " this help text\n"));
995 return 0;
998 static gpg_error_t
999 open_command (char *line)
1001 struct inquire_s *inq = NULL;
1002 char *file = line;
1003 gpg_error_t rc;
1004 int local;
1006 while (file && isspace (*file))
1007 file++;
1009 if (file && *file)
1011 char *p = strrchr (file, ' ');
1013 if (p)
1015 while (isspace (*p))
1016 p++;
1018 file = pwmd_strdup (file + (strlen (file)-strlen (p)));
1022 if (!file || !*file)
1024 pwmd_free (file);
1025 fprintf (stderr, N_("Usage: .open <filename>\n"));
1026 return GPG_ERR_SYNTAX;
1029 #ifdef HAVE_LIBREADLINE
1030 if (interactive || !quiet)
1031 #else
1032 if (!quiet)
1033 #endif
1034 fprintf (stderr, N_("Opening data file \"%s\" ...\n"), file);
1036 #ifdef HAVE_LIBREADLINE
1037 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1038 #else
1039 rc = set_inquire (-1, NULL, &inq);
1040 #endif
1041 if (rc)
1043 pwmd_free (file);
1044 return rc;
1047 pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local);
1049 if (keyfile)
1051 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1052 if (!rc)
1053 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, 1);
1055 else
1056 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1058 if (!rc)
1059 rc = pwmd_open (pwm, file, inquire_cb, inq);
1061 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local);
1063 #ifdef HAVE_LIBREADLINE
1064 if (interactive)
1065 reset_keyfiles ();
1066 #endif
1068 free_inquire (inq);
1069 if (!rc && file != filename)
1071 pwmd_free (filename);
1072 filename = file;
1074 else if (rc)
1076 pwmd_free (filename);
1077 filename = NULL;
1080 return rc;
1083 static gpg_error_t
1084 set_command (const char *line)
1086 gpg_error_t rc = 0;
1087 char name[256] = { 0 };
1088 char value[512] = { 0 };
1089 char *namep;
1090 char *valuep;
1091 const char *p = line;
1093 while (p && *p && isspace (*p))
1094 p++;
1096 namep = parse_arg (p, name, sizeof (name));
1097 if (!namep || !*namep)
1099 fprintf (stderr, N_("Usage: .set help | <name> [<value>]\n"));
1100 return GPG_ERR_SYNTAX;
1103 p += strlen (namep);
1104 while (p && *p && isspace (*p))
1105 p++;
1107 valuep = parse_arg (p, value, sizeof (value));
1109 if (!strcmp (name, "passphrase-file") || !strcmp (name, "new-passphrase-file")
1110 || !strcmp (name, "sign-passphrase-file"))
1112 int is_newkeyfile = 1;
1113 int sign = !strcmp (name, "sign-passphrase-file");
1115 if (!strcmp (name, "passphrase-file") || sign)
1116 is_newkeyfile = 0;
1118 if (is_newkeyfile)
1120 pwmd_free (new_keyfile);
1121 new_keyfile = NULL;
1123 else if (sign)
1125 pwmd_free (sign_keyfile);
1126 sign_keyfile = NULL;
1128 else
1130 pwmd_free (keyfile);
1131 keyfile = NULL;
1134 if (!rc && *valuep)
1136 if (is_newkeyfile)
1137 new_keyfile = pwmd_strdup (value);
1138 else if (sign)
1139 sign_keyfile = pwmd_strdup (value);
1140 else
1141 keyfile = pwmd_strdup (value);
1143 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1145 else if (!local_pin && !no_pinentry)
1147 pwmd_socket_t t;
1149 pwmd_socket_type (pwm, &t);
1150 if (t == PWMD_SOCKET_LOCAL)
1151 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1154 else if (!strcmp(name, "pinentry-timeout"))
1156 char *e = NULL;
1157 int n = strtol(valuep, &e, 10);
1159 if (e && *e)
1160 return gpg_error (GPG_ERR_INV_VALUE);
1162 if (!*valuep)
1163 n = DEFAULT_PIN_TIMEOUT;
1165 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, n);
1167 else if (!strcmp (name, "help"))
1169 fprintf (stderr,
1171 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1172 "delimited. When no value is specified the option is unset.\n\n"
1173 "passphrase-file [<filename>]\n"
1174 " set or unset the file to be used when a passphrase is required (*)\n"
1175 "\n"
1176 "new-passphrase-file [<filename>]\n"
1177 " set or unset the file to be used when a new passphrase is required (*)\n"
1178 "\n"
1179 "sign-passphrase-file [<filename>]\n"
1180 " set or unset the file to be used when a passphrase is required for\n"
1181 " signing (symmetric) (*)\n"
1182 "\n"
1183 "pinentry-timeout <seconds>\n"
1184 " the amount of seconds before pinentry gives up waiting for input\n"
1185 "\n"
1186 "* = the next protocol command will unset this value\n"
1189 else
1190 rc = GPG_ERR_UNKNOWN_OPTION;
1192 return rc;
1195 static gpg_error_t
1196 do_save_passwd_command (const char *line, int which)
1198 struct inquire_s *inq = NULL;
1199 gpg_error_t rc;
1200 int local;
1202 #ifdef HAVE_LIBREADLINE
1203 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1204 #else
1205 rc = set_inquire (-1, NULL, &inq);
1206 #endif
1207 if (rc)
1208 return rc;
1210 pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local);
1212 if (new_keyfile || keyfile || sign_keyfile)
1214 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1215 if (!rc)
1216 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, 1);
1218 else
1219 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1221 if (!rc)
1223 if (which == SAVE_WHICH_SAVE)
1224 rc = pwmd_save (pwm, line, inquire_cb, inq);
1225 else if (which == SAVE_WHICH_PASSWD)
1226 rc = pwmd_passwd (pwm, line, inquire_cb, inq);
1227 else
1228 rc = pwmd_genkey (pwm, line, inquire_cb, inq);
1231 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local);
1233 #ifdef HAVE_LIBREADLINE
1234 if (interactive)
1235 reset_keyfiles ();
1236 #endif
1238 free_inquire (inq);
1239 return rc;
1242 static gpg_error_t
1243 save_command (const char *line)
1245 return do_save_passwd_command (line, SAVE_WHICH_SAVE);
1248 static void
1249 search_and_replace (char *str, const char *s, const char r)
1251 char *p;
1253 p = strstr (str, s);
1254 if (p)
1256 *p = r;
1257 while (*++p)
1258 *p = *(p+1);
1259 search_and_replace (str, s, r);
1260 return;
1264 static char *
1265 openpgp_unescape (char *str)
1267 search_and_replace (str, "\\x3a", ':');
1268 search_and_replace (str, "\\x5c", '\\');
1269 return str;
1272 static void
1273 free_listkeys (struct slist_s *keys)
1275 unsigned i, t;
1277 t = slist_length (keys);
1278 for (i = 0; i < t; i++)
1280 struct keyid_s *key = slist_nth_data (keys, i);
1281 unsigned n, nt;
1283 nt = slist_length (key->userids);
1284 for (n = 0; n < nt; n++)
1286 struct userid_s *userid = slist_nth_data (key->userids, n);
1288 pwmd_free (userid->userid);
1289 pwmd_free (userid->name);
1290 pwmd_free (userid->email);
1291 pwmd_free (userid->comment);
1292 pwmd_free (userid);
1295 slist_free (key->userids);
1296 nt = slist_length (key->subkeys);
1297 for (n = 0; n < nt; n++)
1299 struct keyid_s *sub = slist_nth_data (key->subkeys, n);
1301 pwmd_free (sub->keyid);
1302 pwmd_free (sub->fpr);
1303 pwmd_free (sub->grip);
1304 pwmd_free (sub->card);
1305 pwmd_free (sub->curve);
1306 pwmd_free (sub);
1309 slist_free (key->subkeys);
1310 pwmd_free (key);
1313 slist_free (keys);
1316 static const char *
1317 openpgp_algorithm (struct keyid_s *key)
1319 switch (key->algo)
1321 case 1:
1322 case 2:
1323 case 3:
1324 return "RSA";
1325 case 16:
1326 case 20:
1327 return "ELG";
1328 case 17:
1329 return "DSA";
1330 case 301:
1331 case 302:
1332 case 18:
1333 return "ECC";
1334 default:
1335 break;
1338 return N_("Unknown");
1341 static void
1342 display_listkeys (struct slist_s *keys)
1344 unsigned i, t;
1346 t = slist_length (keys);
1347 for (i = 0; i < t; i++)
1349 struct keyid_s *key = slist_nth_data (keys, i);
1350 unsigned st = slist_length (key->subkeys);
1351 unsigned s;
1352 unsigned ut = slist_length (key->userids);
1353 unsigned u;
1355 for (u = 0; u < ut; u++)
1357 struct userid_s *userid = slist_nth_data (key->userids, u);
1359 fprintf(stdout, N_("User ID: %s\n"), userid->userid);
1362 for (s = 0; s < st; s++)
1364 struct keyid_s *sub = slist_nth_data (key->subkeys, s);
1365 struct tm *tmp;
1366 const char *caps = NULL;
1367 char expires[11] = { 0 };
1368 char created[11] = { 0 };
1370 if (sub->expires)
1372 tmp = localtime (&sub->expires);
1373 strftime (expires, sizeof (expires), "%F", tmp);
1376 tmp = localtime (&sub->created);
1377 strftime (created, sizeof (created), "%F", tmp);
1379 if (sub->can_encrypt)
1380 caps = "E";
1381 else if (sub->can_sign)
1382 caps = "S";
1383 else if (sub->can_auth)
1384 caps = "A";
1385 else if (sub->can_certify)
1386 caps = "C";
1388 fprintf(stdout, N_(
1389 " Subkey %u: %s [%s]%s%s %s-%u%s%s\n"
1390 " Created: %s %s%s\n"
1391 " Fingerprint: %s\n"
1392 " Keygrip: %s\n"
1393 "%s%s%s"),
1394 s+1,
1395 sub->keyid,
1396 caps,
1397 sub->secret || sub->card ? "[P]" : "",
1398 sub->revoked ? "[R]" : "",
1399 openpgp_algorithm (sub),
1400 sub->bits,
1401 sub->curve ? "-" : "",
1402 sub->curve ? sub->curve : "",
1403 created,
1404 sub->expired ? N_("Expired: ") : expires[0] ? N_("Expires: ") : "",
1405 sub->expired || expires[0] ? expires : "",
1406 sub->fpr,
1407 sub->grip,
1408 sub->card ? N_(" Card: ") : "",
1409 sub->card ? sub->card : "",
1410 sub->card ? "\n" : "");
1413 if (i+1 < t)
1414 fprintf (stdout, "\n");
1418 static gpg_error_t
1419 listkeys_command (const char *pattern)
1421 gpg_error_t rc;
1422 char *result;
1423 char **lines = NULL, **p;
1424 struct slist_s *keys = NULL;
1426 rc = pwmd_command (pwm, &result, NULL, NULL, NULL, "LISTKEYS %s", pattern);
1427 if (rc)
1428 return rc;
1430 lines = str_split (result, "\n", 0);
1431 pwmd_free (result);
1432 if (!lines)
1433 return GPG_ERR_ENOMEM;
1435 for (p = lines; *p; p++)
1437 struct keyid_s *key;
1438 char **fields = str_split (*p, ":", 0);
1439 int i, f;
1440 unsigned s;
1441 unsigned n_subkeys = 0;
1442 struct slist_s *tlist;
1444 if (!fields)
1446 rc = GPG_ERR_ENOMEM;
1447 break;
1450 key = pwmd_calloc (1, sizeof (struct keyid_s));
1451 if (!key)
1453 strv_free (fields);
1454 rc = GPG_ERR_ENOMEM;
1455 break;
1458 for (f = i = 0; i < 17; i++, f++)
1460 int b = 0;
1462 if (i < 10)
1463 b = atoi (fields[f]) != 0;
1465 switch (i)
1467 case 0: key->revoked = b; break;
1468 case 1: key->expired = b; break;
1469 case 4: key->can_encrypt = b; break;
1470 case 5: key->can_sign = b; break;
1471 case 7: key->secret = b; break;
1472 case 16: n_subkeys = strtoul (fields[f], NULL, 10); break;
1473 default:
1474 break;
1478 for (s = 0; s < n_subkeys; s++)
1480 struct keyid_s *sub;
1481 int b = 0;
1483 sub = pwmd_calloc (1, sizeof (struct keyid_s));
1484 if (!sub)
1486 strv_free (fields);
1487 rc = GPG_ERR_ENOMEM;
1488 break;
1491 for (i = 0; i < 20; i++, f++)
1493 if (i < 11)
1494 b = atoi (fields[f]) != 0;
1496 switch (i)
1498 case 0: sub->revoked = b; break;
1499 case 1: sub->expired = b; break;
1500 case 4: sub->can_encrypt = b; break;
1501 case 5: sub->can_sign = b; break;
1502 case 6: sub->can_certify = b; break;
1503 case 7: sub->secret = b; break;
1504 case 8: sub->can_auth = b; break;
1505 case 11: sub->algo = atoi (fields[f]); break;
1506 case 12: sub->bits = atoi (fields[f]); break;
1507 case 13: sub->keyid = pwmd_strdup (fields[f]); break;
1508 case 14: sub->fpr = pwmd_strdup (fields[f]); break;
1509 case 15: sub->grip = pwmd_strdup (fields[f]); break;
1510 case 16: sub->created = strtoul (fields[f], NULL, 10); break;
1511 case 17: sub->expires = strtoul (fields[f], NULL, 10); break;
1512 case 18: sub->card = fields[f] && strlen(fields[f]) > 1
1513 ? pwmd_strdup (fields[f]) : NULL; break;
1514 case 19: sub->curve = strlen (fields[f]) > 1 ? pwmd_strdup (openpgp_unescape(fields[f])) : NULL; break;
1515 default:
1516 break;
1520 tlist = slist_append (key->subkeys, sub);
1521 if (!tlist)
1523 rc = GPG_ERR_ENOMEM;
1524 break;
1527 key->subkeys = tlist;
1530 if (rc)
1532 strv_free (fields);
1533 break;
1536 // Re-create a line containing the userIds.
1537 for (; f < strv_length (fields); f++)
1539 struct userid_s *userid;
1541 userid = pwmd_calloc (1, sizeof (struct userid_s));
1542 if (!userid)
1544 rc = GPG_ERR_ENOMEM;
1545 break;
1548 // Revoked.
1549 f++;
1550 // Invalid.
1551 f++;
1552 // Validity.
1553 f++;
1555 userid->userid = pwmd_strdup (openpgp_unescape (fields[f++]));
1556 userid->name = pwmd_strdup (openpgp_unescape (fields[f++]));
1557 userid->email = pwmd_strdup (openpgp_unescape (fields[f++]));
1558 userid->comment = pwmd_strdup (openpgp_unescape (fields[f]));
1560 tlist = slist_append (key->userids, userid);
1561 if (!tlist)
1563 rc = GPG_ERR_ENOMEM;
1564 break;
1567 key->userids = tlist;
1570 strv_free (fields);
1571 if (rc)
1572 break;
1574 tlist = slist_append (keys, key);
1575 if (!tlist)
1577 rc = GPG_ERR_ENOMEM;
1578 break;
1581 keys = tlist;
1584 strv_free (lines);
1586 if (!rc)
1587 display_listkeys (keys);
1589 free_listkeys (keys);
1590 return rc;
1593 static gpg_error_t
1594 parse_dotcommand (const char *line, char **result,
1595 size_t * len, struct inquire_s *inq)
1597 const char *p = line;
1598 gpg_error_t rc = 0;
1600 if (!strncmp (p, ".read", 5))
1601 rc = read_command (p + 5, result, len);
1602 else if (!strncmp (p, ".redir", 6))
1603 rc = redir_command (p + 6);
1604 else if (!strncmp (p, ".help", 5))
1605 rc = help_command (p + 5);
1606 else if (!strncmp (p, ".open", 5))
1607 rc = open_command ((char *)p + 5);
1608 else if (!strncmp (p, ".set", 4))
1609 rc = set_command (p + 4);
1610 else if (!strncmp (p, ".save", 5))
1611 rc = do_save_passwd_command (p + 5, SAVE_WHICH_SAVE);
1612 else if (!strncmp (p, ".passwd", 7))
1613 rc = do_save_passwd_command (p + 7, SAVE_WHICH_PASSWD);
1614 else if (!strncmp (p, ".genkey", 7))
1615 rc = do_save_passwd_command (p + 7, SAVE_WHICH_GENKEY);
1616 else if (!strncmp (p, ".listkeys", 9))
1617 rc = listkeys_command (p+9);
1618 else
1620 rc = pwmd_command (pwm, result, len, inquire_cb, inq, "%s", line);
1621 #ifdef HAVE_LIBREADLINE
1622 if (interactive)
1624 #endif
1625 reset_keyfiles ();
1626 #ifdef HAVE_LIBREADLINE
1628 #endif
1630 if (!rc && !strncasecmp (line, "RESET", 5))
1632 pwmd_free (filename);
1633 filename = NULL;
1637 return FINISH (rc);
1640 #ifdef HAVE_LIBREADLINE
1641 #ifdef HAVE_READLINE_HISTORY
1642 static void
1643 add_history_item (const char *line)
1645 HIST_ENTRY **list, *p = NULL;
1646 int i;
1648 list = history_list ();
1649 for (i = 0; list && list[i]; i++)
1651 if (!strcmp (list[i]->line, line))
1653 p = list[i];
1654 break;
1658 if (p)
1660 char *s;
1662 p = remove_history (i);
1663 #ifdef HAVE_FREE_HISTORY_ENTRY
1664 s = free_history_entry (p);
1665 #endif
1666 free (s);
1669 add_history (line);
1671 #endif
1673 static gpg_error_t
1674 do_interactive ()
1676 gpg_error_t rc;
1677 struct inquire_s *inq = NULL;
1679 rl_initialize ();
1680 rc = process_cmd ();
1681 if (rc)
1682 return rc;
1684 rc = set_inquire (STDIN_FILENO, NULL, &inq);
1685 if (rc)
1686 return rc;
1688 fprintf (stderr,
1689 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1690 print_help ();
1691 rl_event_hook = &interactive_hook;
1692 rl_getc_function = get_readline_char;
1693 rl_set_keyboard_input_timeout (100000);
1695 for (;;)
1697 char *line;
1698 char *result = NULL;
1699 size_t len;
1700 char buf[255];
1702 rc = 0;
1703 snprintf (buf, sizeof (buf), "pwmc%s%s> ",
1704 filename ? ":" : "", filename ? filename : "");
1705 line = readline (buf);
1706 if (interactive_error)
1708 free (line);
1709 rc = interactive_error;
1710 break;
1713 if (!line)
1715 rc = finalize ();
1716 if (!rc)
1717 break;
1719 if (gpg_err_code (rc) != GPG_ERR_CANCELED &&
1720 gpg_err_code (rc) != GPG_ERR_EOF)
1721 fprintf (stderr, "ERR %i: %s\n", rc, gpg_strerror (rc));
1723 continue;
1725 else if (!*line)
1727 free (line);
1728 continue;
1731 #ifdef HAVE_READLINE_HISTORY
1732 add_history_item (line);
1733 #endif
1734 rc = parse_dotcommand (line, &result, &len, inq);
1735 free (line);
1736 if (rc)
1738 char *tmp = NULL;
1740 if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
1741 (void) pwmd_command (pwm, &tmp, NULL, NULL, NULL,
1742 "GETINFO last_error");
1744 show_error (pwm, rc, tmp);
1745 pwmd_free (tmp);
1747 else if (result && len)
1748 printf ("%s%s", result, result[len - 1] != '\n' ? "\n" : "");
1750 pwmd_free (result);
1753 free_inquire (inq);
1754 return rc;
1756 #endif
1758 static gpg_error_t
1759 finalize ()
1761 gpg_error_t rc = 0;
1762 #ifdef HAVE_LIBREADLINE
1763 int quit = 0;
1765 if (interactive)
1767 int finished = 0;
1769 fprintf (stderr, "\n");
1773 char *p, buf[16];
1775 fprintf (stderr,
1777 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1778 p = fgets (buf, sizeof (buf), stdin);
1780 if (feof (stdin))
1782 clearerr (stdin);
1783 return GPG_ERR_EOF;
1786 switch (*p)
1788 case 'h':
1789 print_help ();
1790 break;
1791 case 'c':
1792 return GPG_ERR_CANCELED;
1793 case 'Q':
1794 return 0;
1795 case 'f':
1796 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1797 "CLEARCACHE %s", filename);
1798 if (rc)
1799 return rc;
1801 interactive_hook ();
1802 break;
1803 case 'S':
1804 quit = 1;
1805 case 's':
1806 save = 1;
1807 finished = 1;
1808 break;
1809 default:
1810 break;
1813 while (!finished);
1815 #endif
1817 if (save && !filename)
1819 fprintf (stderr,
1821 ("No filename was specified on the command line. Aborting.\n"));
1822 return GPG_ERR_CANCELED;
1825 if (save && filename)
1827 char *args =
1828 pwmd_strdup_printf ("%s %s%s %s%s %s",
1829 symmetric ? "--symmetric" : "",
1830 keyid ? "--keyid=" : "",
1831 keyid ? keyid : "",
1832 sign_keyid ? "--sign-keyid=" : "",
1833 sign_keyid ? sign_keyid : "",
1834 keyparams ? "--inquire-keyparam" : "");
1836 #ifdef HAVE_LIBREADLINE
1837 if (!quiet || interactive)
1839 #else
1840 if (!quiet)
1842 #endif
1843 fprintf (stderr, "\n");
1844 fprintf (stderr, N_("Saving changes ...\n"));
1847 rc = save_command (args);
1848 pwmd_free (args);
1851 #ifdef HAVE_LIBREADLINE
1852 if (interactive)
1853 return rc ? rc : quit ? 0 : GPG_ERR_CANCELED;
1854 #endif
1856 return rc;
1859 static void
1860 parse_status_ignore (char *str)
1862 size_t n = 0;
1863 char **p, *s;
1865 for (p = status_ignore; p && *p; p++)
1866 pwmd_free (*p);
1868 pwmd_free (status_ignore);
1869 status_ignore = NULL;
1870 if (!str || !*str)
1871 return;
1873 while ((s = strsep (&str, ",")))
1875 p = pwmd_realloc (status_ignore, (n + 2) * sizeof (char *));
1876 p[n++] = pwmd_strdup (s);
1877 p[n] = NULL;
1878 status_ignore = p;
1883 main (int argc, char *argv[])
1885 int connected = 0;
1886 int status_state = 0;
1887 gpg_error_t rc;
1888 int opt;
1889 char command[ASSUAN_LINELENGTH], *p = NULL;
1890 char *result = NULL;
1891 size_t len = 0;
1892 char *pinentry_path = NULL;
1893 char *display = NULL, *tty = NULL, *ttytype = NULL;
1894 char *lcctype = NULL, *lcmessages = NULL;
1895 int outfd = STDOUT_FILENO;
1896 FILE *outfp = stdout;
1897 FILE *inquirefp = stdin;
1898 int show_status = 1;
1899 const char *clientname = "pwmc";
1900 char *inquire = NULL;
1901 char *inquire_line = NULL;
1902 int timeout = 0;
1903 #ifdef WITH_SSH
1904 int use_ssh_agent = -1;
1905 char *knownhosts = NULL;
1906 char *identity = NULL;
1907 int needs_passphrase = 0;
1908 char *ssh_passphrase_file = NULL;
1909 #endif
1910 #ifdef WITH_GNUTLS
1911 char *cacert = NULL;
1912 char *clientcert = NULL;
1913 char *clientkey = NULL;
1914 char *prio = NULL;
1915 int tls_verify = -1;
1916 char *tls_fingerprint = NULL;
1917 #endif
1918 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1919 pwmd_socket_t socktype;
1920 long socket_timeout = 300;
1921 int connect_timeout = 120;
1922 #endif
1923 #ifdef HAVE_LIBREADLINE
1924 int no_interactive = 0;
1925 #endif
1926 int lock_on_open = -1;
1927 long lock_timeout = 50;
1928 char *url = NULL;
1929 char *tmp = NULL;
1930 /* The order is important. */
1931 enum
1933 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1934 OPT_SOCKET_TIMEOUT, OPT_CONNECT_TIMEOUT,
1935 #endif
1936 #ifdef WITH_SSH
1937 OPT_USE_SSH_AGENT, OPT_IDENTITY, OPT_KNOWNHOSTS, OPT_SSH_NEEDS_PASSPHRASE,
1938 OPT_SSH_PASSPHRASE_FILE,
1939 #endif
1940 #ifdef WITH_GNUTLS
1941 OPT_CACERT, OPT_CLIENTCERT, OPT_CLIENTKEY, OPT_PRIORITY, OPT_VERIFY,
1942 OPT_SERVER_FP,
1943 #endif
1944 OPT_URL, OPT_LOCAL, OPT_TTYNAME, OPT_TTYTYPE, OPT_DISPLAY, OPT_LC_CTYPE,
1945 OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES, OPT_PINENTRY, OPT_KEYFILE,
1946 OPT_PASSPHRASE_FILE, OPT_NEW_KEYFILE, OPT_NEW_PASSPHRASE_FILE,
1947 OPT_SIGN_KEYFILE, OPT_SIGN_PASSPHRASE_FILE, OPT_NOLOCK, OPT_LOCK_TIMEOUT,
1948 OPT_SAVE, OPT_OUTPUT_FD, OPT_INQUIRE, OPT_INQUIRE_FD, OPT_INQUIRE_FILE,
1949 OPT_INQUIRE_LINE, OPT_NO_STATUS, OPT_STATUS_IGNORE, OPT_STATUSFD, OPT_NAME,
1950 OPT_VERSION, OPT_HELP, OPT_KEYID, OPT_SIGN_KEYID, OPT_SYMMETRIC,
1951 OPT_KEYPARAMS, OPT_NO_PINENTRY, OPT_QUIET, OPT_STATUS_STATE,
1952 #ifdef HAVE_LIBREADLINE
1953 OPT_NO_INTERACTIVE,
1954 #endif
1956 const struct option long_opts[] = {
1957 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1958 {"socket-timeout", 1, 0, 0},
1959 {"connect-timeout", 1, 0, 0},
1960 #endif
1962 #ifdef WITH_SSH
1963 {"no-ssh-agent", 0, 0, 0},
1964 {"identity", 1, 0, 'i'},
1965 {"knownhosts", 1, 0, 'k'},
1966 {"ssh-needs-passphrase", 0, 0, 0},
1967 {"ssh-passphrase-file", 1, 0, 0},
1968 #endif
1969 #ifdef WITH_GNUTLS
1970 {"ca-cert", 1, 0, 0},
1971 {"client-cert", 1, 0, 0},
1972 {"client-key", 1, 0, 0},
1973 {"tls-priority", 1, 0, 0},
1974 {"no-tls-verify", 0, 0, 0},
1975 {"tls-fingerprint", 1, 0, 0},
1976 #endif
1977 {"url", 1, 0, 0},
1978 {"local-pinentry", 0, 0},
1979 {"ttyname", 1, 0, 'y'},
1980 {"ttytype", 1, 0, 't'},
1981 {"display", 1, 0, 'd'},
1982 {"lc-ctype", 1, 0, 0},
1983 {"lc-messages", 1, 0, 0},
1984 {"timeout", 1, 0, 0},
1985 {"tries", 1, 0, 0},
1986 {"pinentry", 1, 0, 0},
1987 {"key-file", 1, 0, 0},
1988 {"passphrase-file", 1, 0, 0},
1989 {"new-key-file", 1, 0, 0},
1990 {"new-passphrase-file", 1, 0, 0},
1991 {"sign-key-file", 1, 0, 0},
1992 {"sign-passphrase-file", 1, 0, 0},
1993 {"no-lock", 0, 0, 0},
1994 {"lock-timeout", 1, 0, 0},
1995 {"save", 0, 0, 'S'},
1996 {"output-fd", 1, 0, 0},
1997 {"inquire", 1, 0, 0},
1998 {"inquire-fd", 1, 0, 0},
1999 {"inquire-file", 1, 0, 0},
2000 {"inquire-line", 1, 0, 'L'},
2001 {"no-status", 0, 0, 0},
2002 {"status-ignore", 1, 0, 0},
2003 {"status-fd", 1, 0, 0},
2004 {"name", 1, 0, 'n'},
2005 {"version", 0, 0, 0},
2006 {"help", 0, 0, 0},
2007 {"keyid", 1, 0, 0},
2008 {"sign-keyid", 1, 0, 0},
2009 {"symmetric", 0, 0, 0},
2010 {"key-params", 1, 0, 0},
2011 {"no-pinentry", 0, 0, 0},
2012 {"quiet", 0, 0, 0},
2013 {"status-state", 0, 0, 0},
2014 #ifdef HAVE_LIBREADLINE
2015 {"no-interactive", 0, 0},
2016 #endif
2017 {0, 0, 0, 0}
2019 #ifdef WITH_SSH
2020 const char *optstring = "L:y:t:d:P:I:Sn:i:k:s";
2021 #else
2022 const char *optstring = "L:y:t:d:P:I:Sn:s";
2023 #endif
2024 int opt_index = 0;
2026 #ifdef ENABLE_NLS
2027 setlocale (LC_ALL, "");
2028 bindtextdomain ("libpwmd", LOCALEDIR);
2029 #endif
2031 tries = DEFAULT_PIN_TRIES;
2032 inquirefd = STDIN_FILENO;
2033 statusfd = STDERR_FILENO;
2034 statusfp = stderr;
2035 tmp = pwmd_strdup (DEFAULT_STATUS_IGNORE);
2036 parse_status_ignore (tmp);
2037 pwmd_free (tmp);
2038 no_pinentry = -1;
2039 local_pin = -1;
2041 while ((opt =
2042 getopt_long (argc, argv, optstring, long_opts, &opt_index)) != -1)
2044 switch (opt)
2046 /* Handle long options without a short option part. */
2047 case 0:
2048 switch (opt_index)
2050 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2051 case OPT_SOCKET_TIMEOUT:
2052 socket_timeout = strtol (optarg, &p, 10);
2053 break;
2054 case OPT_CONNECT_TIMEOUT:
2055 connect_timeout = strtol (optarg, &p, 10);
2056 break;
2057 #endif
2058 #ifdef WITH_SSH
2059 case OPT_USE_SSH_AGENT:
2060 use_ssh_agent = 0;
2061 break;
2062 case OPT_SSH_NEEDS_PASSPHRASE:
2063 needs_passphrase = 1;
2064 break;
2065 case OPT_SSH_PASSPHRASE_FILE:
2066 ssh_passphrase_file = optarg;
2067 break;
2068 #endif
2069 #ifdef WITH_GNUTLS
2070 case OPT_CACERT:
2071 cacert = optarg;
2072 break;
2073 case OPT_CLIENTCERT:
2074 clientcert = optarg;
2075 break;
2076 case OPT_CLIENTKEY:
2077 clientkey = optarg;
2078 break;
2079 case OPT_PRIORITY:
2080 prio = optarg;
2081 break;
2082 case OPT_VERIFY:
2083 tls_verify = 0;
2084 break;
2085 case OPT_SERVER_FP:
2086 tls_fingerprint = optarg;
2087 break;
2088 #endif
2089 case OPT_SYMMETRIC:
2090 symmetric = 1;
2091 break;
2092 case OPT_KEYPARAMS:
2093 keyparams = optarg;
2094 break;
2095 case OPT_KEYFILE:
2096 case OPT_PASSPHRASE_FILE:
2097 keyfile = pwmd_strdup (optarg);
2098 break;
2099 case OPT_NEW_KEYFILE:
2100 case OPT_NEW_PASSPHRASE_FILE:
2101 new_keyfile = pwmd_strdup (optarg);
2102 break;
2103 case OPT_SIGN_KEYFILE:
2104 case OPT_SIGN_PASSPHRASE_FILE:
2105 sign_keyfile = pwmd_strdup (optarg);
2106 break;
2107 case OPT_NOLOCK:
2108 lock_on_open = 0;
2109 break;
2110 case OPT_LOCK_TIMEOUT:
2111 lock_timeout = strtol (optarg, &p, 10);
2112 break;
2113 case OPT_URL:
2114 url = optarg;
2115 break;
2116 case OPT_LOCAL:
2117 local_pin = 1;
2118 break;
2119 case OPT_LC_CTYPE:
2120 lcctype = pwmd_strdup (optarg);
2121 break;
2122 case OPT_LC_MESSAGES:
2123 lcmessages = pwmd_strdup (optarg);
2124 break;
2125 case OPT_TIMEOUT:
2126 timeout = strtol (optarg, &p, 10);
2127 break;
2128 case OPT_TRIES:
2129 tries = strtol (optarg, &p, 10);
2130 break;
2131 case OPT_INQUIRE:
2132 inquire = escape (optarg);
2133 break;
2134 case OPT_INQUIRE_FD:
2135 inquirefd = strtol (optarg, &p, 10);
2136 if (!p)
2138 inquirefp = fdopen (inquirefd, "r");
2139 if (!inquirefp)
2140 err (EXIT_FAILURE, "%i", inquirefd);
2142 break;
2143 case OPT_INQUIRE_FILE:
2144 inquirefd = open (optarg, O_RDONLY);
2145 if (inquirefd == -1)
2146 err (EXIT_FAILURE, "%s", optarg);
2147 inquirefp = fdopen (inquirefd, "r");
2148 break;
2149 case OPT_OUTPUT_FD:
2150 outfd = strtol (optarg, &p, 10);
2151 if (!p || !*p)
2153 outfp = fdopen (outfd, "w");
2154 if (!outfp)
2155 err (EXIT_FAILURE, "%i", outfd);
2157 break;
2158 case OPT_NO_STATUS:
2159 show_status = 0;
2160 break;
2161 case OPT_STATUSFD:
2162 statusfd = strtol (optarg, &p, 10);
2163 if (!p || !*p)
2165 statusfp = fdopen (statusfd, "w");
2166 if (!statusfp)
2167 err (EXIT_FAILURE, "%i", statusfd);
2169 break;
2170 case OPT_STATUS_IGNORE:
2171 parse_status_ignore (optarg);
2172 break;
2173 case OPT_VERSION:
2174 printf ("%s (pwmc)\n\n"
2175 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016\n"
2176 "%s\n"
2177 "Released under the terms of the LGPL v2.1. Use at your own risk.\n\n"
2178 "Compile-time features:\n"
2179 #ifdef HAVE_LIBREADLINE
2180 "+INTERACTIVE "
2181 #else
2182 "-INTERACTIVE "
2183 #endif
2184 #ifdef WITH_SSH
2185 "+SSH "
2186 #else
2187 "-SSH "
2188 #endif
2189 #ifdef WITH_GNUTLS
2190 "+GNUTLS "
2191 #else
2192 "-GNUTLS "
2193 #endif
2194 #ifdef WITH_PINENTRY
2195 "+PINENTRY "
2196 #else
2197 "-PINENTRY "
2198 #endif
2199 #ifdef WITH_QUALITY
2200 "+QUALITY "
2201 #else
2202 "-QUALITY "
2203 #endif
2204 #ifdef MEM_DEBUG
2205 "+MEM_DEBUG "
2206 #else
2207 "-MEM_DEBUG "
2208 #endif
2209 "\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
2210 exit (EXIT_SUCCESS);
2211 case OPT_PINENTRY:
2212 pinentry_path = optarg;
2213 break;
2214 case OPT_HELP:
2215 usage (argv[0], EXIT_SUCCESS);
2216 case OPT_KEYID:
2217 keyid = optarg;
2218 break;
2219 case OPT_SIGN_KEYID:
2220 sign_keyid = optarg;
2221 break;
2222 case OPT_QUIET:
2223 quiet = 1;
2224 show_status = 0;
2225 break;
2226 case OPT_STATUS_STATE:
2227 status_state = 1;
2228 break;
2229 case OPT_NO_PINENTRY:
2230 no_pinentry = 1;
2231 break;
2232 #ifdef HAVE_LIBREADLINE
2233 case OPT_NO_INTERACTIVE:
2234 no_interactive = 1;
2235 break;
2236 #endif
2237 default:
2238 usage (argv[0], EXIT_FAILURE);
2241 if (p && *p)
2243 fprintf (stderr, N_("%s: invalid argument for option '--%s'\n"),
2244 argv[0], long_opts[opt_index].name);
2245 usage (argv[0], EXIT_FAILURE);
2248 break;
2249 #ifdef WITH_SSH
2250 case 'i':
2251 identity = optarg;
2252 break;
2253 case 'k':
2254 knownhosts = optarg;
2255 break;
2256 #endif
2257 case 'L':
2258 inquire_line = optarg;
2259 break;
2260 case 'y':
2261 tty = optarg;
2262 break;
2263 case 't':
2264 ttytype = optarg;
2265 break;
2266 case 'd':
2267 display = optarg;
2268 break;
2269 case 'S':
2270 save = 1;
2271 break;
2272 case 'n':
2273 clientname = optarg;
2274 break;
2275 default:
2276 usage (argv[0], EXIT_FAILURE);
2280 #ifdef HAVE_LIBREADLINE
2281 if (isatty (STDIN_FILENO) && !inquire && !inquire_line && !no_interactive)
2282 interactive = 1;
2283 #endif
2285 pwmd_init ();
2286 rc = pwmd_new (clientname, &pwm);
2287 if (rc)
2288 goto done;
2290 filename = argv[optind] ? pwmd_strdup (argv[optind]) : NULL;
2291 if (no_pinentry != -1)
2292 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
2293 else
2294 rc = pwmd_getopt (pwm, PWMD_OPTION_NO_PINENTRY, &no_pinentry);
2295 if (rc)
2296 goto done;
2298 if (local_pin != -1)
2299 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local_pin);
2300 else
2301 rc = pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local_pin);
2302 if (rc)
2303 goto done;
2305 pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
2306 if (!quiet)
2307 fprintf (stderr, N_("Connecting ...\n"));
2309 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
2310 socktype = is_remote_url (url);
2311 if (socktype != PWMD_SOCKET_LOCAL)
2313 local_pin = 1;
2314 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2315 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, connect_timeout);
2316 if (rc)
2317 goto done;
2318 #endif
2320 if (socktype == PWMD_SOCKET_SSH)
2322 #ifdef WITH_SSH
2323 if (use_ssh_agent == -1)
2324 rc = pwmd_getopt (pwm, PWMD_OPTION_SSH_AGENT, &use_ssh_agent);
2326 if (!rc)
2328 if (!getenv ("SSH_AUTH_SOCK") || identity)
2329 use_ssh_agent = 0;
2331 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_AGENT, use_ssh_agent);
2332 if (rc)
2333 goto done;
2335 else
2336 goto done;
2338 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_NEEDS_PASSPHRASE,
2339 needs_passphrase);
2340 if (rc)
2341 goto done;
2343 if (ssh_passphrase_file)
2345 struct stat st;
2346 int fd;
2348 if (stat (ssh_passphrase_file, &st) == -1)
2350 rc = gpg_error_from_syserror ();
2351 fprintf(stderr, "%s: %s\n", ssh_passphrase_file,
2352 gpg_strerror (rc));
2353 goto done;
2356 result = pwmd_calloc (1, st.st_size+1);
2357 if (!result)
2359 rc = GPG_ERR_ENOMEM;
2360 goto done;
2363 fd = open (ssh_passphrase_file, O_RDONLY);
2364 if (fd != -1)
2366 len = read (fd, result, st.st_size);
2367 if (len == st.st_size)
2368 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_PASSPHRASE, result);
2369 else
2370 rc = gpg_error_from_syserror ();
2372 close (fd);
2374 else
2375 rc = gpg_error_from_syserror ();
2377 pwmd_free (result);
2378 result = NULL;
2379 len = 0;
2381 if (rc)
2383 fprintf(stderr, "%s: %s\n", ssh_passphrase_file,
2384 gpg_strerror (rc));
2385 goto done;
2389 rc = pwmd_connect (pwm, url, identity, knownhosts);
2390 #endif
2392 #ifdef WITH_GNUTLS
2393 else
2395 if (tls_verify != -1)
2397 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_VERIFY, tls_verify);
2398 if (rc)
2399 goto done;
2402 if (prio)
2403 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_PRIORITY, prio);
2405 if (!rc)
2406 rc = pwmd_connect (pwm, url, clientcert, clientkey, cacert,
2407 tls_fingerprint);
2409 #endif
2411 else
2412 rc = pwmd_connect (pwm, url);
2413 #else
2414 rc = pwmd_connect (pwm, url);
2415 #endif
2416 if (rc)
2417 goto done;
2419 if (!quiet)
2420 fprintf (stderr, N_("Connected.\n"));
2422 connected = 1;
2423 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2424 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, socket_timeout);
2425 if (rc)
2426 goto done;
2427 #endif
2429 if (lock_timeout)
2431 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
2432 "OPTION LOCK-TIMEOUT=%li", lock_timeout);
2433 if (rc)
2434 goto done;
2437 if (status_state)
2439 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION CLIENT-STATE=1");
2440 if (rc)
2441 goto done;
2444 if (lock_on_open != -1)
2446 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCK_ON_OPEN, lock_on_open);
2447 if (rc)
2448 goto done;
2451 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, NULL, NULL);
2452 if (rc)
2453 goto done;
2455 if (timeout > 0)
2457 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
2458 if (rc)
2459 goto done;
2462 if (pinentry_path)
2464 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
2465 if (rc)
2466 goto done;
2469 if (display)
2471 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
2472 if (rc)
2473 goto done;
2476 if (tty)
2478 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, tty);
2479 if (rc)
2480 goto done;
2483 if (ttytype)
2485 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
2486 if (rc)
2487 goto done;
2490 if (lcctype)
2492 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
2493 if (rc)
2494 goto done;
2497 if (lcmessages)
2499 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES, lcmessages);
2500 if (rc)
2501 goto done;
2504 if (show_status)
2506 rc = pwmd_setopt (pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
2507 if (rc)
2508 goto done;
2511 if (filename)
2513 rc = open_command (filename);
2514 if (rc)
2515 goto done;
2518 #ifdef HAVE_LIBREADLINE
2519 if (interactive)
2521 rc = do_interactive ();
2522 result = NULL;
2523 goto do_exit;
2525 #endif
2527 if (inquire)
2529 struct inquire_s *inq = NULL;
2531 rc = set_inquire (inquirefd, inquire_line, &inq);
2532 if (!rc)
2533 rc = pwmd_command (pwm, &result, &len, inquire_cb, inq, "%s", inquire);
2535 free_inquire (inq);
2536 goto done;
2539 if (fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1)
2541 rc = gpg_error_from_errno (errno);
2542 goto done;
2545 ssize_t n;
2547 for (;;)
2549 rc = process_cmd ();
2551 if (rc)
2552 goto done;
2554 n = read (STDIN_FILENO, command, sizeof (command)-1);
2555 if (n == -1)
2557 if (errno == EAGAIN)
2559 usleep (100000);
2560 continue;
2563 rc = gpg_error_from_errno (errno);
2564 goto done;
2566 else if (!n)
2567 goto done;
2569 p = command;
2570 command[n] = 0;
2571 break;
2574 if (!p || !*p || !strcasecmp (p, "BYE"))
2575 goto done;
2578 struct inquire_s *inq = NULL;
2579 rc = set_inquire (inquirefd, inquire_line, &inq);
2580 if (!rc)
2582 rc = parse_dotcommand (command, &result, &len, inq);
2583 free_inquire (inq);
2586 if (rc)
2587 goto done;
2589 done:
2590 if (result)
2592 fwrite (result, 1, result[len - 1] == 0 ? len - 1 : len, outfp);
2593 fflush (outfp);
2594 pwmd_free (result);
2597 result = NULL;
2598 if (!rc)
2599 rc = finalize ();
2600 else if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
2601 (void) pwmd_command (pwm, &result, NULL, NULL, NULL,
2602 "GETINFO last_error");
2604 #ifdef HAVE_LIBREADLINE
2605 do_exit:
2606 #endif
2607 wipememory (command, 0, sizeof (command));
2609 if (rc && !quiet)
2610 show_error (pwm, rc, result);
2612 pwmd_close (pwm);
2613 reset_keyfiles ();
2614 pwmd_deinit ();
2615 pwmd_free (result);
2616 pwmd_free (filename);
2617 parse_status_ignore (NULL);
2618 if (connected && !quiet)
2619 fprintf (stderr, N_("Connection closed.\n"));
2621 exit (rc ? EXIT_FAILURE : EXIT_SUCCESS);