pwmc: Add algorithm to .listkeys output.
[libpwmd.git] / src / pwmc.c
blob37201869f7a9cee2aee64053637677fcdf3337b1
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015,
3 2016
4 Ben Kibbey <bjk@luxsci.net>
6 This file is part of libpwmd.
8 Libpwmd is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
13 Libpwmd is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Libpwmd. If not, see <http://www.gnu.org/licenses/>.
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <stdint.h>
29 #include <err.h>
30 #include <errno.h>
31 #include <string.h>
32 #include <libpwmd.h>
33 #include <assuan.h>
34 #include <sys/select.h>
35 #include <fcntl.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <libgen.h>
39 #include <termios.h>
40 #include <limits.h>
41 #include <ctype.h>
43 #include "util-string.h"
44 #include "util-slist.h"
46 #ifdef WITH_GNUTLS
47 #include <gnutls/gnutls.h>
48 #endif
50 #ifdef HAVE_LOCALE_H
51 #include <locale.h>
52 #endif
54 #ifdef HAVE_GETOPT_LONG
55 #ifdef HAVE_GETOPT_H
56 #include <getopt.h>
57 #endif
58 #else
59 #include "getopt_long.h"
60 #endif
62 #ifdef HAVE_LIBREADLINE
63 #if defined(HAVE_READLINE_READLINE_H)
64 #include <readline/readline.h>
65 #elif defined(HAVE_READLINE_H)
66 #include <readline.h>
67 #endif /* !defined(HAVE_READLINE_H) */
68 static int interactive_error;
69 static int interactive;
70 #endif /* HAVE_LIBREADLINE */
72 #ifdef HAVE_READLINE_HISTORY
73 #if defined(HAVE_READLINE_HISTORY_H)
74 #include <readline/history.h>
75 #elif defined(HAVE_HISTORY_H)
76 #include <history.h>
77 #endif
78 #endif /* HAVE_READLINE_HISTORY */
80 #ifndef LINE_MAX
81 #define LINE_MAX 2048
82 #endif
84 #include "gettext.h"
85 #define N_(msgid) gettext(msgid)
87 #include "mem.h"
90 #define DEFAULT_STATUS_IGNORE "KEEPALIVE,GPGME,PASSPHRASE_INFO,PASSPHRASE_HINT"
91 #define DEFAULT_PIN_TIMEOUT 30
92 #define DEFAULT_PIN_TRIES 3
93 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
94 ? gpg_error(rc) : rc
96 static int no_pinentry;
97 static pwm_t *pwm;
98 static char *filename;
99 static int save;
100 static char *keyid;
101 static char *sign_keyid;
102 static int symmetric;
103 static char *keyparams;
104 static char *keyfile;
105 static char *new_keyfile;
106 static char *sign_keyfile;
107 static int tries;
108 static int local_pin;
109 static int inquirefd;
110 static int statusfd;
111 FILE *statusfp;
112 static int quiet;
113 static char **status_ignore;
115 struct inquire_s
117 int fd;
118 char *line;
119 size_t len;
120 size_t size; // from stat(2).
121 char *last_keyword;
124 struct userid_s {
125 char *userid;
126 char *name;
127 char *email;
128 char *comment;
131 struct keyid_s {
132 char *keyid;
133 char *fpr;
134 char *card;
135 int can_sign;
136 int can_encrypt;
137 int can_certify;
138 int can_auth;
139 int expired;
140 time_t expires;
141 time_t created;
142 int secret;
143 int revoked;
144 int algo;
145 unsigned bits;
146 char *curve;
147 struct slist_s *userids;
148 struct slist_s *subkeys;
151 static gpg_error_t finalize ();
152 static gpg_error_t set_inquire (int fd, const char *line,
153 struct inquire_s **result);
154 static gpg_error_t parse_dotcommand (const char *line, char **result,
155 size_t * len, struct inquire_s *inq);
156 static gpg_error_t open_command (char *line);
158 static void
159 show_error (pwm_t *pwm, gpg_error_t rc, const char *str)
161 #ifdef WITH_GNUTLS
162 const char *tlsstr;
163 int e = pwmd_gnutls_error (pwm, &tlsstr);
165 if (e)
166 fprintf(stderr, "TLS: %s\n", tlsstr);
167 #endif
168 fprintf (stderr, "ERR %i: %s%s%s%s", rc, gpg_strerror (rc),
169 str ? ": " : "", str ? str : "", str ? "" : "\n");
172 static void
173 reset_keyfiles ()
175 pwmd_free (keyfile);
176 pwmd_free (new_keyfile);
177 pwmd_free (sign_keyfile);
178 keyfile = new_keyfile = sign_keyfile = NULL;
181 static void
182 usage (const char *pn, int status)
184 fprintf (status == EXIT_FAILURE ? stderr : stdout,
185 N_("Usage: pwmc [options] [file]\n"
186 " --url <string>\n"
187 " a url string to connect to (%s, see below)\n"
188 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
189 " --connect-timeout <seconds>\n"
190 " seconds before connecting to a remote host fails (0=disabled, 120)\n"
191 " --socket-timeout <seconds>\n"
192 " seconds before a remote command fails (0=disabled, 300)\n"
193 #endif
194 #ifdef WITH_GNUTLS
195 " --ca-cert <filename>\n"
196 " certificate authority (CA) used to sign the server cert\n"
197 " --client-cert <filename>\n"
198 " client certificate to use for authentication\n"
199 " --client-key <filename>\n"
200 " key file used to protect the client certificate\n"
201 " --tls-priority <string>\n"
202 " compression, cipher and hash algorithm string\n"
203 " (SECURE256:SECURE192:SECURE128:-VERS-SSL3.0)\n"
204 " --tls-verify\n"
205 " verify the hostname against the server certificate\n"
206 " --tls-fingerprint <string>\n"
207 " a SHA-256 hash of the server fingerprint to verify against\n"
208 #endif
209 #ifdef WITH_SSH
210 " --no-ssh-agent\n"
211 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
212 " --identity, -i <filename>\n"
213 " the ssh identity file to use for authentication\n"
214 " --knownhosts, -k <filename>\n"
215 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
216 " --ssh-needs-passphrase\n"
217 " prompt for a passphrase for the SSH identity file\n"
218 " --ssh-passphrase-file <filename>\n"
219 " read the SSH private key passphrase from filename\n"
220 #endif
221 " --no-lock\n"
222 " do not lock the data file upon opening it\n"
223 " --lock-timeout <N>\n"
224 " time in tenths of a second to wait for a locked data file (50)\n"
225 " --name, -n <string>\n"
226 " set the client name\n"
227 " --pinentry <path>\n"
228 " the full path to the pinentry binary\n"
229 " --local-pinentry\n"
230 " force using a local pinentry\n"
231 " --no-pinentry\n"
232 " disable pinentry both remotely and locally\n"
233 " --ttyname, -y <path>\n"
234 " tty that pinentry will use\n"
235 " --ttytype, -t <string>\n"
236 " pinentry terminal type (default is $TERM)\n"
237 " --display, -d\n"
238 " pinentry display (default is $DISPLAY)\n"
239 " --lc-ctype <string>\n"
240 " locale setting for pinentry\n"
241 " --lc-messages <string>\n"
242 " locale setting for pinentry\n"
243 " --tries <N>\n"
244 " number of pinentry tries before failing (3)\n"
245 " --timeout <seconds>\n"
246 " pinentry timeout\n"
247 " --inquire <COMMAND>\n"
248 " the specified command (with any options) uses a server inquire while\n"
249 " command data is read via the inquire file descriptor (stdin)\n"
250 " --inquire-line, -L <STRING>\n"
251 " the initial line to send (i.e., element path) before the inquire data\n"
252 " --inquire-fd <FD>\n"
253 " read inquire data from the specified file descriptor (stdin)\n"
254 " --inquire-file <filename>\n"
255 " read inquire data from the specified filename\n"
256 " --output-fd <FD>\n"
257 " redirect command output to the specified file descriptor\n"
258 " --save, -S\n"
259 " send the SAVE command before exiting\n"
260 " --passphrase-file <filename>\n"
261 " obtain the passphrase from the specified filename\n"
262 " --new-passphrase-file <filename>\n"
263 " obtain the passphrase to save with from the specified filename\n"
264 " --sign-passphrase-file <filename>\n"
265 " obtain the passphrase to sign with (symmetric) from the specified filename\n"
266 " --key-params <filename>\n"
267 " key parameters to use for key generation (pwmd default)\n"
268 " --keyid <recipient>[,<recipient>]\n"
269 " the public key ID to u\n"
270 " --sign-keyid <string>\n"
271 " the key ID to sign the data file with\n"
272 " --symmetric\n"
273 " use conventional encryption with optional signer(s) for new files\n"
274 " --no-status\n"
275 " disable showing of status messages from the server\n"
276 " --status-state\n"
277 " enable receiving of client STATE status messages\n"
278 " --status-fd <FD>\n"
279 " redirect status messages to the specified file descriptor\n"
280 " --status-ignore <string[,...]>\n"
281 " prevent parsing of the specified status message keywords\n"
282 " --quiet\n"
283 " disable showing of extra messages (implies --no-status)\n"
284 #ifdef HAVE_LIBREADLINE
285 " --no-interactive\n"
286 " disable interactive mode\n"
287 #endif
288 " --version\n"
289 " --help\n"),
290 #ifdef DEFAULT_PWMD_SOCKET
291 DEFAULT_PWMD_SOCKET
292 #else
293 "~/.pwmd/socket"
294 #endif
296 fprintf (status == EXIT_FAILURE ? stderr : stdout,
297 N_("\n"
298 "An optional url may be in the form of:\n"
299 " --url /path/to/socket\n"
300 " --url file://[path/to/socket]\n"
301 #ifdef WITH_SSH
302 " or\n"
303 " --url ssh[46]://[username@]hostname[:port]\n"
304 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
305 #endif
306 #ifdef WITH_GNUTLS
307 " or\n"
308 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
309 " --client-key filename\n"
310 #endif
311 #ifdef HAVE_LIBREADLINE
312 "\n"
313 "Interactive mode is used when input is from a terminal.\n"
314 #endif
316 exit (status);
319 static gpg_error_t
320 inquire_cb (void *user, const char *keyword, gpg_error_t rc,
321 char **data, size_t * size)
323 struct inquire_s *inq = user;
324 int is_password = 0;
325 int is_newpassword = 0;
326 int sign = 0;
327 int is_keyparam = 0;
329 *data = NULL;
330 *size = 0;
332 if (rc)
333 return rc;
335 if (!strcmp (keyword, "PASSPHRASE"))
336 is_password = 1;
337 else if (!strcmp (keyword, "SIGN_PASSPHRASE"))
338 sign = 1;
339 else if (!strcmp (keyword, "NEW_PASSPHRASE"))
340 is_newpassword = 1;
341 #ifdef HAVE_LIBREADLINE
342 else if (!strcmp (keyword, "KEYPARAM") && !interactive)
344 #else
345 else if (!strcmp (keyword, "KEYPARAM"))
347 #endif
348 int fd;
349 if (!keyparams || !*keyparams)
350 return gpg_error (GPG_ERR_INV_PARAMETER);
352 fd = open (keyparams, O_RDONLY);
353 if (fd == -1)
355 fprintf (stderr, "%s: %s\n", keyparams, strerror (errno));
356 return gpg_error_from_syserror ();
359 rc = set_inquire (fd, NULL, &inq);
360 if (rc)
362 close (fd);
363 return rc;
366 if (!quiet)
367 fprintf (stderr, N_("Using file '%s' as %s.\n"), keyparams, keyword);
369 is_keyparam = 1;
372 if ((is_password && !keyfile) || (is_newpassword && !new_keyfile)
373 || (sign && !sign_keyfile))
375 char *tmp;
376 int local;
378 /* Try to use the local pinentry between inquires (new/sign/passphrase).
379 * If --no-pinentry was specified then the passphrase is read from the
380 * terminal as usual. */
381 pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local);
382 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, 1);
383 rc = pwmd_password (pwm, keyword, &tmp, &inq->len);
384 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local);
385 if (rc && gpg_err_code (rc) != GPG_ERR_EOF)
386 return rc;
388 pwmd_free (inq->line);
389 inq->line = tmp;
390 *data = inq->line;
391 *size = inq->len;
392 return gpg_error (GPG_ERR_EOF);
394 else if ((is_newpassword && new_keyfile) || (is_password && keyfile)
395 || (sign && sign_keyfile))
397 int fd;
399 if (sign)
400 fd = open (sign_keyfile, O_RDONLY);
401 else
402 fd = open (is_password || sign ? keyfile : new_keyfile, O_RDONLY);
404 if (fd == -1)
406 if (sign)
407 fprintf (stderr, "%s: %s\n", sign_keyfile, strerror (errno));
408 else
409 fprintf (stderr, "%s: %s\n", is_newpassword ? new_keyfile
410 : keyfile, strerror (errno));
411 return gpg_error_from_syserror ();
414 rc = set_inquire (fd, NULL, &inq);
415 if (rc)
417 close (fd);
418 return rc;
421 if (!quiet)
422 fprintf (stderr, N_("Using keyfile '%s' as %s.\n"),
423 sign ? sign_keyfile : is_newpassword ? new_keyfile
424 : keyfile, keyword);
426 #ifdef HAVE_LIBREADLINE
427 else if ((!inq->last_keyword || strcmp (keyword, inq->last_keyword))
428 && interactive && inq->fd == STDIN_FILENO)
430 fprintf (stderr,
432 ("%sPress CTRL-D to send the current line. Press twice to end. %s:\n"),
433 inq->last_keyword ? "\n" : "", keyword);
434 pwmd_free (inq->last_keyword);
435 inq->last_keyword = pwmd_strdup (keyword);
437 #endif
439 /* The first part of the command data. */
440 if (inq->len)
442 *data = inq->line;
443 *size = inq->len;
444 inq->len = 0;
445 return inq->fd == -1 ? gpg_error (GPG_ERR_EOF) : 0;
448 *size = read (inq->fd, inq->line, ASSUAN_LINELENGTH);
449 if (*size == -1)
451 *size = 0;
452 return gpg_error (gpg_error_from_syserror ());
454 else if (*size)
455 *data = inq->line;
456 else if (inq->fd != STDIN_FILENO &&
457 (is_newpassword || is_password || sign || is_keyparam))
459 *inq->line = 0;
460 inq->size = 1;
461 *data = inq->line;
462 *size = 1;
465 if (((is_newpassword && new_keyfile) || (is_password && keyfile)
466 || (sign && sign_keyfile) || (keyparams && is_keyparam))
467 && *size == inq->size)
468 return gpg_error (GPG_ERR_EOF);
470 return *size ? 0 : gpg_error (GPG_ERR_EOF);
473 static int
474 status_msg_cb (void *data, const char *line)
476 char *p = strchr (line, ' ');
477 char **s;
479 /* Ignore status messages specified by the client via --status-ignore. */
480 for (s = status_ignore; s && *s; s++)
482 char *tmp = strchr (line, ' ');
483 size_t len = tmp ? strlen (line) - strlen (tmp) : strlen (line);
485 if (!strncmp (line, *s, len) && len == strlen (*s))
486 return 0;
489 #ifdef HAVE_LIBREADLINE
490 if (interactive && !strncmp (line, "XFER ", 5)
491 #else
492 if (!strncmp (line, "XFER ", 5)
493 #endif
494 && *line != '#' && p && strchr (p, ' ') && *++p)
496 char *p1 = strchr (p, ' ');
497 int a = strtol (p, NULL, 10);
499 if (isdigit (*p) && p1)
501 int b = strtol (p1, NULL, 10);
502 char l[64] = { 0 };
503 int t = a && b ? a * 100 / b : 0;
505 strncpy (l, line, strlen (line) - strlen (p) - 1);
506 fprintf (statusfp, "\rS:%s %i/%i %i%%%s", l, a, b, t,
507 a == b ? "\n" : "");
508 fflush (statusfp);
509 return 0;
513 fprintf (statusfp, "S:%s\n", line);
514 fflush (statusfp);
515 #ifdef HAVE_LIBREADLINE
516 rl_on_new_line ();
517 #endif
518 return 0;
521 static gpg_error_t
522 process_cmd ()
524 return pwmd_process (pwm);
527 #ifdef WITH_SSH
528 static gpg_error_t
529 knownhost_cb (void *data, const char *host, const char *key, size_t len)
531 gpg_error_t rc = 0;
532 char *buf =
533 pwmd_strdup_printf (N_
534 ("Password Manager Daemon: %s\n\nWhile attempting an SSH connection to %s there was a problem verifying it's hostkey against the known and trusted hosts file because it's hostkey was not found.\n\nWould you like to treat this connection as trusted for this and future connections by adding %s's hostkey to the known hosts file?\n"),
535 (char *) data, host, host);
537 if (no_pinentry && !isatty (STDIN_FILENO))
539 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
540 pwmd_free (buf);
541 return GPG_ERR_ENOTTY;
543 else if (no_pinentry)
545 for (char *p = buf, len = 0; *p; p++, len++)
547 if (*p == '\n')
548 len = 0;
550 if (len == 78)
552 char *t = p;
554 while (len && !isspace (*(--p)))
555 len--;
557 if (len)
558 *p = '\n';
559 len = 78 - len;
560 p = t;
563 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_PROMPT, N_("Accept [y/N]:"));
566 if (!rc)
567 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, buf);
569 pwmd_free (buf);
570 if (rc)
571 return rc;
573 return pwmd_getpin (pwm, NULL, NULL, NULL, PWMD_PINENTRY_CONFIRM);
575 #endif
577 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
578 static pwmd_socket_t
579 is_remote_url (const char *str)
581 if (!str)
582 return PWMD_SOCKET_LOCAL;
584 #ifdef WITH_SSH
585 if (strstr (str, "ssh://") || strstr (str, "ssh4://")
586 || strstr (str, "ssh6://"))
587 return PWMD_SOCKET_SSH;
588 #endif
590 #ifdef WITH_GNUTLS
591 if (strstr (str, "tls://") || strstr (str, "tls4://")
592 || strstr (str, "tls6://"))
593 return PWMD_SOCKET_TLS;
594 #endif
596 return PWMD_SOCKET_LOCAL;
598 #endif
600 static char *
601 escape (const char *str)
603 const char *p;
604 char *buf = pwmd_malloc (ASSUAN_LINELENGTH + 1), *b = buf;
605 size_t len = 0;
607 for (p = str; *p; p++, len++)
609 if (len == ASSUAN_LINELENGTH)
610 break;
612 if (*p == '\\')
614 switch (*++p)
616 case 't':
617 *b++ = '\t';
618 break;
619 case 'n':
620 *b++ = '\n';
621 break;
622 case 'v':
623 *b++ = '\v';
624 break;
625 case 'b':
626 *b++ = '\b';
627 break;
628 case 'f':
629 *b++ = '\f';
630 break;
631 case 'r':
632 *b++ = '\r';
633 break;
634 default:
635 *b++ = *p;
636 break;
639 if (!*p)
640 break;
642 continue;
645 *b++ = *p;
648 *b = 0;
649 return buf;
652 static void
653 free_inquire (struct inquire_s *inq)
655 if (!inq)
656 return;
658 pwmd_free (inq->line);
660 if (inq->fd != -1 && inq->fd != STDIN_FILENO)
661 close (inq->fd);
663 pwmd_free (inq->last_keyword);
664 pwmd_free (inq);
667 /* When *result is not NULL it is updated to the new values and not
668 * reallocated. */
669 static gpg_error_t
670 set_inquire (int fd, const char *line, struct inquire_s **result)
672 struct inquire_s inq = { 0 };
673 struct stat st = { 0 };
674 gpg_error_t rc;
676 if (fd != -1)
678 if (fstat (fd, &st) == -1)
679 return gpg_error_from_syserror ();
681 inq.size = st.st_size;
684 inq.fd = fd;
685 inq.line = pwmd_calloc (1, ASSUAN_LINELENGTH);
686 if (!inq.line)
687 return GPG_ERR_ENOMEM;
689 if (line)
691 char *s = escape (line);
693 if (!s)
695 pwmd_free (inq.line);
696 return GPG_ERR_ENOMEM;
699 if (strlen (s) >= ASSUAN_LINELENGTH)
701 pwmd_free (inq.line);
702 pwmd_free (s);
703 return GPG_ERR_LINE_TOO_LONG;
706 strncpy (inq.line, s, ASSUAN_LINELENGTH - 1);
707 inq.len = strlen (s);
708 pwmd_free (s);
711 rc = pwmd_setopt (pwm, PWMD_OPTION_INQUIRE_TOTAL,
712 st.st_size ? st.st_size + strlen (inq.line) : 0);
713 if (rc)
715 pwmd_free (inq.line);
716 return rc;
719 if (*result == NULL)
720 *result = pwmd_malloc (sizeof (struct inquire_s));
721 else
723 if ((*result)->fd != -1 && (*result)->fd != STDIN_FILENO)
724 close ((*result)->fd);
726 pwmd_free ((*result)->line);
727 (*result)->line = NULL;
728 (*result)->fd = -1;
729 (*result)->len = 0;
732 memcpy (*result, &inq, sizeof (struct inquire_s));
733 memset (&inq, 0, sizeof (struct inquire_s));
734 return rc;
737 #ifdef HAVE_LIBREADLINE
738 static int
739 interactive_hook (void)
741 interactive_error = process_cmd ();
743 if (interactive_error)
744 rl_event_hook = NULL;
746 return 0;
749 static int
750 get_readline_char (FILE *fp)
752 if (rl_line_buffer
753 && (!strncmp (rl_line_buffer, ".set passphrase-file ", 16)
754 || !strncmp (rl_line_buffer, ".set new-passphrase-file ", 20)
755 || !strncmp (rl_line_buffer, ".set sign-passphrase-file ", 21)))
756 rl_inhibit_completion = 0;
757 else if (rl_line_buffer
758 && !strncmp (rl_line_buffer, ".redir ", 7))
760 char *p = strchr (rl_line_buffer, ' ');
762 if (strchr (++p, ' '))
763 rl_inhibit_completion = 1;
764 else
765 rl_inhibit_completion = 0;
767 else if (rl_line_buffer
768 && !strncmp (rl_line_buffer, ".read ", 6))
770 char *p = rl_line_buffer + 6;
772 if (strstr (p, "--prefix "))
774 p = strstr (p, "--prefix ");
775 p += 9;
776 p = strchr (p, ' ');
777 if (p)
778 p++;
781 if (!p || strchr (p, ' '))
782 rl_inhibit_completion = 1;
783 else
784 rl_inhibit_completion = 0;
786 else
787 rl_inhibit_completion = 1;
789 return fgetc (fp);
792 static void
793 print_help ()
795 fprintf (stderr,
797 ("------------------------------------------------------------\n"
798 "Elements are TAB delimited. Type HELP for protocol commands.\n"
799 "Type .help for pwmc commands. Press CTRL-D to quit.\n"
800 "------------------------------------------------------------\n"));
802 #endif
804 static char *
805 parse_arg (const char *src, char *dst, size_t len)
807 char *p = dst;
808 const char *s = src;
809 size_t n = 0;
811 for (; s && *s && *s != ' ' && n < len; s++, n++)
812 *p++ = *s;
814 *p = 0;
815 return dst;
818 static char *
819 parse_opt (char **line, const char *opt, gpg_error_t * rc)
821 static char result[ASSUAN_LINELENGTH] = { 0 }, *r = result;
822 char *s = strstr (*line, opt);
824 *rc = 0;
825 result[0] = 0;
826 r = result;
828 if (s)
830 size_t len = 0;
831 int quote = 0;
832 size_t rlen = strlen (opt);
833 char *p = s + rlen;
834 int lastc = 0;
836 while (*p && *p == ' ')
838 rlen++;
839 p++;
842 for (; *p && len < sizeof (result) - 1; p++, rlen++)
844 if (isspace (*p) && !quote)
845 break;
847 if (*p == '\"' && lastc != '\\')
849 quote = !quote;
850 lastc = *p;
851 continue;
854 *r++ = lastc = *p;
855 len++;
858 *r = 0;
860 if (len >= sizeof (result) - 1)
861 *rc = GPG_ERR_LINE_TOO_LONG;
862 else
864 p = s + rlen;
866 while (*p && *p == ' ')
867 p++;
869 *line = p;
873 return result;
876 static gpg_error_t
877 read_command (const char *line, char **result, size_t * len)
879 int fd;
880 gpg_error_t rc = 0;
881 char *file = NULL;
882 struct inquire_s *inq = NULL;
883 char *p = (char *) line;
884 const char *prefix = parse_opt (&p, "--prefix", &rc);
885 char filebuf[ASSUAN_LINELENGTH];
887 if (rc)
888 return rc;
890 rc = GPG_ERR_SYNTAX;
892 if (p && *p)
894 while (*p && isspace (*p))
895 p++;
897 file = parse_arg (p, filebuf, sizeof (filebuf));
898 if (file && *file)
900 p += strlen (file) + 1;
902 while (*p && isspace (*p))
903 p++;
905 if (*p)
906 rc = 0;
910 if (rc)
912 fprintf (stderr,
914 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
915 fprintf (stderr,
917 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\\ = \\)\n"));
918 return rc;
921 fd = open (file, O_RDONLY);
922 if (fd == -1)
923 return gpg_error_from_syserror ();
925 rc = set_inquire (fd, prefix && *prefix ? prefix : NULL, &inq);
926 if (rc)
928 close (fd);
929 return rc;
932 rc = pwmd_command (pwm, result, len, inquire_cb, inq, "%s", p);
933 free_inquire (inq);
934 return rc;
937 static gpg_error_t
938 redir_command (const char *line)
940 const char *p = line;
941 int fd;
942 gpg_error_t rc = GPG_ERR_SYNTAX;
943 char *file = NULL;
944 struct inquire_s *inq = NULL;
945 char *result = NULL;
946 size_t len = 0;
947 char filebuf[ASSUAN_LINELENGTH];
949 if (p && *p && *++p)
951 file = parse_arg (p, filebuf, sizeof (filebuf));
952 if (file && *file)
954 p += strlen (file) + 1;
956 while (*p && isspace (*p))
957 p++;
959 if (*p)
960 rc = 0;
964 if (rc)
966 fprintf (stderr, N_("Usage: .redir <filename> <command> [args]\n"));
967 return rc;
970 fd = open (file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
971 if (fd == -1)
972 return gpg_error_from_syserror ();
974 #ifdef HAVE_LIBREADLINE
975 rc = set_inquire (interactive ? STDIN_FILENO : inquirefd, NULL, &inq);
976 #else
977 rc = set_inquire (inquirefd, NULL, &inq);
978 #endif
979 if (rc)
981 close (fd);
982 return rc;
985 rc = parse_dotcommand (p, &result, &len, inq);
986 if (!rc && result && len--)
987 { // null byte which is always appended
988 if (write (fd, result, len) != len)
989 rc = GPG_ERR_TOO_SHORT;
990 pwmd_free (result);
993 free_inquire (inq);
994 close (fd);
995 return rc;
998 static gpg_error_t
999 help_command (const char *line)
1001 fprintf (stderr,
1002 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
1003 " .redir <filename> <command>\n"
1004 " redirect the output of a command to the specified file\n"
1005 "\n"
1006 " .open <filename>\n"
1007 " open the specified filename losing any changes to the current one\n"
1008 "\n"
1009 " .read [--prefix <string>] <filename> <command> [args]\n"
1010 " obtain data from the specified filename for an inquire command\n"
1011 "\n"
1012 " .set help | <name> [<value>]\n"
1013 " set option <name> to <value>\n"
1014 "\n"
1015 " .save [args]\n"
1016 " write changes of the file to disk\n"
1017 "\n"
1018 " .passwd [args]\n"
1019 " change the passphrase of a data file\n"
1020 "\n"
1021 " .listkeys [--options] [pattern[,..]]\n"
1022 " show human readable output of the LISTKEYS command\n"
1023 "\n"
1024 " .help\n"
1025 " this help text\n"));
1026 return 0;
1029 static gpg_error_t
1030 open_command (char *line)
1032 struct inquire_s *inq = NULL;
1033 const char *file = line;
1034 gpg_error_t rc;
1035 int local;
1037 while (file && isspace (*file))
1038 file++;
1040 if (!file || !*file)
1042 fprintf (stderr, N_("Usage: .open <filename>\n"));
1043 return GPG_ERR_SYNTAX;
1046 #ifdef HAVE_LIBREADLINE
1047 if (interactive || !quiet)
1048 #else
1049 if (!quiet)
1050 #endif
1051 fprintf (stderr, N_("Opening data file \"%s\" ...\n"), file);
1053 #ifdef HAVE_LIBREADLINE
1054 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1055 #else
1056 rc = set_inquire (-1, NULL, &inq);
1057 #endif
1058 if (rc)
1059 return rc;
1061 pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local);
1063 if (keyfile)
1065 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1066 if (!rc)
1067 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, 1);
1069 else
1070 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1072 if (!rc)
1073 rc = pwmd_open (pwm, file, inquire_cb, inq);
1075 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local);
1077 #ifdef HAVE_LIBREADLINE
1078 if (interactive)
1079 reset_keyfiles ();
1080 #endif
1082 free_inquire (inq);
1083 if (!rc && file != filename)
1085 pwmd_free (filename);
1086 filename = pwmd_strdup (file);
1089 return rc;
1092 static gpg_error_t
1093 set_command (const char *line)
1095 gpg_error_t rc = 0;
1096 char name[256] = { 0 };
1097 char value[512] = { 0 };
1098 char *namep;
1099 char *valuep;
1100 const char *p = line;
1102 while (p && *p && isspace (*p))
1103 p++;
1105 namep = parse_arg (p, name, sizeof (name));
1106 if (!namep || !*namep)
1108 fprintf (stderr, N_("Usage: .set help | <name> [<value>]\n"));
1109 return GPG_ERR_SYNTAX;
1112 p += strlen (namep);
1113 while (p && *p && isspace (*p))
1114 p++;
1116 valuep = parse_arg (p, value, sizeof (value));
1118 if (!strcmp (name, "passphrase-file") || !strcmp (name, "new-passphrase-file")
1119 || !strcmp (name, "sign-passphrase-file"))
1121 int is_newkeyfile = 1;
1122 int sign = !strcmp (name, "sign-passphrase-file");
1124 if (!strcmp (name, "passphrase-file") || sign)
1125 is_newkeyfile = 0;
1127 if (is_newkeyfile)
1129 pwmd_free (new_keyfile);
1130 new_keyfile = NULL;
1132 else if (sign)
1134 pwmd_free (sign_keyfile);
1135 sign_keyfile = NULL;
1137 else
1139 pwmd_free (keyfile);
1140 keyfile = NULL;
1143 if (!rc && *valuep)
1145 if (is_newkeyfile)
1146 new_keyfile = pwmd_strdup (value);
1147 else if (sign)
1148 sign_keyfile = pwmd_strdup (value);
1149 else
1150 keyfile = pwmd_strdup (value);
1152 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1154 else if (!local_pin && !no_pinentry)
1156 pwmd_socket_t t;
1158 pwmd_socket_type (pwm, &t);
1159 if (t == PWMD_SOCKET_LOCAL)
1160 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1163 else if (!strcmp(name, "pinentry-timeout"))
1165 char *e = NULL;
1166 int n = strtol(valuep, &e, 10);
1168 if (e && *e)
1169 return gpg_error (GPG_ERR_INV_VALUE);
1171 if (!*valuep)
1172 n = DEFAULT_PIN_TIMEOUT;
1174 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, n);
1176 else if (!strcmp (name, "help"))
1178 fprintf (stderr,
1180 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1181 "delimited. When no value is specified the option is unset.\n\n"
1182 "passphrase-file [<filename>]\n"
1183 " set or unset the file to be used when a passphrase is required (*)\n"
1184 "\n"
1185 "new-passphrase-file [<filename>]\n"
1186 " set or unset the file to be used when a new passphrase is required (*)\n"
1187 "\n"
1188 "sign-passphrase-file [<filename>]\n"
1189 " set or unset the file to be used when a passphrase is required for\n"
1190 " signing (symmetric) (*)\n"
1191 "\n"
1192 "pinentry-timeout <seconds>\n"
1193 " the amount of seconds before pinentry gives up waiting for input\n"
1194 "\n"
1195 "* = the next protocol command will unset this value\n"
1198 else
1199 rc = GPG_ERR_UNKNOWN_OPTION;
1201 return rc;
1204 static gpg_error_t
1205 do_save_passwd_command (const char *line, int save)
1207 struct inquire_s *inq = NULL;
1208 gpg_error_t rc;
1209 int local;
1211 #ifdef HAVE_LIBREADLINE
1212 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1213 #else
1214 rc = set_inquire (-1, NULL, &inq);
1215 #endif
1216 if (rc)
1217 return rc;
1219 pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local);
1221 if (new_keyfile || keyfile || sign_keyfile)
1223 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1224 if (!rc)
1225 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, 1);
1227 else
1228 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1230 if (!rc)
1232 if (save)
1233 rc = pwmd_save (pwm, line, inquire_cb, inq);
1234 else
1235 rc = pwmd_passwd (pwm, line, inquire_cb, inq);
1238 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local);
1240 #ifdef HAVE_LIBREADLINE
1241 if (interactive)
1242 reset_keyfiles ();
1243 #endif
1245 free_inquire (inq);
1246 return rc;
1249 static gpg_error_t
1250 save_command (const char *line)
1252 return do_save_passwd_command (line, 1);
1255 static void
1256 search_and_replace (char *str, const char *s, const char r)
1258 char *p;
1260 p = strstr (str, s);
1261 if (p)
1263 *p = r;
1264 while (*++p)
1265 *p = *(p+1);
1266 search_and_replace (str, s, r);
1267 return;
1271 static char *
1272 openpgp_unescape (char *str)
1274 search_and_replace (str, "\\x3a", ':');
1275 search_and_replace (str, "\\x5c", '\\');
1276 return str;
1279 static void
1280 free_listkeys (struct slist_s *keys)
1282 unsigned i, t;
1284 t = slist_length (keys);
1285 for (i = 0; i < t; i++)
1287 struct keyid_s *key = slist_nth_data (keys, i);
1288 unsigned n, nt;
1290 nt = slist_length (key->userids);
1291 for (n = 0; n < nt; n++)
1293 struct userid_s *userid = slist_nth_data (key->userids, n);
1295 pwmd_free (userid->userid);
1296 pwmd_free (userid->name);
1297 pwmd_free (userid->email);
1298 pwmd_free (userid->comment);
1299 pwmd_free (userid);
1302 slist_free (key->userids);
1303 nt = slist_length (key->subkeys);
1304 for (n = 0; n < nt; n++)
1306 struct keyid_s *sub = slist_nth_data (key->subkeys, n);
1308 pwmd_free (sub->keyid);
1309 pwmd_free (sub->fpr);
1310 pwmd_free (sub->card);
1311 pwmd_free (sub->curve);
1312 pwmd_free (sub);
1315 slist_free (key->subkeys);
1316 pwmd_free (key);
1319 slist_free (keys);
1322 static char *
1323 openpgp_algorithm (struct keyid_s *key)
1325 switch (key->algo)
1327 case 1:
1328 case 2:
1329 case 3:
1330 return "RSA";
1331 case 16:
1332 case 20:
1333 return "ELG";
1334 case 17:
1335 return "DSA";
1336 case 301:
1337 case 302:
1338 case 18:
1339 return "ECC";
1340 default:
1341 break;
1344 return N_("Unknown");
1347 static void
1348 display_listkeys (struct slist_s *keys)
1350 unsigned i, t;
1352 t = slist_length (keys);
1353 for (i = 0; i < t; i++)
1355 struct keyid_s *key = slist_nth_data (keys, i);
1356 unsigned st = slist_length (key->subkeys);
1357 unsigned s;
1358 unsigned ut = slist_length (key->userids);
1359 unsigned u;
1361 for (u = 0; u < ut; u++)
1363 struct userid_s *userid = slist_nth_data (key->userids, u);
1365 fprintf(stdout, N_("User ID: %s\n"), userid->userid);
1368 for (s = 0; s < st; s++)
1370 struct keyid_s *sub = slist_nth_data (key->subkeys, s);
1371 struct tm *tmp;
1372 char *caps = NULL;
1373 char expires[11] = { 0 };
1374 char created[11] = { 0 };
1376 if (sub->expires)
1378 tmp = localtime (&sub->expires);
1379 strftime (expires, sizeof (expires), "%F", tmp);
1382 tmp = localtime (&sub->created);
1383 strftime (created, sizeof (created), "%F", tmp);
1385 if (sub->can_encrypt)
1386 caps = "E";
1387 else if (sub->can_sign)
1388 caps = "S";
1389 else if (sub->can_auth)
1390 caps = "A";
1391 else if (sub->can_certify)
1392 caps = "C";
1394 fprintf(stdout, N_(
1395 " Subkey %u: %s [%s]%s%s %s-%u%s%s\n"
1396 " Created: %s %s%s\n"
1397 " Fingerprint: %s\n"
1398 "%s%s%s"),
1399 s+1,
1400 sub->keyid,
1401 caps,
1402 sub->secret || sub->card ? "[P]" : "",
1403 sub->revoked ? "[R]" : "",
1404 openpgp_algorithm (sub),
1405 sub->bits,
1406 sub->curve ? "-" : "",
1407 sub->curve ? sub->curve : "",
1408 created,
1409 sub->expired ? N_("Expired: ") : expires[0] ? N_("Expires: ") : "",
1410 sub->expired || expires[0] ? expires : "",
1411 sub->fpr,
1412 sub->card ? N_(" Card: ") : "",
1413 sub->card ? sub->card : "",
1414 sub->card ? "\n" : "");
1417 if (i+1 < t)
1418 fprintf (stdout, "\n");
1422 static gpg_error_t
1423 listkeys_command (const char *pattern)
1425 gpg_error_t rc;
1426 char *result;
1427 char **lines = NULL, **p;
1428 struct slist_s *keys = NULL;
1430 rc = pwmd_command (pwm, &result, NULL, NULL, NULL, "LISTKEYS %s", pattern);
1431 if (rc)
1432 return rc;
1434 lines = str_split (result, "\n", 0);
1435 pwmd_free (result);
1436 if (!lines)
1437 return GPG_ERR_ENOMEM;
1439 for (p = lines; *p; p++)
1441 struct keyid_s *key;
1442 char **fields = str_split (*p, ":", 0);
1443 int i, f;
1444 unsigned s;
1445 unsigned n_subkeys = 0;
1446 struct slist_s *tlist;
1448 if (!fields)
1450 rc = GPG_ERR_ENOMEM;
1451 break;
1454 key = pwmd_calloc (1, sizeof (struct keyid_s));
1455 if (!key)
1457 strv_free (fields);
1458 rc = GPG_ERR_ENOMEM;
1459 break;
1462 for (f = i = 0; i < 17; i++, f++)
1464 int b = 0;
1466 if (i < 10)
1467 b = atoi (fields[f]) != 0;
1469 switch (i)
1471 case 0: key->revoked = b; break;
1472 case 1: key->expired = b; break;
1473 case 4: key->can_encrypt = b; break;
1474 case 5: key->can_sign = b; break;
1475 case 7: key->secret = b; break;
1476 case 16: n_subkeys = strtoul (fields[f], NULL, 10); break;
1477 default:
1478 break;
1482 for (s = 0; s < n_subkeys; s++)
1484 struct keyid_s *sub;
1485 int b = 0;
1487 sub = pwmd_calloc (1, sizeof (struct keyid_s));
1488 if (!sub)
1490 strv_free (fields);
1491 rc = GPG_ERR_ENOMEM;
1492 break;
1495 for (i = 0; i < 20; i++, f++)
1497 if (i < 11)
1498 b = atoi (fields[f]) != 0;
1500 switch (i)
1502 case 0: sub->revoked = b; break;
1503 case 1: sub->expired = b; break;
1504 case 4: sub->can_encrypt = b; break;
1505 case 5: sub->can_sign = b; break;
1506 case 6: sub->can_certify = b; break;
1507 case 7: sub->secret = b; break;
1508 case 8: sub->can_auth = b; break;
1509 case 11: sub->algo = atoi (fields[f]); break;
1510 case 12: sub->bits = atoi (fields[f]); break;
1511 case 13: sub->keyid = pwmd_strdup (fields[f]); break;
1512 case 14: sub->fpr = pwmd_strdup (fields[f]); break;
1513 case 16: sub->created = strtoul (fields[f], NULL, 10); break;
1514 case 17: sub->expires = strtoul (fields[f], NULL, 10); break;
1515 case 18: sub->card = fields[f] && strlen(fields[f]) > 1
1516 ? pwmd_strdup (fields[f]) : NULL; break;
1517 case 19: sub->curve = strlen (fields[f]) > 1 ? pwmd_strdup (openpgp_unescape(fields[f])) : NULL; break;
1518 default:
1519 break;
1523 tlist = slist_append (key->subkeys, sub);
1524 if (!tlist)
1526 rc = GPG_ERR_ENOMEM;
1527 break;
1530 key->subkeys = tlist;
1533 if (rc)
1535 strv_free (fields);
1536 break;
1539 // Re-create a line containing the userIds.
1540 for (; f < strv_length (fields); f++)
1542 struct userid_s *userid;
1544 userid = pwmd_calloc (1, sizeof (struct userid_s));
1545 if (!userid)
1547 rc = GPG_ERR_ENOMEM;
1548 break;
1551 // Revoked.
1552 f++;
1553 // Invalid.
1554 f++;
1555 // Validity.
1556 f++;
1558 userid->userid = pwmd_strdup (openpgp_unescape (fields[f++]));
1559 userid->name = pwmd_strdup (openpgp_unescape (fields[f++]));
1560 userid->email = pwmd_strdup (openpgp_unescape (fields[f++]));
1561 userid->comment = pwmd_strdup (openpgp_unescape (fields[f]));
1563 tlist = slist_append (key->userids, userid);
1564 if (!tlist)
1566 rc = GPG_ERR_ENOMEM;
1567 break;
1570 key->userids = tlist;
1573 strv_free (fields);
1574 if (rc)
1575 break;
1577 tlist = slist_append (keys, key);
1578 if (!tlist)
1580 rc = GPG_ERR_ENOMEM;
1581 break;
1584 keys = tlist;
1587 strv_free (lines);
1589 if (!rc)
1590 display_listkeys (keys);
1592 free_listkeys (keys);
1593 return rc;
1596 static gpg_error_t
1597 parse_dotcommand (const char *line, char **result,
1598 size_t * len, struct inquire_s *inq)
1600 const char *p = line;
1601 gpg_error_t rc = 0;
1603 if (!strncmp (p, ".read", 5))
1604 rc = read_command (p + 5, result, len);
1605 else if (!strncmp (p, ".redir", 6))
1606 rc = redir_command (p + 6);
1607 else if (!strncmp (p, ".help", 5))
1608 rc = help_command (p + 5);
1609 else if (!strncmp (p, ".open", 5))
1610 rc = open_command ((char *)p + 5);
1611 else if (!strncmp (p, ".set", 4))
1612 rc = set_command (p + 4);
1613 else if (!strncmp (p, ".save", 5))
1614 rc = do_save_passwd_command (p + 5, 1);
1615 else if (!strncmp (p, ".passwd", 7))
1616 rc = do_save_passwd_command (p + 7, 0);
1617 else if (!strncmp (p, ".listkeys", 9))
1618 rc = listkeys_command (p+9);
1619 else
1621 rc = pwmd_command (pwm, result, len, inquire_cb, inq, "%s", line);
1622 #ifdef HAVE_LIBREADLINE
1623 if (interactive)
1625 #endif
1626 reset_keyfiles ();
1627 #ifdef HAVE_LIBREADLINE
1629 #endif
1631 if (!rc && !strncasecmp (line, "RESET", 5))
1633 pwmd_free (filename);
1634 filename = NULL;
1638 return FINISH (rc);
1641 #ifdef HAVE_LIBREADLINE
1642 #ifdef HAVE_READLINE_HISTORY
1643 static void
1644 add_history_item (const char *line)
1646 HIST_ENTRY **list, *p = NULL;
1647 int i;
1649 list = history_list ();
1650 for (i = 0; list && list[i]; i++)
1652 if (!strcmp (list[i]->line, line))
1654 p = list[i];
1655 break;
1659 if (p)
1661 char *s;
1663 p = remove_history (i);
1664 s = free_history_entry (p);
1665 free (s);
1668 add_history (line);
1670 #endif
1672 static gpg_error_t
1673 do_interactive ()
1675 gpg_error_t rc;
1676 struct inquire_s *inq = NULL;
1678 rl_initialize ();
1679 rc = process_cmd ();
1680 if (rc)
1681 return rc;
1683 rc = set_inquire (STDIN_FILENO, NULL, &inq);
1684 if (rc)
1685 return rc;
1687 fprintf (stderr,
1688 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1689 print_help ();
1690 rl_event_hook = &interactive_hook;
1691 rl_getc_function = get_readline_char;
1692 rl_set_keyboard_input_timeout (100000);
1694 for (;;)
1696 char *line;
1697 char *result = NULL;
1698 size_t len;
1699 char buf[255];
1701 rc = 0;
1702 snprintf (buf, sizeof (buf), "pwmc%s%s> ",
1703 filename ? ":" : "", filename ? filename : "");
1704 line = readline (buf);
1705 if (interactive_error)
1707 free (line);
1708 rc = interactive_error;
1709 break;
1712 if (!line)
1714 rc = finalize ();
1715 if (!rc)
1716 break;
1718 if (gpg_err_code (rc) != GPG_ERR_CANCELED &&
1719 gpg_err_code (rc) != GPG_ERR_EOF)
1720 fprintf (stderr, "ERR %i: %s\n", rc, gpg_strerror (rc));
1722 continue;
1724 else if (!*line)
1726 free (line);
1727 continue;
1730 #ifdef HAVE_READLINE_HISTORY
1731 add_history_item (line);
1732 #endif
1733 rc = parse_dotcommand (line, &result, &len, inq);
1734 free (line);
1735 if (rc)
1737 char *tmp = NULL;
1739 if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
1740 (void) pwmd_command (pwm, &tmp, NULL, NULL, NULL,
1741 "GETINFO last_error");
1743 show_error (pwm, rc, tmp);
1744 pwmd_free (tmp);
1746 else if (result && len)
1747 printf ("%s%s", result, result[len - 1] != '\n' ? "\n" : "");
1749 pwmd_free (result);
1752 free_inquire (inq);
1753 return rc;
1755 #endif
1757 static gpg_error_t
1758 finalize ()
1760 gpg_error_t rc = 0;
1761 #ifdef HAVE_LIBREADLINE
1762 int quit = 0;
1764 if (interactive)
1766 int finished = 0;
1768 fprintf (stderr, "\n");
1772 char *p, buf[16];
1774 fprintf (stderr,
1776 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1777 p = fgets (buf, sizeof (buf), stdin);
1779 if (feof (stdin))
1781 clearerr (stdin);
1782 return GPG_ERR_EOF;
1785 switch (*p)
1787 case 'h':
1788 print_help ();
1789 break;
1790 case 'c':
1791 return GPG_ERR_CANCELED;
1792 case 'Q':
1793 return 0;
1794 case 'f':
1795 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1796 "CLEARCACHE %s", filename);
1797 if (rc)
1798 return rc;
1800 interactive_hook ();
1801 break;
1802 case 'S':
1803 quit = 1;
1804 case 's':
1805 save = 1;
1806 finished = 1;
1807 break;
1808 default:
1809 break;
1812 while (!finished);
1814 #endif
1816 if (save && !filename)
1818 fprintf (stderr,
1820 ("No filename was specified on the command line. Aborting.\n"));
1821 return GPG_ERR_CANCELED;
1824 if (save && filename)
1826 char *args =
1827 pwmd_strdup_printf ("%s %s%s %s%s %s",
1828 symmetric ? "--symmetric" : "",
1829 keyid ? "--keyid=" : "",
1830 keyid ? keyid : "",
1831 sign_keyid ? "--sign-keyid=" : "",
1832 sign_keyid ? sign_keyid : "",
1833 keyparams ? "--inquire-keyparam" : "");
1835 #ifdef HAVE_LIBREADLINE
1836 if (!quiet || interactive)
1838 #else
1839 if (!quiet)
1841 #endif
1842 fprintf (stderr, "\n");
1843 fprintf (stderr, N_("Saving changes ...\n"));
1846 rc = save_command (args);
1847 pwmd_free (args);
1850 #ifdef HAVE_LIBREADLINE
1851 if (interactive)
1852 return rc ? rc : quit ? 0 : GPG_ERR_CANCELED;
1853 #endif
1855 return rc;
1858 static void
1859 parse_status_ignore (char *str)
1861 size_t n = 0;
1862 char **p, *s;
1864 for (p = status_ignore; p && *p; p++)
1865 pwmd_free (*p);
1867 pwmd_free (status_ignore);
1868 status_ignore = NULL;
1869 if (!str || !*str)
1870 return;
1872 while ((s = strsep (&str, ",")))
1874 p = pwmd_realloc (status_ignore, (n + 2) * sizeof (char *));
1875 p[n++] = pwmd_strdup (s);
1876 p[n] = NULL;
1877 status_ignore = p;
1882 main (int argc, char *argv[])
1884 int connected = 0;
1885 int status_state = 0;
1886 gpg_error_t rc;
1887 int opt;
1888 char command[ASSUAN_LINELENGTH], *p = NULL;
1889 char *result = NULL;
1890 size_t len = 0;
1891 char *pinentry_path = NULL;
1892 char *display = NULL, *tty = NULL, *ttytype = NULL;
1893 char *lcctype = NULL, *lcmessages = NULL;
1894 int outfd = STDOUT_FILENO;
1895 FILE *outfp = stdout;
1896 FILE *inquirefp = stdin;
1897 int show_status = 1;
1898 char *clientname = "pwmc";
1899 char *inquire = NULL;
1900 char *inquire_line = NULL;
1901 int timeout = 0;
1902 #ifdef WITH_SSH
1903 int use_ssh_agent = 1;
1904 char *knownhosts = NULL;
1905 char *identity = NULL;
1906 int needs_passphrase = 0;
1907 char *ssh_passphrase_file = NULL;
1908 #endif
1909 #ifdef WITH_GNUTLS
1910 char *cacert = NULL;
1911 char *clientcert = NULL;
1912 char *clientkey = NULL;
1913 char *prio = NULL;
1914 int tls_verify = 0;
1915 char *tls_fingerprint = NULL;
1916 #endif
1917 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1918 pwmd_socket_t socktype;
1919 long socket_timeout = 300;
1920 int connect_timeout = 120;
1921 #endif
1922 #ifdef HAVE_LIBREADLINE
1923 int no_interactive = 0;
1924 #endif
1925 int lock_on_open = 1;
1926 long lock_timeout = 50;
1927 char *url = NULL;
1928 char *tmp = NULL;
1929 /* The order is important. */
1930 enum
1932 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1933 OPT_SOCKET_TIMEOUT, OPT_CONNECT_TIMEOUT,
1934 #endif
1935 #ifdef WITH_SSH
1936 OPT_USE_SSH_AGENT, OPT_IDENTITY, OPT_KNOWNHOSTS, OPT_SSH_NEEDS_PASSPHRASE,
1937 OPT_SSH_PASSPHRASE_FILE,
1938 #endif
1939 #ifdef WITH_GNUTLS
1940 OPT_CACERT, OPT_CLIENTCERT, OPT_CLIENTKEY, OPT_PRIORITY, OPT_VERIFY,
1941 OPT_SERVER_FP,
1942 #endif
1943 OPT_URL, OPT_LOCAL, OPT_TTYNAME, OPT_TTYTYPE, OPT_DISPLAY, OPT_LC_CTYPE,
1944 OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES, OPT_PINENTRY, OPT_KEYFILE,
1945 OPT_PASSPHRASE_FILE, OPT_NEW_KEYFILE, OPT_NEW_PASSPHRASE_FILE,
1946 OPT_SIGN_KEYFILE, OPT_SIGN_PASSPHRASE_FILE, OPT_NOLOCK, OPT_LOCK_TIMEOUT,
1947 OPT_SAVE, OPT_OUTPUT_FD, OPT_INQUIRE, OPT_INQUIRE_FD, OPT_INQUIRE_FILE,
1948 OPT_INQUIRE_LINE, OPT_NO_STATUS, OPT_STATUS_IGNORE, OPT_STATUSFD, OPT_NAME,
1949 OPT_VERSION, OPT_HELP, OPT_KEYID, OPT_SIGN_KEYID, OPT_SYMMETRIC,
1950 OPT_KEYPARAMS, OPT_NO_PINENTRY, OPT_QUIET, OPT_STATUS_STATE,
1951 #ifdef HAVE_LIBREADLINE
1952 OPT_NO_INTERACTIVE,
1953 #endif
1955 const struct option long_opts[] = {
1956 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1957 {"socket-timeout", 1, 0, 0},
1958 {"connect-timeout", 1, 0, 0},
1959 #endif
1961 #ifdef WITH_SSH
1962 {"no-ssh-agent", 0, 0, 0},
1963 {"identity", 1, 0, 'i'},
1964 {"knownhosts", 1, 0, 'k'},
1965 {"ssh-needs-passphrase", 0, 0, 0},
1966 {"ssh-passphrase-file", 1, 0, 0},
1967 #endif
1968 #ifdef WITH_GNUTLS
1969 {"ca-cert", 1, 0, 0},
1970 {"client-cert", 1, 0, 0},
1971 {"client-key", 1, 0, 0},
1972 {"tls-priority", 1, 0, 0},
1973 {"tls-verify", 0, 0, 0},
1974 {"tls-fingerprint", 1, 0, 0},
1975 #endif
1976 {"url", 1, 0, 0},
1977 {"local-pinentry", 0, 0},
1978 {"ttyname", 1, 0, 'y'},
1979 {"ttytype", 1, 0, 't'},
1980 {"display", 1, 0, 'd'},
1981 {"lc-ctype", 1, 0, 0},
1982 {"lc-messages", 1, 0, 0},
1983 {"timeout", 1, 0, 0},
1984 {"tries", 1, 0, 0},
1985 {"pinentry", 1, 0, 0},
1986 {"key-file", 1, 0, 0},
1987 {"passphrase-file", 1, 0, 0},
1988 {"new-key-file", 1, 0, 0},
1989 {"new-passphrase-file", 1, 0, 0},
1990 {"sign-key-file", 1, 0, 0},
1991 {"sign-passphrase-file", 1, 0, 0},
1992 {"no-lock", 0, 0, 0},
1993 {"lock-timeout", 1, 0, 0},
1994 {"save", 0, 0, 'S'},
1995 {"output-fd", 1, 0, 0},
1996 {"inquire", 1, 0, 0},
1997 {"inquire-fd", 1, 0, 0},
1998 {"inquire-file", 1, 0, 0},
1999 {"inquire-line", 1, 0, 'L'},
2000 {"no-status", 0, 0, 0},
2001 {"status-ignore", 1, 0, 0},
2002 {"status-fd", 1, 0, 0},
2003 {"name", 1, 0, 'n'},
2004 {"version", 0, 0, 0},
2005 {"help", 0, 0, 0},
2006 {"keyid", 1, 0, 0},
2007 {"sign-keyid", 1, 0, 0},
2008 {"symmetric", 0, 0, 0},
2009 {"key-params", 1, 0, 0},
2010 {"no-pinentry", 0, 0, 0},
2011 {"quiet", 0, 0, 0},
2012 {"status-state", 0, 0, 0},
2013 #ifdef HAVE_LIBREADLINE
2014 {"no-interactive", 0, 0},
2015 #endif
2016 {0, 0, 0, 0}
2018 #ifdef WITH_SSH
2019 const char *optstring = "L:y:t:d:P:I:Sn:i:k:s";
2020 #else
2021 const char *optstring = "L:y:t:d:P:I:Sn:s";
2022 #endif
2023 int opt_index = 0;
2025 #ifdef ENABLE_NLS
2026 setlocale (LC_ALL, "");
2027 bindtextdomain ("libpwmd", LOCALEDIR);
2028 #endif
2030 tries = DEFAULT_PIN_TRIES;
2031 inquirefd = STDIN_FILENO;
2032 statusfd = STDERR_FILENO;
2033 statusfp = stderr;
2034 tmp = pwmd_strdup (DEFAULT_STATUS_IGNORE);
2035 parse_status_ignore (tmp);
2036 pwmd_free (tmp);
2038 while ((opt =
2039 getopt_long (argc, argv, optstring, long_opts, &opt_index)) != -1)
2041 switch (opt)
2043 /* Handle long options without a short option part. */
2044 case 0:
2045 switch (opt_index)
2047 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2048 case OPT_SOCKET_TIMEOUT:
2049 socket_timeout = strtol (optarg, &p, 10);
2050 break;
2051 case OPT_CONNECT_TIMEOUT:
2052 connect_timeout = strtol (optarg, &p, 10);
2053 break;
2054 #endif
2055 #ifdef WITH_SSH
2056 case OPT_USE_SSH_AGENT:
2057 use_ssh_agent = 0;
2058 break;
2059 case OPT_SSH_NEEDS_PASSPHRASE:
2060 needs_passphrase = 1;
2061 break;
2062 case OPT_SSH_PASSPHRASE_FILE:
2063 ssh_passphrase_file = optarg;
2064 break;
2065 #endif
2066 #ifdef WITH_GNUTLS
2067 case OPT_CACERT:
2068 cacert = optarg;
2069 break;
2070 case OPT_CLIENTCERT:
2071 clientcert = optarg;
2072 break;
2073 case OPT_CLIENTKEY:
2074 clientkey = optarg;
2075 break;
2076 case OPT_PRIORITY:
2077 prio = optarg;
2078 break;
2079 case OPT_VERIFY:
2080 tls_verify = 1;
2081 break;
2082 case OPT_SERVER_FP:
2083 tls_fingerprint = optarg;
2084 break;
2085 #endif
2086 case OPT_SYMMETRIC:
2087 symmetric = 1;
2088 break;
2089 case OPT_KEYPARAMS:
2090 keyparams = optarg;
2091 break;
2092 case OPT_KEYFILE:
2093 case OPT_PASSPHRASE_FILE:
2094 keyfile = pwmd_strdup (optarg);
2095 break;
2096 case OPT_NEW_KEYFILE:
2097 case OPT_NEW_PASSPHRASE_FILE:
2098 new_keyfile = pwmd_strdup (optarg);
2099 break;
2100 case OPT_SIGN_KEYFILE:
2101 case OPT_SIGN_PASSPHRASE_FILE:
2102 sign_keyfile = pwmd_strdup (optarg);
2103 break;
2104 case OPT_NOLOCK:
2105 lock_on_open = 0;
2106 break;
2107 case OPT_LOCK_TIMEOUT:
2108 lock_timeout = strtol (optarg, &p, 10);
2109 break;
2110 case OPT_URL:
2111 url = optarg;
2112 break;
2113 case OPT_LOCAL:
2114 local_pin = 1;
2115 break;
2116 case OPT_LC_CTYPE:
2117 lcctype = pwmd_strdup (optarg);
2118 break;
2119 case OPT_LC_MESSAGES:
2120 lcmessages = pwmd_strdup (optarg);
2121 break;
2122 case OPT_TIMEOUT:
2123 timeout = strtol (optarg, &p, 10);
2124 break;
2125 case OPT_TRIES:
2126 tries = strtol (optarg, &p, 10);
2127 break;
2128 case OPT_INQUIRE:
2129 inquire = escape (optarg);
2130 break;
2131 case OPT_INQUIRE_FD:
2132 inquirefd = strtol (optarg, &p, 10);
2133 if (!p)
2135 inquirefp = fdopen (inquirefd, "r");
2136 if (!inquirefp)
2137 err (EXIT_FAILURE, "%i", inquirefd);
2139 break;
2140 case OPT_INQUIRE_FILE:
2141 inquirefd = open (optarg, O_RDONLY);
2142 if (inquirefd == -1)
2143 err (EXIT_FAILURE, "%s", optarg);
2144 inquirefp = fdopen (inquirefd, "r");
2145 break;
2146 case OPT_OUTPUT_FD:
2147 outfd = strtol (optarg, &p, 10);
2148 if (!p || !*p)
2150 outfp = fdopen (outfd, "w");
2151 if (!outfp)
2152 err (EXIT_FAILURE, "%i", outfd);
2154 break;
2155 case OPT_NO_STATUS:
2156 show_status = 0;
2157 break;
2158 case OPT_STATUSFD:
2159 statusfd = strtol (optarg, &p, 10);
2160 if (!p || !*p)
2162 statusfp = fdopen (statusfd, "w");
2163 if (!statusfp)
2164 err (EXIT_FAILURE, "%i", statusfd);
2166 break;
2167 case OPT_STATUS_IGNORE:
2168 parse_status_ignore (optarg);
2169 break;
2170 case OPT_VERSION:
2171 printf ("%s (pwmc)\n\n"
2172 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016\n"
2173 "%s\n"
2174 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
2175 "Compile-time features:\n"
2176 #ifdef HAVE_LIBREADLINE
2177 "+INTERACTIVE "
2178 #else
2179 "-INTERACTIVE "
2180 #endif
2181 #ifdef WITH_SSH
2182 "+SSH "
2183 #else
2184 "-SSH "
2185 #endif
2186 #ifdef WITH_GNUTLS
2187 "+GNUTLS "
2188 #else
2189 "-GNUTLS "
2190 #endif
2191 #ifdef WITH_PINENTRY
2192 "+PINENTRY "
2193 #else
2194 "-PINENTRY "
2195 #endif
2196 #ifdef WITH_QUALITY
2197 "+QUALITY "
2198 #else
2199 "-QUALITY "
2200 #endif
2201 #ifdef MEM_DEBUG
2202 "+MEM_DEBUG "
2203 #else
2204 "-MEM_DEBUG "
2205 #endif
2206 "\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
2207 exit (EXIT_SUCCESS);
2208 case OPT_PINENTRY:
2209 pinentry_path = optarg;
2210 break;
2211 case OPT_HELP:
2212 usage (argv[0], EXIT_SUCCESS);
2213 case OPT_KEYID:
2214 keyid = optarg;
2215 break;
2216 case OPT_SIGN_KEYID:
2217 sign_keyid = optarg;
2218 break;
2219 case OPT_QUIET:
2220 quiet = 1;
2221 show_status = 0;
2222 break;
2223 case OPT_STATUS_STATE:
2224 status_state = 1;
2225 break;
2226 case OPT_NO_PINENTRY:
2227 no_pinentry = 1;
2228 break;
2229 #ifdef HAVE_LIBREADLINE
2230 case OPT_NO_INTERACTIVE:
2231 no_interactive = 1;
2232 break;
2233 #endif
2234 default:
2235 usage (argv[0], EXIT_FAILURE);
2238 if (p && *p)
2240 fprintf (stderr, N_("%s: invalid argument for option '--%s'\n"),
2241 argv[0], long_opts[opt_index].name);
2242 usage (argv[0], EXIT_FAILURE);
2245 break;
2246 #ifdef WITH_SSH
2247 case 'i':
2248 identity = optarg;
2249 break;
2250 case 'k':
2251 knownhosts = optarg;
2252 break;
2253 #endif
2254 case 'L':
2255 inquire_line = optarg;
2256 break;
2257 case 'y':
2258 tty = optarg;
2259 break;
2260 case 't':
2261 ttytype = optarg;
2262 break;
2263 case 'd':
2264 display = optarg;
2265 break;
2266 case 'S':
2267 save = 1;
2268 break;
2269 case 'n':
2270 clientname = optarg;
2271 break;
2272 default:
2273 usage (argv[0], EXIT_FAILURE);
2277 #ifdef HAVE_LIBREADLINE
2278 if (isatty (STDIN_FILENO) && !inquire && !inquire_line && !no_interactive)
2279 interactive = 1;
2280 #endif
2282 pwmd_init ();
2283 rc = pwmd_new (clientname, &pwm);
2284 if (rc)
2285 goto done;
2287 filename = argv[optind] ? pwmd_strdup (argv[optind]) : NULL;
2288 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
2289 if (rc)
2290 goto done;
2292 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local_pin);
2293 if (rc)
2294 goto done;
2296 pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
2297 if (!quiet)
2298 fprintf (stderr, N_("Connecting ...\n"));
2300 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
2301 socktype = is_remote_url (url);
2302 if (socktype != PWMD_SOCKET_LOCAL)
2304 local_pin = 1;
2305 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2306 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, connect_timeout);
2307 if (rc)
2308 goto done;
2309 #endif
2311 if (socktype == PWMD_SOCKET_SSH)
2313 #ifdef WITH_SSH
2314 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_CB, knownhost_cb);
2315 if (rc)
2316 goto done;
2318 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_DATA, clientname);
2319 if (rc)
2320 goto done;
2322 if (!getenv ("SSH_AUTH_SOCK") || identity)
2323 use_ssh_agent = 0;
2325 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_AGENT, use_ssh_agent);
2326 if (rc)
2327 goto done;
2329 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_NEEDS_PASSPHRASE,
2330 needs_passphrase);
2331 if (rc)
2332 goto done;
2334 if (ssh_passphrase_file)
2336 struct stat st;
2337 int fd;
2339 if (stat (ssh_passphrase_file, &st) == -1)
2341 rc = gpg_error_from_syserror ();
2342 fprintf(stderr, "%s: %s\n", ssh_passphrase_file,
2343 gpg_strerror (rc));
2344 goto done;
2347 result = pwmd_calloc (1, st.st_size+1);
2348 if (!result)
2350 rc = GPG_ERR_ENOMEM;
2351 goto done;
2354 fd = open (ssh_passphrase_file, O_RDONLY);
2355 if (fd != -1)
2357 len = read (fd, result, st.st_size);
2358 if (len == st.st_size)
2359 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_PASSPHRASE, result);
2360 else
2361 rc = gpg_error_from_syserror ();
2363 close (fd);
2365 else
2366 rc = gpg_error_from_syserror ();
2368 pwmd_free (result);
2369 result = NULL;
2370 len = 0;
2372 if (rc)
2374 fprintf(stderr, "%s: %s\n", ssh_passphrase_file,
2375 gpg_strerror (rc));
2376 goto done;
2380 rc = pwmd_connect (pwm, url, identity, knownhosts);
2381 #endif
2383 #ifdef WITH_GNUTLS
2384 else
2386 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_VERIFY, tls_verify);
2387 if (rc)
2388 goto done;
2390 rc = pwmd_connect (pwm, url, clientcert, clientkey, cacert, prio,
2391 tls_fingerprint);
2393 #endif
2395 else
2396 rc = pwmd_connect (pwm, url);
2397 #else
2398 rc = pwmd_connect (pwm, url);
2399 #endif
2400 if (rc)
2401 goto done;
2403 if (!quiet)
2404 fprintf (stderr, N_("Connected.\n"));
2406 connected = 1;
2407 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2408 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, socket_timeout);
2409 if (rc)
2410 goto done;
2411 #endif
2413 if (lock_timeout)
2415 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
2416 "OPTION LOCK-TIMEOUT=%li", lock_timeout);
2417 if (rc)
2418 goto done;
2421 if (status_state)
2423 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION CLIENT-STATE=1");
2424 if (rc)
2425 goto done;
2428 if (lock_on_open)
2430 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCK_ON_OPEN, 1);
2431 if (rc)
2432 goto done;
2435 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, NULL, NULL);
2436 if (rc)
2437 goto done;
2439 if (timeout > 0)
2441 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
2442 if (rc)
2443 goto done;
2446 if (pinentry_path)
2448 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
2449 if (rc)
2450 goto done;
2453 if (display)
2455 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
2456 if (rc)
2457 goto done;
2460 if (tty)
2462 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, tty);
2463 if (rc)
2464 goto done;
2467 if (ttytype)
2469 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
2470 if (rc)
2471 goto done;
2474 if (lcctype)
2476 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
2477 if (rc)
2478 goto done;
2481 if (lcmessages)
2483 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES, lcmessages);
2484 if (rc)
2485 goto done;
2488 if (show_status)
2490 rc = pwmd_setopt (pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
2491 if (rc)
2492 goto done;
2495 if (filename)
2497 rc = open_command (filename);
2498 if (rc)
2499 goto done;
2502 #ifdef HAVE_LIBREADLINE
2503 if (interactive)
2505 rc = do_interactive ();
2506 result = NULL;
2507 goto do_exit;
2509 #endif
2511 if (inquire)
2513 struct inquire_s *inq = NULL;
2515 rc = set_inquire (inquirefd, inquire_line, &inq);
2516 if (!rc)
2517 rc = pwmd_command (pwm, &result, &len, inquire_cb, inq, "%s", inquire);
2519 free_inquire (inq);
2520 goto done;
2523 if (fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1)
2525 rc = gpg_error_from_errno (errno);
2526 goto done;
2529 ssize_t n;
2531 for (;;)
2533 rc = process_cmd ();
2535 if (rc)
2536 goto done;
2538 n = read (STDIN_FILENO, command, sizeof (command)-1);
2539 if (n == -1)
2541 if (errno == EAGAIN)
2543 usleep (100000);
2544 continue;
2547 rc = gpg_error_from_errno (errno);
2548 goto done;
2550 else if (!n)
2551 goto done;
2553 p = command;
2554 command[n] = 0;
2555 break;
2558 if (!p || !*p || !strcasecmp (p, "BYE"))
2559 goto done;
2562 struct inquire_s *inq = NULL;
2563 rc = set_inquire (inquirefd, inquire_line, &inq);
2564 if (!rc)
2566 rc = parse_dotcommand (command, &result, &len, inq);
2567 free_inquire (inq);
2570 if (rc)
2571 goto done;
2573 done:
2574 if (result)
2576 fwrite (result, 1, result[len - 1] == 0 ? len - 1 : len, outfp);
2577 fflush (outfp);
2578 pwmd_free (result);
2581 result = NULL;
2582 if (!rc)
2583 rc = finalize ();
2584 else if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
2585 (void) pwmd_command (pwm, &result, NULL, NULL, NULL,
2586 "GETINFO last_error");
2588 #ifdef HAVE_LIBREADLINE
2589 do_exit:
2590 #endif
2591 wipememory (command, 0, sizeof (command));
2593 if (rc && !quiet)
2594 show_error (pwm, rc, result);
2596 pwmd_close (pwm);
2597 reset_keyfiles ();
2598 pwmd_deinit ();
2599 pwmd_free (result);
2600 pwmd_free (filename);
2601 parse_status_ignore (NULL);
2602 if (connected && !quiet)
2603 fprintf (stderr, N_("Connection closed.\n"));
2605 exit (rc ? EXIT_FAILURE : EXIT_SUCCESS);