Fix pkg-config meta file to add libassuan flags.
[libpwmd.git] / src / pwmc.c
blobc6701d3030c5aeebb861bf36dfce5eea9c2d26f2
1 /*
2 Copyright (C) 2006-2016, 2017 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, *tmp = NULL;
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 if (*p)
1020 file = tmp = pwmd_strdup (file + (strlen (file)-strlen (p)));
1021 if (!file || !*file)
1023 pwmd_free (file);
1024 file = tmp = NULL;
1027 else
1028 file = NULL;
1032 if (!file || !*file)
1034 fprintf (stderr, N_("Usage: .open [--options] <filename>\n"));
1035 return GPG_ERR_SYNTAX;
1038 #ifdef HAVE_LIBREADLINE
1039 if (interactive || !quiet)
1040 #else
1041 if (!quiet)
1042 #endif
1043 fprintf (stderr, N_("Opening data file \"%s\" ...\n"), file);
1045 #ifdef HAVE_LIBREADLINE
1046 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1047 #else
1048 rc = set_inquire (-1, NULL, &inq);
1049 #endif
1050 if (rc)
1052 if (tmp)
1053 pwmd_free (file);
1054 return rc;
1057 pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local);
1059 if (keyfile)
1061 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1062 if (!rc)
1063 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, 1);
1065 else
1066 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1068 if (!rc)
1069 rc = pwmd_open (pwm, file, inquire_cb, inq);
1071 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local);
1073 #ifdef HAVE_LIBREADLINE
1074 if (interactive)
1075 reset_keyfiles ();
1076 #endif
1078 free_inquire (inq);
1079 if (!rc)
1081 if (tmp)
1083 pwmd_free (filename);
1084 filename = tmp;
1086 else
1088 char *p = pwmd_strdup (file);
1090 pwmd_free (filename);
1091 filename = p;
1092 if (!filename)
1093 rc = GPG_ERR_ENOMEM;
1096 else
1098 pwmd_free (tmp);
1099 pwmd_free (filename);
1100 filename = NULL;
1103 return rc;
1106 static gpg_error_t
1107 set_command (const char *line)
1109 gpg_error_t rc = 0;
1110 char name[256] = { 0 };
1111 char value[512] = { 0 };
1112 char *namep;
1113 char *valuep;
1114 const char *p = line;
1116 while (p && *p && isspace (*p))
1117 p++;
1119 namep = parse_arg (p, name, sizeof (name));
1120 if (!namep || !*namep)
1122 fprintf (stderr, N_("Usage: .set help | <name> [<value>]\n"));
1123 return GPG_ERR_SYNTAX;
1126 p += strlen (namep);
1127 while (p && *p && isspace (*p))
1128 p++;
1130 valuep = parse_arg (p, value, sizeof (value));
1132 if (!strcmp (name, "passphrase-file") || !strcmp (name, "new-passphrase-file")
1133 || !strcmp (name, "sign-passphrase-file"))
1135 int is_newkeyfile = 1;
1136 int sign = !strcmp (name, "sign-passphrase-file");
1138 if (!strcmp (name, "passphrase-file") || sign)
1139 is_newkeyfile = 0;
1141 if (is_newkeyfile)
1143 pwmd_free (new_keyfile);
1144 new_keyfile = NULL;
1146 else if (sign)
1148 pwmd_free (sign_keyfile);
1149 sign_keyfile = NULL;
1151 else
1153 pwmd_free (keyfile);
1154 keyfile = NULL;
1157 if (!rc && *valuep)
1159 if (is_newkeyfile)
1160 new_keyfile = pwmd_strdup (value);
1161 else if (sign)
1162 sign_keyfile = pwmd_strdup (value);
1163 else
1164 keyfile = pwmd_strdup (value);
1166 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1168 else if (!local_pin && !no_pinentry)
1170 pwmd_socket_t t;
1172 pwmd_socket_type (pwm, &t);
1173 if (t == PWMD_SOCKET_LOCAL)
1174 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1177 else if (!strcmp(name, "pinentry-timeout"))
1179 char *e = NULL;
1180 int n = strtol(valuep, &e, 10);
1182 if (e && *e)
1183 return gpg_error (GPG_ERR_INV_VALUE);
1185 if (!*valuep)
1186 n = DEFAULT_PIN_TIMEOUT;
1188 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, n);
1190 else if (!strcmp (name, "help"))
1192 fprintf (stderr,
1194 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1195 "delimited. When no value is specified the option is unset.\n\n"
1196 "passphrase-file [<filename>]\n"
1197 " set or unset the file to be used when a passphrase is required (*)\n"
1198 "\n"
1199 "new-passphrase-file [<filename>]\n"
1200 " set or unset the file to be used when a new passphrase is required (*)\n"
1201 "\n"
1202 "sign-passphrase-file [<filename>]\n"
1203 " set or unset the file to be used when a passphrase is required for\n"
1204 " signing (symmetric) (*)\n"
1205 "\n"
1206 "pinentry-timeout <seconds>\n"
1207 " the amount of seconds before pinentry gives up waiting for input\n"
1208 "\n"
1209 "* = the next protocol command will unset this value\n"
1212 else
1213 rc = GPG_ERR_UNKNOWN_OPTION;
1215 return rc;
1218 static gpg_error_t
1219 do_save_passwd_command (const char *line, int which)
1221 struct inquire_s *inq = NULL;
1222 gpg_error_t rc;
1223 int local;
1225 #ifdef HAVE_LIBREADLINE
1226 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1227 #else
1228 rc = set_inquire (-1, NULL, &inq);
1229 #endif
1230 if (rc)
1231 return rc;
1233 pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local);
1235 if (new_keyfile || keyfile || sign_keyfile)
1237 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1238 if (!rc)
1239 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, 1);
1241 else
1242 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1244 if (!rc)
1246 if (which == SAVE_WHICH_SAVE)
1247 rc = pwmd_save (pwm, line, inquire_cb, inq);
1248 else if (which == SAVE_WHICH_PASSWD)
1249 rc = pwmd_passwd (pwm, line, inquire_cb, inq);
1250 else
1251 rc = pwmd_genkey (pwm, line, inquire_cb, inq);
1254 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local);
1256 #ifdef HAVE_LIBREADLINE
1257 if (interactive)
1258 reset_keyfiles ();
1259 #endif
1261 free_inquire (inq);
1262 return rc;
1265 static gpg_error_t
1266 save_command (const char *line)
1268 return do_save_passwd_command (line, SAVE_WHICH_SAVE);
1271 static void
1272 search_and_replace (char *str, const char *s, const char r)
1274 char *p;
1276 p = strstr (str, s);
1277 if (p)
1279 *p = r;
1280 while (*++p)
1281 *p = *(p+1);
1282 search_and_replace (str, s, r);
1283 return;
1287 static char *
1288 openpgp_unescape (char *str)
1290 search_and_replace (str, "\\x3a", ':');
1291 search_and_replace (str, "\\x5c", '\\');
1292 return str;
1295 static void
1296 free_listkeys (struct slist_s *keys)
1298 unsigned i, t;
1300 t = slist_length (keys);
1301 for (i = 0; i < t; i++)
1303 struct keyid_s *key = slist_nth_data (keys, i);
1304 unsigned n, nt;
1306 nt = slist_length (key->userids);
1307 for (n = 0; n < nt; n++)
1309 struct userid_s *userid = slist_nth_data (key->userids, n);
1311 pwmd_free (userid->userid);
1312 pwmd_free (userid->name);
1313 pwmd_free (userid->email);
1314 pwmd_free (userid->comment);
1315 pwmd_free (userid);
1318 slist_free (key->userids);
1319 nt = slist_length (key->subkeys);
1320 for (n = 0; n < nt; n++)
1322 struct keyid_s *sub = slist_nth_data (key->subkeys, n);
1324 pwmd_free (sub->keyid);
1325 pwmd_free (sub->fpr);
1326 pwmd_free (sub->grip);
1327 pwmd_free (sub->card);
1328 pwmd_free (sub->curve);
1329 pwmd_free (sub);
1332 slist_free (key->subkeys);
1333 pwmd_free (key);
1336 slist_free (keys);
1339 static const char *
1340 openpgp_algorithm (struct keyid_s *key)
1342 switch (key->algo)
1344 case 1:
1345 case 2:
1346 case 3:
1347 return "RSA";
1348 case 16:
1349 case 20:
1350 return "ELG";
1351 case 17:
1352 return "DSA";
1353 case 301:
1354 case 302:
1355 case 18:
1356 return "ECC";
1357 default:
1358 break;
1361 return N_("Unknown");
1364 static void
1365 display_listkeys (struct slist_s *keys)
1367 unsigned i, t;
1369 t = slist_length (keys);
1370 for (i = 0; i < t; i++)
1372 struct keyid_s *key = slist_nth_data (keys, i);
1373 unsigned st = slist_length (key->subkeys);
1374 unsigned s;
1375 unsigned ut = slist_length (key->userids);
1376 unsigned u;
1378 for (u = 0; u < ut; u++)
1380 struct userid_s *userid = slist_nth_data (key->userids, u);
1382 fprintf(stdout, N_("User ID: %s\n"), userid->userid);
1385 for (s = 0; s < st; s++)
1387 struct keyid_s *sub = slist_nth_data (key->subkeys, s);
1388 struct tm *tmp;
1389 const char *caps = NULL;
1390 char expires[11] = { 0 };
1391 char created[11] = { 0 };
1393 if (sub->expires)
1395 tmp = localtime (&sub->expires);
1396 strftime (expires, sizeof (expires), "%F", tmp);
1399 tmp = localtime (&sub->created);
1400 strftime (created, sizeof (created), "%F", tmp);
1402 if (sub->can_encrypt)
1403 caps = "E";
1404 else if (sub->can_sign)
1405 caps = "S";
1406 else if (sub->can_auth)
1407 caps = "A";
1408 else if (sub->can_certify)
1409 caps = "C";
1411 fprintf(stdout, N_(
1412 " Subkey %u: %s [%s]%s%s %s-%u%s%s\n"
1413 " Created: %s %s%s\n"
1414 " Fingerprint: %s\n"
1415 " Keygrip: %s\n"
1416 "%s%s%s"),
1417 s+1,
1418 sub->keyid,
1419 caps,
1420 sub->secret || sub->card ? "[P]" : "",
1421 sub->revoked ? "[R]" : "",
1422 openpgp_algorithm (sub),
1423 sub->bits,
1424 sub->curve ? "-" : "",
1425 sub->curve ? sub->curve : "",
1426 created,
1427 sub->expired ? N_("Expired: ") : expires[0] ? N_("Expires: ") : "",
1428 sub->expired || expires[0] ? expires : "",
1429 sub->fpr,
1430 sub->grip,
1431 sub->card ? N_(" Card: ") : "",
1432 sub->card ? sub->card : "",
1433 sub->card ? "\n" : "");
1436 if (i+1 < t)
1437 fprintf (stdout, "\n");
1441 static gpg_error_t
1442 listkeys_command (const char *pattern)
1444 gpg_error_t rc;
1445 char *result;
1446 char **lines = NULL, **p;
1447 struct slist_s *keys = NULL;
1449 rc = pwmd_command (pwm, &result, NULL, NULL, NULL, "LISTKEYS %s", pattern);
1450 if (rc)
1451 return rc;
1453 lines = str_split (result, "\n", 0);
1454 pwmd_free (result);
1455 if (!lines)
1456 return GPG_ERR_ENOMEM;
1458 for (p = lines; *p; p++)
1460 struct keyid_s *key;
1461 char **fields = str_split (*p, ":", 0);
1462 int i, f;
1463 unsigned s;
1464 unsigned n_subkeys = 0;
1465 struct slist_s *tlist;
1467 if (!fields)
1469 rc = GPG_ERR_ENOMEM;
1470 break;
1473 key = pwmd_calloc (1, sizeof (struct keyid_s));
1474 if (!key)
1476 strv_free (fields);
1477 rc = GPG_ERR_ENOMEM;
1478 break;
1481 for (f = i = 0; i < 17; i++, f++)
1483 int b = 0;
1485 if (i < 10)
1486 b = atoi (fields[f]) != 0;
1488 switch (i)
1490 case 0: key->revoked = b; break;
1491 case 1: key->expired = b; break;
1492 case 4: key->can_encrypt = b; break;
1493 case 5: key->can_sign = b; break;
1494 case 7: key->secret = b; break;
1495 case 16: n_subkeys = strtoul (fields[f], NULL, 10); break;
1496 default:
1497 break;
1501 for (s = 0; s < n_subkeys; s++)
1503 struct keyid_s *sub;
1504 int b = 0;
1506 sub = pwmd_calloc (1, sizeof (struct keyid_s));
1507 if (!sub)
1509 strv_free (fields);
1510 rc = GPG_ERR_ENOMEM;
1511 break;
1514 for (i = 0; i < 20; i++, f++)
1516 if (i < 11)
1517 b = atoi (fields[f]) != 0;
1519 switch (i)
1521 case 0: sub->revoked = b; break;
1522 case 1: sub->expired = b; break;
1523 case 4: sub->can_encrypt = b; break;
1524 case 5: sub->can_sign = b; break;
1525 case 6: sub->can_certify = b; break;
1526 case 7: sub->secret = b; break;
1527 case 8: sub->can_auth = b; break;
1528 case 11: sub->algo = atoi (fields[f]); break;
1529 case 12: sub->bits = atoi (fields[f]); break;
1530 case 13: sub->keyid = pwmd_strdup (fields[f]); break;
1531 case 14: sub->fpr = pwmd_strdup (fields[f]); break;
1532 case 15: sub->grip = pwmd_strdup (fields[f]); break;
1533 case 16: sub->created = strtoul (fields[f], NULL, 10); break;
1534 case 17: sub->expires = strtoul (fields[f], NULL, 10); break;
1535 case 18: sub->card = fields[f] && strlen(fields[f]) > 1
1536 ? pwmd_strdup (fields[f]) : NULL; break;
1537 case 19: sub->curve = strlen (fields[f]) > 1 ? pwmd_strdup (openpgp_unescape(fields[f])) : NULL; break;
1538 default:
1539 break;
1543 tlist = slist_append (key->subkeys, sub);
1544 if (!tlist)
1546 rc = GPG_ERR_ENOMEM;
1547 break;
1550 key->subkeys = tlist;
1553 if (rc)
1555 strv_free (fields);
1556 break;
1559 // Re-create a line containing the userIds.
1560 for (; f < strv_length (fields); f++)
1562 struct userid_s *userid;
1564 userid = pwmd_calloc (1, sizeof (struct userid_s));
1565 if (!userid)
1567 rc = GPG_ERR_ENOMEM;
1568 break;
1571 // Revoked.
1572 f++;
1573 // Invalid.
1574 f++;
1575 // Validity.
1576 f++;
1578 userid->userid = pwmd_strdup (openpgp_unescape (fields[f++]));
1579 userid->name = pwmd_strdup (openpgp_unescape (fields[f++]));
1580 userid->email = pwmd_strdup (openpgp_unescape (fields[f++]));
1581 userid->comment = pwmd_strdup (openpgp_unescape (fields[f]));
1583 tlist = slist_append (key->userids, userid);
1584 if (!tlist)
1586 rc = GPG_ERR_ENOMEM;
1587 break;
1590 key->userids = tlist;
1593 strv_free (fields);
1594 if (rc)
1595 break;
1597 tlist = slist_append (keys, key);
1598 if (!tlist)
1600 rc = GPG_ERR_ENOMEM;
1601 break;
1604 keys = tlist;
1607 strv_free (lines);
1609 if (!rc)
1610 display_listkeys (keys);
1612 free_listkeys (keys);
1613 return rc;
1616 static gpg_error_t
1617 parse_dotcommand (const char *line, char **result,
1618 size_t * len, struct inquire_s *inq)
1620 const char *p = line;
1621 gpg_error_t rc = 0;
1623 if (!strncmp (p, ".read", 5))
1624 rc = read_command (p + 5, result, len);
1625 else if (!strncmp (p, ".redir", 6))
1626 rc = redir_command (p + 6);
1627 else if (!strncmp (p, ".help", 5))
1628 rc = help_command (p + 5);
1629 else if (!strncmp (p, ".open", 5))
1630 rc = open_command ((char *)p + 5);
1631 else if (!strncmp (p, ".set", 4))
1632 rc = set_command (p + 4);
1633 else if (!strncmp (p, ".save", 5))
1634 rc = do_save_passwd_command (p + 5, SAVE_WHICH_SAVE);
1635 else if (!strncmp (p, ".passwd", 7))
1636 rc = do_save_passwd_command (p + 7, SAVE_WHICH_PASSWD);
1637 else if (!strncmp (p, ".genkey", 7))
1638 rc = do_save_passwd_command (p + 7, SAVE_WHICH_GENKEY);
1639 else if (!strncmp (p, ".listkeys", 9))
1640 rc = listkeys_command (p+9);
1641 else
1643 rc = pwmd_command (pwm, result, len, inquire_cb, inq, "%s", line);
1644 #ifdef HAVE_LIBREADLINE
1645 if (interactive)
1647 #endif
1648 reset_keyfiles ();
1649 #ifdef HAVE_LIBREADLINE
1651 #endif
1653 if (!rc && !strncasecmp (line, "RESET", 5))
1655 pwmd_free (filename);
1656 filename = NULL;
1660 return FINISH (rc);
1663 #ifdef HAVE_LIBREADLINE
1664 #ifdef HAVE_READLINE_HISTORY
1665 static void
1666 add_history_item (const char *line)
1668 HIST_ENTRY **list, *p = NULL;
1669 int i;
1671 list = history_list ();
1672 for (i = 0; list && list[i]; i++)
1674 if (!strcmp (list[i]->line, line))
1676 p = list[i];
1677 break;
1681 if (p)
1683 char *s;
1685 p = remove_history (i);
1686 #ifdef HAVE_FREE_HISTORY_ENTRY
1687 s = free_history_entry (p);
1688 #endif
1689 free (s);
1692 add_history (line);
1694 #endif
1696 static gpg_error_t
1697 do_interactive ()
1699 gpg_error_t rc;
1700 struct inquire_s *inq = NULL;
1702 rl_initialize ();
1703 rc = process_cmd ();
1704 if (rc)
1705 return rc;
1707 rc = set_inquire (STDIN_FILENO, NULL, &inq);
1708 if (rc)
1709 return rc;
1711 fprintf (stderr,
1712 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1713 print_help ();
1714 rl_event_hook = &interactive_hook;
1715 rl_getc_function = get_readline_char;
1716 rl_set_keyboard_input_timeout (100000);
1718 for (;;)
1720 char *line;
1721 char *result = NULL;
1722 size_t len;
1723 char buf[255];
1725 snprintf (buf, sizeof (buf), "pwmc%s%s> ",
1726 filename ? ":" : "", filename ? filename : "");
1727 line = readline (buf);
1728 if (interactive_error)
1730 free (line);
1731 rc = interactive_error;
1732 break;
1735 if (!line)
1737 rc = finalize ();
1738 if (!rc)
1739 break;
1741 if (gpg_err_code (rc) != GPG_ERR_CANCELED &&
1742 gpg_err_code (rc) != GPG_ERR_EOF)
1743 fprintf (stderr, "ERR %i: %s\n", rc, gpg_strerror (rc));
1745 continue;
1747 else if (!*line)
1749 free (line);
1750 continue;
1753 #ifdef HAVE_READLINE_HISTORY
1754 add_history_item (line);
1755 #endif
1756 rc = parse_dotcommand (line, &result, &len, inq);
1757 free (line);
1758 if (rc)
1760 char *tmp = NULL;
1762 if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
1763 (void) pwmd_command (pwm, &tmp, NULL, NULL, NULL,
1764 "GETINFO last_error");
1766 show_error (pwm, rc, tmp);
1767 pwmd_free (tmp);
1769 else if (result && len)
1770 printf ("%s%s", result, result[len - 1] != '\n' ? "\n" : "");
1772 pwmd_free (result);
1775 free_inquire (inq);
1776 return rc;
1778 #endif
1780 static gpg_error_t
1781 finalize ()
1783 gpg_error_t rc = 0;
1784 #ifdef HAVE_LIBREADLINE
1785 int quit = 0;
1787 if (interactive)
1789 int finished = 0;
1791 fprintf (stderr, "\n");
1795 char *p, buf[16];
1797 fprintf (stderr,
1799 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1800 p = fgets (buf, sizeof (buf), stdin);
1802 if (feof (stdin))
1804 clearerr (stdin);
1805 return GPG_ERR_EOF;
1808 switch (*p)
1810 case 'h':
1811 print_help ();
1812 break;
1813 case 'c':
1814 return GPG_ERR_CANCELED;
1815 case 'Q':
1816 return 0;
1817 case 'f':
1818 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1819 "CLEARCACHE %s", filename);
1820 if (rc)
1821 return rc;
1823 interactive_hook ();
1824 break;
1825 case 'S':
1826 quit = 1;
1827 case 's':
1828 save = 1;
1829 finished = 1;
1830 break;
1831 default:
1832 break;
1835 while (!finished);
1837 #endif
1839 if (save && !filename)
1841 fprintf (stderr,
1843 ("No filename was specified on the command line. Aborting.\n"));
1844 return GPG_ERR_CANCELED;
1847 if (save && filename)
1849 char *args =
1850 pwmd_strdup_printf ("%s %s%s %s%s %s",
1851 symmetric ? "--symmetric" : "",
1852 keyid ? "--keyid=" : "",
1853 keyid ? keyid : "",
1854 sign_keyid ? "--sign-keyid=" : "",
1855 sign_keyid ? sign_keyid : "",
1856 keyparams ? "--inquire-keyparam" : "");
1858 #ifdef HAVE_LIBREADLINE
1859 if (!quiet || interactive)
1861 #else
1862 if (!quiet)
1864 #endif
1865 fprintf (stderr, "\n");
1866 fprintf (stderr, N_("Saving changes ...\n"));
1869 rc = save_command (args);
1870 pwmd_free (args);
1873 #ifdef HAVE_LIBREADLINE
1874 if (interactive)
1875 return rc ? rc : quit ? 0 : GPG_ERR_CANCELED;
1876 #endif
1878 return rc;
1881 static void
1882 parse_status_ignore (char *str)
1884 char *s;
1886 strv_free (status_ignore);
1887 status_ignore = NULL;
1888 if (!str || !*str)
1889 return;
1891 while ((s = strsep (&str, ",")))
1893 char **p = strv_cat (status_ignore, pwmd_strdup (s));
1895 if (!p)
1897 strv_free (status_ignore);
1898 status_ignore = NULL;
1899 break;
1901 status_ignore = p;
1906 main (int argc, char *argv[])
1908 int connected = 0;
1909 int status_state = 0;
1910 gpg_error_t rc;
1911 int opt;
1912 char command[ASSUAN_LINELENGTH], *p = NULL;
1913 char *result = NULL;
1914 size_t len = 0;
1915 char *pinentry_path = NULL;
1916 char *display = NULL, *tty = NULL, *ttytype = NULL;
1917 char *lcctype = NULL, *lcmessages = NULL;
1918 int outfd = STDOUT_FILENO;
1919 FILE *outfp = stdout;
1920 int show_status = 1;
1921 const char *clientname = "pwmc";
1922 char *inquire = NULL;
1923 char *inquire_line = NULL;
1924 int timeout = 0;
1925 #ifdef WITH_SSH
1926 int use_ssh_agent = -1;
1927 char *knownhosts = NULL;
1928 char *identity = NULL;
1929 int needs_passphrase = 0;
1930 char *ssh_passphrase_file = NULL;
1931 #endif
1932 #ifdef WITH_GNUTLS
1933 char *cacert = NULL;
1934 char *clientcert = NULL;
1935 char *clientkey = NULL;
1936 char *prio = NULL;
1937 int tls_verify = -1;
1938 char *tls_fingerprint = NULL;
1939 #endif
1940 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1941 pwmd_socket_t socktype;
1942 long socket_timeout = 300;
1943 int connect_timeout = 120;
1944 #endif
1945 #ifdef HAVE_LIBREADLINE
1946 int no_interactive = 0;
1947 #endif
1948 int lock_on_open = -1;
1949 long lock_timeout = 50;
1950 char *url = NULL;
1951 char *tmp = NULL;
1952 /* The order is important. */
1953 enum
1955 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1956 OPT_SOCKET_TIMEOUT, OPT_CONNECT_TIMEOUT,
1957 #endif
1958 #ifdef WITH_SSH
1959 OPT_USE_SSH_AGENT, OPT_IDENTITY, OPT_KNOWNHOSTS, OPT_SSH_NEEDS_PASSPHRASE,
1960 OPT_SSH_PASSPHRASE_FILE,
1961 #endif
1962 #ifdef WITH_GNUTLS
1963 OPT_CACERT, OPT_CLIENTCERT, OPT_CLIENTKEY, OPT_PRIORITY, OPT_VERIFY,
1964 OPT_SERVER_FP,
1965 #endif
1966 OPT_URL, OPT_LOCAL, OPT_TTYNAME, OPT_TTYTYPE, OPT_DISPLAY, OPT_LC_CTYPE,
1967 OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES, OPT_PINENTRY, OPT_KEYFILE,
1968 OPT_PASSPHRASE_FILE, OPT_NEW_KEYFILE, OPT_NEW_PASSPHRASE_FILE,
1969 OPT_SIGN_KEYFILE, OPT_SIGN_PASSPHRASE_FILE, OPT_NOLOCK, OPT_LOCK_TIMEOUT,
1970 OPT_SAVE, OPT_OUTPUT_FD, OPT_INQUIRE, OPT_INQUIRE_FD, OPT_INQUIRE_FILE,
1971 OPT_INQUIRE_LINE, OPT_NO_STATUS, OPT_STATUS_IGNORE, OPT_STATUSFD, OPT_NAME,
1972 OPT_VERSION, OPT_HELP, OPT_KEYID, OPT_SIGN_KEYID, OPT_SYMMETRIC,
1973 OPT_KEYPARAMS, OPT_NO_PINENTRY, OPT_QUIET, OPT_STATUS_STATE,
1974 #ifdef HAVE_LIBREADLINE
1975 OPT_NO_INTERACTIVE,
1976 #endif
1978 const struct option long_opts[] = {
1979 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1980 {"socket-timeout", 1, 0, 0},
1981 {"connect-timeout", 1, 0, 0},
1982 #endif
1984 #ifdef WITH_SSH
1985 {"no-ssh-agent", 0, 0, 0},
1986 {"identity", 1, 0, 'i'},
1987 {"knownhosts", 1, 0, 'k'},
1988 {"ssh-needs-passphrase", 0, 0, 0},
1989 {"ssh-passphrase-file", 1, 0, 0},
1990 #endif
1991 #ifdef WITH_GNUTLS
1992 {"ca-cert", 1, 0, 0},
1993 {"client-cert", 1, 0, 0},
1994 {"client-key", 1, 0, 0},
1995 {"tls-priority", 1, 0, 0},
1996 {"no-tls-verify", 0, 0, 0},
1997 {"tls-fingerprint", 1, 0, 0},
1998 #endif
1999 {"url", 1, 0, 0},
2000 {"local-pinentry", 0, 0},
2001 {"ttyname", 1, 0, 'y'},
2002 {"ttytype", 1, 0, 't'},
2003 {"display", 1, 0, 'd'},
2004 {"lc-ctype", 1, 0, 0},
2005 {"lc-messages", 1, 0, 0},
2006 {"timeout", 1, 0, 0},
2007 {"tries", 1, 0, 0},
2008 {"pinentry", 1, 0, 0},
2009 {"key-file", 1, 0, 0},
2010 {"passphrase-file", 1, 0, 0},
2011 {"new-key-file", 1, 0, 0},
2012 {"new-passphrase-file", 1, 0, 0},
2013 {"sign-key-file", 1, 0, 0},
2014 {"sign-passphrase-file", 1, 0, 0},
2015 {"no-lock", 0, 0, 0},
2016 {"lock-timeout", 1, 0, 0},
2017 {"save", 0, 0, 'S'},
2018 {"output-fd", 1, 0, 0},
2019 {"inquire", 1, 0, 0},
2020 {"inquire-fd", 1, 0, 0},
2021 {"inquire-file", 1, 0, 0},
2022 {"inquire-line", 1, 0, 'L'},
2023 {"no-status", 0, 0, 0},
2024 {"status-ignore", 1, 0, 0},
2025 {"status-fd", 1, 0, 0},
2026 {"name", 1, 0, 'n'},
2027 {"version", 0, 0, 0},
2028 {"help", 0, 0, 0},
2029 {"keyid", 1, 0, 0},
2030 {"sign-keyid", 1, 0, 0},
2031 {"symmetric", 0, 0, 0},
2032 {"key-params", 1, 0, 0},
2033 {"no-pinentry", 0, 0, 0},
2034 {"quiet", 0, 0, 0},
2035 {"status-state", 0, 0, 0},
2036 #ifdef HAVE_LIBREADLINE
2037 {"no-interactive", 0, 0},
2038 #endif
2039 {0, 0, 0, 0}
2041 #ifdef WITH_SSH
2042 const char *optstring = "L:y:t:d:P:I:Sn:i:k:s";
2043 #else
2044 const char *optstring = "L:y:t:d:P:I:Sn:s";
2045 #endif
2046 int opt_index = 0;
2048 #ifdef ENABLE_NLS
2049 setlocale (LC_ALL, "");
2050 bindtextdomain ("libpwmd", LOCALEDIR);
2051 #endif
2053 tries = DEFAULT_PIN_TRIES;
2054 inquirefd = STDIN_FILENO;
2055 statusfd = STDERR_FILENO;
2056 statusfp = stderr;
2057 tmp = pwmd_strdup (DEFAULT_STATUS_IGNORE);
2058 parse_status_ignore (tmp);
2059 pwmd_free (tmp);
2060 no_pinentry = -1;
2061 local_pin = -1;
2063 while ((opt =
2064 getopt_long (argc, argv, optstring, long_opts, &opt_index)) != -1)
2066 switch (opt)
2068 /* Handle long options without a short option part. */
2069 case 0:
2070 switch (opt_index)
2072 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2073 case OPT_SOCKET_TIMEOUT:
2074 socket_timeout = strtol (optarg, &p, 10);
2075 break;
2076 case OPT_CONNECT_TIMEOUT:
2077 connect_timeout = strtol (optarg, &p, 10);
2078 break;
2079 #endif
2080 #ifdef WITH_SSH
2081 case OPT_USE_SSH_AGENT:
2082 use_ssh_agent = 0;
2083 break;
2084 case OPT_SSH_NEEDS_PASSPHRASE:
2085 needs_passphrase = 1;
2086 break;
2087 case OPT_SSH_PASSPHRASE_FILE:
2088 ssh_passphrase_file = optarg;
2089 break;
2090 #endif
2091 #ifdef WITH_GNUTLS
2092 case OPT_CACERT:
2093 cacert = optarg;
2094 break;
2095 case OPT_CLIENTCERT:
2096 clientcert = optarg;
2097 break;
2098 case OPT_CLIENTKEY:
2099 clientkey = optarg;
2100 break;
2101 case OPT_PRIORITY:
2102 prio = optarg;
2103 break;
2104 case OPT_VERIFY:
2105 tls_verify = 0;
2106 break;
2107 case OPT_SERVER_FP:
2108 tls_fingerprint = optarg;
2109 break;
2110 #endif
2111 case OPT_SYMMETRIC:
2112 symmetric = 1;
2113 break;
2114 case OPT_KEYPARAMS:
2115 keyparams = optarg;
2116 break;
2117 case OPT_KEYFILE:
2118 case OPT_PASSPHRASE_FILE:
2119 keyfile = pwmd_strdup (optarg);
2120 break;
2121 case OPT_NEW_KEYFILE:
2122 case OPT_NEW_PASSPHRASE_FILE:
2123 new_keyfile = pwmd_strdup (optarg);
2124 break;
2125 case OPT_SIGN_KEYFILE:
2126 case OPT_SIGN_PASSPHRASE_FILE:
2127 sign_keyfile = pwmd_strdup (optarg);
2128 break;
2129 case OPT_NOLOCK:
2130 lock_on_open = 0;
2131 break;
2132 case OPT_LOCK_TIMEOUT:
2133 lock_timeout = strtol (optarg, &p, 10);
2134 break;
2135 case OPT_URL:
2136 url = optarg;
2137 break;
2138 case OPT_LOCAL:
2139 local_pin = 1;
2140 break;
2141 case OPT_LC_CTYPE:
2142 lcctype = pwmd_strdup (optarg);
2143 break;
2144 case OPT_LC_MESSAGES:
2145 lcmessages = pwmd_strdup (optarg);
2146 break;
2147 case OPT_TIMEOUT:
2148 timeout = strtol (optarg, &p, 10);
2149 break;
2150 case OPT_TRIES:
2151 tries = strtol (optarg, &p, 10);
2152 break;
2153 case OPT_INQUIRE:
2154 inquire = escape (optarg);
2155 break;
2156 case OPT_INQUIRE_FD:
2157 inquirefd = strtol (optarg, &p, 10);
2158 break;
2159 case OPT_INQUIRE_FILE:
2160 inquirefd = open (optarg, O_RDONLY);
2161 if (inquirefd == -1)
2162 err (EXIT_FAILURE, "%s", optarg);
2163 break;
2164 case OPT_OUTPUT_FD:
2165 outfd = strtol (optarg, &p, 10);
2166 if (!p || !*p)
2168 outfp = fdopen (outfd, "w");
2169 if (!outfp)
2170 err (EXIT_FAILURE, "%i", outfd);
2172 break;
2173 case OPT_NO_STATUS:
2174 show_status = 0;
2175 break;
2176 case OPT_STATUSFD:
2177 statusfd = strtol (optarg, &p, 10);
2178 if (!p || !*p)
2180 statusfp = fdopen (statusfd, "w");
2181 if (!statusfp)
2182 err (EXIT_FAILURE, "%i", statusfd);
2184 break;
2185 case OPT_STATUS_IGNORE:
2186 parse_status_ignore (optarg);
2187 break;
2188 case OPT_VERSION:
2189 printf ("%s (pwmc)\n\n"
2190 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017\n"
2191 "%s\n"
2192 "Released under the terms of the LGPL v2.1. Use at your own risk.\n\n"
2193 "Compile-time features:\n"
2194 #ifdef HAVE_LIBREADLINE
2195 "+INTERACTIVE "
2196 #else
2197 "-INTERACTIVE "
2198 #endif
2199 #ifdef WITH_SSH
2200 "+SSH "
2201 #else
2202 "-SSH "
2203 #endif
2204 #ifdef WITH_GNUTLS
2205 "+GNUTLS "
2206 #else
2207 "-GNUTLS "
2208 #endif
2209 #ifdef WITH_PINENTRY
2210 "+PINENTRY "
2211 #else
2212 "-PINENTRY "
2213 #endif
2214 #ifdef WITH_QUALITY
2215 "+QUALITY "
2216 #else
2217 "-QUALITY "
2218 #endif
2219 #ifdef MEM_DEBUG
2220 "+MEM_DEBUG "
2221 #else
2222 "-MEM_DEBUG "
2223 #endif
2224 "\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
2225 exit (EXIT_SUCCESS);
2226 case OPT_PINENTRY:
2227 pinentry_path = optarg;
2228 break;
2229 case OPT_HELP:
2230 usage (argv[0], EXIT_SUCCESS);
2231 case OPT_KEYID:
2232 keyid = optarg;
2233 break;
2234 case OPT_SIGN_KEYID:
2235 sign_keyid = optarg;
2236 break;
2237 case OPT_QUIET:
2238 quiet = 1;
2239 show_status = 0;
2240 break;
2241 case OPT_STATUS_STATE:
2242 status_state = 1;
2243 break;
2244 case OPT_NO_PINENTRY:
2245 no_pinentry = 1;
2246 break;
2247 #ifdef HAVE_LIBREADLINE
2248 case OPT_NO_INTERACTIVE:
2249 no_interactive = 1;
2250 break;
2251 #endif
2252 default:
2253 usage (argv[0], EXIT_FAILURE);
2256 if (p && *p)
2258 fprintf (stderr, N_("%s: invalid argument for option '--%s'\n"),
2259 argv[0], long_opts[opt_index].name);
2260 usage (argv[0], EXIT_FAILURE);
2263 break;
2264 #ifdef WITH_SSH
2265 case 'i':
2266 identity = optarg;
2267 break;
2268 case 'k':
2269 knownhosts = optarg;
2270 break;
2271 #endif
2272 case 'L':
2273 inquire_line = optarg;
2274 break;
2275 case 'y':
2276 tty = optarg;
2277 break;
2278 case 't':
2279 ttytype = optarg;
2280 break;
2281 case 'd':
2282 display = optarg;
2283 break;
2284 case 'S':
2285 save = 1;
2286 break;
2287 case 'n':
2288 clientname = optarg;
2289 break;
2290 default:
2291 usage (argv[0], EXIT_FAILURE);
2295 #ifdef HAVE_LIBREADLINE
2296 if (isatty (STDIN_FILENO) && !inquire && !inquire_line && !no_interactive)
2297 interactive = 1;
2298 #endif
2300 pwmd_init ();
2301 rc = pwmd_new (clientname, &pwm);
2302 if (rc)
2303 goto done;
2305 filename = argv[optind] ? pwmd_strdup (argv[optind]) : NULL;
2306 if (no_pinentry != -1)
2307 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
2308 else
2309 rc = pwmd_getopt (pwm, PWMD_OPTION_NO_PINENTRY, &no_pinentry);
2310 if (rc)
2311 goto done;
2313 if (local_pin != -1)
2314 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local_pin);
2315 else
2316 rc = pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local_pin);
2317 if (rc)
2318 goto done;
2320 pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
2321 if (!quiet)
2322 fprintf (stderr, N_("Connecting ...\n"));
2324 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
2325 socktype = is_remote_url (url);
2326 if (socktype != PWMD_SOCKET_LOCAL)
2328 local_pin = 1;
2329 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2330 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, connect_timeout);
2331 if (rc)
2332 goto done;
2333 #endif
2335 if (socktype == PWMD_SOCKET_SSH)
2337 #ifdef WITH_SSH
2338 if (use_ssh_agent == -1)
2339 rc = pwmd_getopt (pwm, PWMD_OPTION_SSH_AGENT, &use_ssh_agent);
2341 if (!rc)
2343 if (!getenv ("SSH_AUTH_SOCK") || identity)
2344 use_ssh_agent = 0;
2346 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_AGENT, use_ssh_agent);
2347 if (rc)
2348 goto done;
2350 else
2351 goto done;
2353 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_NEEDS_PASSPHRASE,
2354 needs_passphrase);
2355 if (rc)
2356 goto done;
2358 if (ssh_passphrase_file)
2360 struct stat st;
2361 int fd;
2363 if (stat (ssh_passphrase_file, &st) == -1)
2365 rc = gpg_error_from_syserror ();
2366 fprintf(stderr, "%s: %s\n", ssh_passphrase_file,
2367 gpg_strerror (rc));
2368 goto done;
2371 result = pwmd_calloc (1, st.st_size+1);
2372 if (!result)
2374 rc = GPG_ERR_ENOMEM;
2375 goto done;
2378 fd = open (ssh_passphrase_file, O_RDONLY);
2379 if (fd != -1)
2381 len = read (fd, result, st.st_size);
2382 if (len == st.st_size)
2383 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_PASSPHRASE, result);
2384 else
2385 rc = gpg_error_from_syserror ();
2387 close (fd);
2389 else
2390 rc = gpg_error_from_syserror ();
2392 pwmd_free (result);
2393 result = NULL;
2394 len = 0;
2396 if (rc)
2398 fprintf(stderr, "%s: %s\n", ssh_passphrase_file,
2399 gpg_strerror (rc));
2400 goto done;
2404 rc = pwmd_connect (pwm, url, identity, knownhosts);
2405 #endif
2407 #ifdef WITH_GNUTLS
2408 else
2410 if (tls_verify != -1)
2412 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_VERIFY, tls_verify);
2413 if (rc)
2414 goto done;
2417 if (prio)
2418 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_PRIORITY, prio);
2420 if (!rc)
2421 rc = pwmd_connect (pwm, url, clientcert, clientkey, cacert,
2422 tls_fingerprint);
2424 #endif
2426 else
2427 rc = pwmd_connect (pwm, url);
2428 #else
2429 rc = pwmd_connect (pwm, url);
2430 #endif
2431 if (rc)
2432 goto done;
2434 if (!quiet)
2435 fprintf (stderr, N_("Connected.\n"));
2437 connected = 1;
2438 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2439 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, socket_timeout);
2440 if (rc)
2441 goto done;
2442 #endif
2444 if (lock_timeout)
2446 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
2447 "OPTION LOCK-TIMEOUT=%li", lock_timeout);
2448 if (rc)
2449 goto done;
2452 if (status_state)
2454 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION CLIENT-STATE=1");
2455 if (rc)
2456 goto done;
2459 if (lock_on_open != -1)
2461 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCK_ON_OPEN, lock_on_open);
2462 if (rc)
2463 goto done;
2466 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, NULL, NULL);
2467 if (rc)
2468 goto done;
2470 if (timeout > 0)
2472 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
2473 if (rc)
2474 goto done;
2477 if (pinentry_path)
2479 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
2480 if (rc)
2481 goto done;
2484 if (display)
2486 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
2487 if (rc)
2488 goto done;
2491 if (tty)
2493 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, tty);
2494 if (rc)
2495 goto done;
2498 if (ttytype)
2500 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
2501 if (rc)
2502 goto done;
2505 if (lcctype)
2507 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
2508 if (rc)
2509 goto done;
2512 if (lcmessages)
2514 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES, lcmessages);
2515 if (rc)
2516 goto done;
2519 if (show_status)
2521 rc = pwmd_setopt (pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
2522 if (rc)
2523 goto done;
2526 if (filename)
2528 rc = open_command (filename);
2529 if (rc)
2530 goto done;
2533 #ifdef HAVE_LIBREADLINE
2534 if (interactive)
2536 rc = do_interactive ();
2537 result = NULL;
2538 goto do_exit;
2540 #endif
2542 if (inquire)
2544 struct inquire_s *inq = NULL;
2546 rc = set_inquire (inquirefd, inquire_line, &inq);
2547 if (!rc)
2548 rc = pwmd_command (pwm, &result, &len, inquire_cb, inq, "%s", inquire);
2550 free_inquire (inq);
2551 goto done;
2554 if (fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1)
2556 rc = gpg_error_from_errno (errno);
2557 goto done;
2560 ssize_t n;
2562 for (;;)
2564 rc = process_cmd ();
2566 if (rc)
2567 goto done;
2569 n = read (STDIN_FILENO, command, sizeof (command)-1);
2570 if (n == -1)
2572 if (errno == EAGAIN)
2574 usleep (100000);
2575 continue;
2578 rc = gpg_error_from_errno (errno);
2579 goto done;
2581 else if (!n)
2582 goto done;
2584 p = command;
2585 command[n] = 0;
2586 break;
2589 if (!p || !*p || !strcasecmp (p, "BYE"))
2590 goto done;
2593 struct inquire_s *inq = NULL;
2594 rc = set_inquire (inquirefd, inquire_line, &inq);
2595 if (!rc)
2597 rc = parse_dotcommand (command, &result, &len, inq);
2598 free_inquire (inq);
2601 if (rc)
2602 goto done;
2604 done:
2605 if (result)
2607 fwrite (result, 1, result[len - 1] == 0 ? len - 1 : len, outfp);
2608 fflush (outfp);
2609 pwmd_free (result);
2612 result = NULL;
2613 if (!rc)
2614 rc = finalize ();
2615 else if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
2616 (void) pwmd_command (pwm, &result, NULL, NULL, NULL,
2617 "GETINFO last_error");
2619 #ifdef HAVE_LIBREADLINE
2620 do_exit:
2621 #endif
2622 wipememory (command, 0, sizeof (command));
2624 if (rc && !quiet)
2625 show_error (pwm, rc, result);
2627 pwmd_close (pwm);
2628 reset_keyfiles ();
2629 pwmd_deinit ();
2630 pwmd_free (result);
2631 pwmd_free (filename);
2632 pwmd_free (inquire);
2633 strv_free (status_ignore);
2634 if (connected && !quiet)
2635 fprintf (stderr, N_("Connection closed.\n"));
2637 exit (rc ? EXIT_FAILURE : EXIT_SUCCESS);