Port to Windows.
[libpwmd.git] / src / pwmc.c
blob8d3fbf77fdf51b8c2c7d724f899892ea5af739a3
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 <errno.h>
30 #include <string.h>
31 #include <libpwmd.h>
32 #include <assuan.h>
33 #include <fcntl.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <libgen.h>
37 #include <limits.h>
38 #include <ctype.h>
39 #include <time.h>
41 #ifndef __MINGW32__
42 #include <err.h>
43 #include <termios.h>
44 #include <sys/select.h>
45 #include <stropts.h>
46 #endif
48 #include "util-string.h"
49 #include "util-slist.h"
51 #ifdef WITH_GNUTLS
52 #include <gnutls/gnutls.h>
53 #endif
55 #ifdef HAVE_LOCALE_H
56 #include <locale.h>
57 #endif
59 #ifdef HAVE_GETOPT_LONG
60 #ifdef HAVE_GETOPT_H
61 #include <getopt.h>
62 #endif
63 #else
64 #include "getopt_long.h"
65 #endif
67 #ifdef HAVE_LIBREADLINE
68 #if defined(HAVE_READLINE_READLINE_H)
69 #include <readline/readline.h>
70 #elif defined(HAVE_READLINE_H)
71 #include <readline.h>
72 #endif /* !defined(HAVE_READLINE_H) */
73 static int interactive_error;
74 static int interactive;
75 #endif /* HAVE_LIBREADLINE */
77 #ifdef HAVE_READLINE_HISTORY
78 #if defined(HAVE_READLINE_HISTORY_H)
79 #include <readline/history.h>
80 #elif defined(HAVE_HISTORY_H)
81 #include <history.h>
82 #endif
83 #endif /* HAVE_READLINE_HISTORY */
85 #ifndef LINE_MAX
86 #define LINE_MAX 2048
87 #endif
89 #include "gettext.h"
90 #define N_(msgid) gettext(msgid)
92 #include "mem.h"
95 #define DEFAULT_STATUS_IGNORE "KEEPALIVE,GPGME,PASSPHRASE_INFO,PASSPHRASE_HINT"
96 #define DEFAULT_PIN_TIMEOUT 30
97 #define DEFAULT_PIN_TRIES 3
99 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
100 ? gpg_error(rc) : rc
102 enum
104 SAVE_WHICH_SAVE,
105 SAVE_WHICH_PASSWD,
106 SAVE_WHICH_GENKEY
109 static int no_pinentry;
110 static pwm_t *pwm;
111 static char *filename;
112 static int save;
113 static char *keyid;
114 static char *sign_keyid;
115 static int symmetric;
116 static char *keyparams;
117 static char *keyfile;
118 static char *new_keyfile;
119 static char *sign_keyfile;
120 static int tries;
121 static int local_pin;
122 static int inquirefd;
123 static int statusfd;
124 FILE *statusfp;
125 static int quiet;
126 static char **status_ignore;
128 struct inquire_s
130 int fd;
131 char *line;
132 size_t len;
133 size_t size; // from stat(2).
134 char *last_keyword;
137 struct userid_s {
138 char *userid;
139 char *name;
140 char *email;
141 char *comment;
144 struct keyid_s {
145 char *keyid;
146 char *fpr;
147 char *grip;
148 char *card;
149 int can_sign;
150 int can_encrypt;
151 int can_certify;
152 int can_auth;
153 int expired;
154 time_t expires;
155 time_t created;
156 int secret;
157 int revoked;
158 int algo;
159 unsigned bits;
160 char *curve;
161 struct slist_s *userids;
162 struct slist_s *subkeys;
165 static gpg_error_t finalize ();
166 static gpg_error_t set_inquire (int fd, const char *line,
167 struct inquire_s **result);
168 static gpg_error_t parse_dotcommand (const char *line, char **result,
169 size_t * len, struct inquire_s *inq);
170 static gpg_error_t open_command (char *line);
171 #ifndef HAVE_STRSEP
172 char *strsep (char **, const char *);
173 #endif
174 #ifndef HAVE_ERR
175 int err (int, const char *, ...);
176 #endif
178 static void
179 show_error (pwm_t *h, gpg_error_t rc, const char *str)
181 #ifdef WITH_GNUTLS
182 const char *tlsstr;
183 int e = pwmd_gnutls_error (h, &tlsstr);
185 if (e)
186 fprintf(stderr, "TLS: %s\n", tlsstr);
187 #else
188 (void)h;
189 #endif
190 fprintf (stderr, "ERR %i: %s%s%s%s", rc, gpg_strerror (rc),
191 str ? ": " : "", str ? str : "", str ? "" : "\n");
194 static void
195 reset_keyfiles ()
197 pwmd_free (keyfile);
198 pwmd_free (new_keyfile);
199 pwmd_free (sign_keyfile);
200 keyfile = new_keyfile = sign_keyfile = NULL;
203 static void
204 usage (const char *pn, int status)
206 fprintf (status == EXIT_FAILURE ? stderr : stdout,
207 N_("Usage: %s [options] [file]\n"
208 " --url <string>\n"
209 " a url string to connect to (%s, see below)\n"
210 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
211 " --connect-timeout <seconds>\n"
212 " seconds before connecting to a remote host fails (0=disabled, 120)\n"
213 " --socket-timeout <seconds>\n"
214 " seconds before a remote command fails (0=disabled, 300)\n"
215 #endif
216 #ifdef WITH_GNUTLS
217 " --ca-cert <filename>\n"
218 " certificate authority (CA) used to sign the server cert\n"
219 " --client-cert <filename>\n"
220 " client certificate to use for authentication\n"
221 " --client-key <filename>\n"
222 " key file used to protect the client certificate\n"
223 " --tls-priority <string>\n"
224 " compression, cipher and hash algorithm string\n"
225 " (SECURE256:SECURE192:SECURE128:-VERS-SSL3.0:-VERS-TLS1.0)\n"
226 " --no-tls-verify\n"
227 " disable verifying the hostname against the server certificate\n"
228 " --tls-fingerprint <string>\n"
229 " a SHA-256 hash of the server fingerprint to verify against\n"
230 #endif
231 #ifdef WITH_SSH
232 " --no-ssh-agent\n"
233 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
234 " --identity, -i <filename>\n"
235 " the ssh identity file to use for authentication\n"
236 " --knownhosts, -k <filename>\n"
237 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
238 " --ssh-needs-passphrase\n"
239 " prompt for a passphrase for the SSH identity file\n"
240 " --ssh-passphrase-file <filename>\n"
241 " read the SSH private key passphrase from filename\n"
242 #endif
243 " --no-lock\n"
244 " do not lock the data file upon opening it\n"
245 " --lock-timeout <N>\n"
246 " time in tenths of a second to wait for a locked data file (50)\n"
247 " --name, -n <string>\n"
248 " set the client name\n"
249 " --pinentry <path>\n"
250 " the full path to the pinentry binary\n"
251 " --local-pinentry\n"
252 " force using a local pinentry\n"
253 " --no-pinentry\n"
254 " disable pinentry both remotely and locally\n"
255 " --ttyname, -y <path>\n"
256 " tty that pinentry will use\n"
257 " --ttytype, -t <string>\n"
258 " pinentry terminal type (default is $TERM)\n"
259 " --display, -d\n"
260 " pinentry display (default is $DISPLAY)\n"
261 " --lc-ctype <string>\n"
262 " locale setting for pinentry\n"
263 " --lc-messages <string>\n"
264 " locale setting for pinentry\n"
265 " --tries <N>\n"
266 " number of pinentry tries before failing (3)\n"
267 " --timeout <seconds>\n"
268 " pinentry timeout\n"
269 " --inquire <COMMAND>\n"
270 " the specified command (with any options) uses a server inquire while\n"
271 " command data is read via the inquire file descriptor (stdin)\n"
272 " --inquire-line, -L <STRING>\n"
273 " the initial line to send (i.e., element path) before the inquire data\n"
274 " --inquire-fd <FD>\n"
275 " read inquire data from the specified file descriptor (stdin)\n"
276 " --inquire-file <filename>\n"
277 " read inquire data from the specified filename\n"
278 " --output-fd <FD>\n"
279 " redirect command output to the specified file descriptor\n"
280 " --save, -S\n"
281 " send the SAVE command before exiting\n"
282 " --passphrase-file <filename>\n"
283 " obtain the passphrase from the specified filename\n"
284 " --new-passphrase-file <filename>\n"
285 " obtain the passphrase to save with from the specified filename\n"
286 " --sign-passphrase-file <filename>\n"
287 " obtain the passphrase to sign with from the specified filename\n"
288 " --key-params <filename>\n"
289 " key parameters to use for key generation (pwmd default)\n"
290 " --keyid <recipient>[,<recipient>]\n"
291 " the public key ID to u\n"
292 " --sign-keyid <string>\n"
293 " the key ID to sign the data file with\n"
294 " --symmetric\n"
295 " use conventional encryption with optional signer(s) for new files\n"
296 " --no-status\n"
297 " disable showing of status messages from the server\n"
298 " --status-state\n"
299 " enable receiving of client STATE status messages\n"
300 " --status-fd <FD>\n"
301 " redirect status messages to the specified file descriptor\n"
302 " --status-ignore <string[,...]>\n"
303 " prevent parsing of the specified status message keywords\n"
304 " --quiet\n"
305 " disable showing of extra messages (implies --no-status)\n"
306 #ifdef HAVE_LIBREADLINE
307 " --no-interactive\n"
308 " disable interactive mode\n"
309 #endif
310 " --version\n"
311 " --help\n"),
313 #ifdef DEFAULT_PWMD_SOCKET
314 DEFAULT_PWMD_SOCKET
315 #else
316 "~/.pwmd/socket"
317 #endif
319 fprintf (status == EXIT_FAILURE ? stderr : stdout,
320 N_("\n"
321 "An optional url may be in the form of:\n"
322 " --url /path/to/socket\n"
323 " --url file://[/path/to/socket]\n"
324 #ifdef WITH_SSH
325 " or\n"
326 " --url ssh[46]://[username@]hostname[:port] (uses ssh-agent)\n"
327 " -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
328 #endif
329 #ifdef WITH_GNUTLS
330 " or\n"
331 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
332 " --client-key filename\n"
333 #endif
334 #ifdef HAVE_LIBREADLINE
335 "\n"
336 "Interactive mode is used when input is from a terminal.\n"
337 #endif
339 exit (status);
342 static gpg_error_t
343 inquire_cb (void *user, const char *keyword, gpg_error_t rc,
344 char **data, size_t * size)
346 struct inquire_s *inq = user;
347 int is_password = 0;
348 int is_newpassword = 0;
349 int sign = 0;
350 int is_keyparam = 0;
352 *data = NULL;
353 *size = 0;
355 if (rc)
356 return rc;
358 if (!strcmp (keyword, "PASSPHRASE"))
359 is_password = 1;
360 else if (!strcmp (keyword, "SIGN_PASSPHRASE"))
361 sign = 1;
362 else if (!strcmp (keyword, "NEW_PASSPHRASE"))
363 is_newpassword = 1;
364 #ifdef HAVE_LIBREADLINE
365 else if (!strcmp (keyword, "KEYPARAM") && !interactive)
367 #else
368 else if (!strcmp (keyword, "KEYPARAM"))
370 #endif
371 int fd;
372 if (!keyparams || !*keyparams)
373 return gpg_error (GPG_ERR_INV_PARAMETER);
375 fd = open (keyparams, O_RDONLY);
376 if (fd == -1)
378 fprintf (stderr, "%s: %s\n", keyparams, strerror (errno));
379 return gpg_error_from_syserror ();
382 rc = set_inquire (fd, NULL, &inq);
383 if (rc)
385 close (fd);
386 return rc;
389 if (!quiet)
390 fprintf (stderr, N_("Using file '%s' as %s.\n"), keyparams, keyword);
392 is_keyparam = 1;
395 if ((is_password && !keyfile) || (is_newpassword && !new_keyfile)
396 || (sign && !sign_keyfile))
398 char *tmp;
399 int local;
401 /* Try to use the local pinentry between inquires (new/sign/passphrase).
402 * If --no-pinentry was specified then the passphrase is read from the
403 * terminal as usual. */
404 pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local);
405 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, 1);
406 rc = pwmd_password (pwm, keyword, &tmp, &inq->len);
407 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local);
408 if (rc && gpg_err_code (rc) != GPG_ERR_EOF)
409 return rc;
411 pwmd_free (inq->line);
412 inq->line = tmp;
413 *data = inq->line;
414 *size = inq->len;
415 return gpg_error (GPG_ERR_EOF);
417 else if ((is_newpassword && new_keyfile) || (is_password && keyfile)
418 || (sign && sign_keyfile))
420 int fd;
422 if (sign)
423 fd = open (sign_keyfile, O_RDONLY);
424 else
425 fd = open (is_password || sign ? keyfile : new_keyfile, O_RDONLY);
427 if (fd == -1)
429 if (sign)
430 fprintf (stderr, "%s: %s\n", sign_keyfile, strerror (errno));
431 else
432 fprintf (stderr, "%s: %s\n", is_newpassword ? new_keyfile
433 : keyfile, strerror (errno));
434 return gpg_error_from_syserror ();
437 rc = set_inquire (fd, NULL, &inq);
438 if (rc)
440 close (fd);
441 return rc;
444 if (!quiet)
445 fprintf (stderr, N_("Using keyfile '%s' as %s.\n"),
446 sign ? sign_keyfile : is_newpassword ? new_keyfile
447 : keyfile, keyword);
449 #ifdef HAVE_LIBREADLINE
450 else if ((!inq->last_keyword || strcmp (keyword, inq->last_keyword))
451 && interactive && inq->fd == STDIN_FILENO)
453 fprintf (stderr,
455 ("%sPress CTRL-D to send the current line. Press twice to end. %s:\n"),
456 inq->last_keyword ? "\n" : "", keyword);
457 pwmd_free (inq->last_keyword);
458 inq->last_keyword = pwmd_strdup (keyword);
460 #endif
462 /* The first part of the command data. */
463 if (inq->len)
465 *data = inq->line;
466 *size = inq->len;
467 inq->len = 0;
468 return inq->fd == -1 ? gpg_error (GPG_ERR_EOF) : 0;
471 *size = read (inq->fd, inq->line, ASSUAN_LINELENGTH);
472 if (*size == -1)
474 *size = 0;
475 return gpg_error (gpg_error_from_syserror ());
477 else if (*size)
478 *data = inq->line;
479 else if (inq->fd != STDIN_FILENO &&
480 (is_newpassword || is_password || sign || is_keyparam))
482 *inq->line = 0;
483 inq->size = 1;
484 *data = inq->line;
485 *size = 1;
488 if (((is_newpassword && new_keyfile) || (is_password && keyfile)
489 || (sign && sign_keyfile) || (keyparams && is_keyparam))
490 && *size == inq->size)
491 return gpg_error (GPG_ERR_EOF);
493 return *size ? 0 : gpg_error (GPG_ERR_EOF);
496 static int
497 status_msg_cb (void *data, const char *line)
499 char *p = strchr (line, ' ');
500 char **s;
502 (void)data;
504 /* Ignore status messages specified by the client via --status-ignore. */
505 for (s = status_ignore; s && *s; s++)
507 char *tmp = strchr (line, ' ');
508 size_t len = tmp ? strlen (line) - strlen (tmp) : strlen (line);
510 if (!strncmp (line, *s, len) && len == strlen (*s))
511 return 0;
514 #ifdef HAVE_LIBREADLINE
515 if (interactive && !strncmp (line, "XFER ", 5)
516 #else
517 if (!strncmp (line, "XFER ", 5)
518 #endif
519 && *line != '#' && p && strchr (p, ' ') && *++p)
521 char *p1 = strchr (p, ' ');
522 int a = strtol (p, NULL, 10);
524 if (isdigit (*p) && p1)
526 int b = strtol (p1, NULL, 10);
527 char l[64] = { 0 };
528 int t = a && b ? a * 100 / b : 0;
530 strncpy (l, line, strlen (line) - strlen (p) - 1);
531 fprintf (statusfp, "\rS:%s %i/%i %i%%%s", l, a, b, t,
532 a == b ? "\n" : "");
533 fflush (statusfp);
534 return 0;
538 fprintf (statusfp, "S:%s\n", line);
539 fflush (statusfp);
540 #ifdef HAVE_LIBREADLINE
541 rl_on_new_line ();
542 #endif
543 return 0;
546 static gpg_error_t
547 process_cmd ()
549 return pwmd_process (pwm);
552 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
553 static pwmd_socket_t
554 is_remote_url (const char *str)
556 if (!str)
557 return PWMD_SOCKET_LOCAL;
559 #ifdef WITH_SSH
560 if (strstr (str, "ssh://") || strstr (str, "ssh4://")
561 || strstr (str, "ssh6://"))
562 return PWMD_SOCKET_SSH;
563 #endif
565 #ifdef WITH_GNUTLS
566 if (strstr (str, "tls://") || strstr (str, "tls4://")
567 || strstr (str, "tls6://"))
568 return PWMD_SOCKET_TLS;
569 #endif
571 return PWMD_SOCKET_LOCAL;
573 #endif
575 static char *
576 escape (const char *str)
578 const char *p;
579 char *buf = pwmd_malloc (ASSUAN_LINELENGTH + 1), *b = buf;
580 size_t len = 0;
582 for (p = str; *p; p++, len++)
584 if (len == ASSUAN_LINELENGTH)
585 break;
587 if (*p == '\\')
589 switch (*++p)
591 case 't':
592 *b++ = '\t';
593 break;
594 case 'n':
595 *b++ = '\n';
596 break;
597 case 'v':
598 *b++ = '\v';
599 break;
600 case 'b':
601 *b++ = '\b';
602 break;
603 case 'f':
604 *b++ = '\f';
605 break;
606 case 'r':
607 *b++ = '\r';
608 break;
609 default:
610 *b++ = *p;
611 break;
614 if (!*p)
615 break;
617 continue;
620 *b++ = *p;
623 *b = 0;
624 return buf;
627 static void
628 free_inquire (struct inquire_s *inq)
630 if (!inq)
631 return;
633 pwmd_free (inq->line);
635 if (inq->fd != -1 && inq->fd != STDIN_FILENO)
636 close (inq->fd);
638 pwmd_free (inq->last_keyword);
639 pwmd_free (inq);
642 /* When *result is not NULL it is updated to the new values and not
643 * reallocated. */
644 static gpg_error_t
645 set_inquire (int fd, const char *line, struct inquire_s **result)
647 struct inquire_s inq = { 0 };
648 struct stat st = { 0 };
649 gpg_error_t rc;
651 if (fd != -1)
653 if (fstat (fd, &st) == -1)
654 return gpg_error_from_syserror ();
656 inq.size = st.st_size;
659 inq.fd = fd;
660 inq.line = pwmd_calloc (1, ASSUAN_LINELENGTH);
661 if (!inq.line)
662 return GPG_ERR_ENOMEM;
664 if (line)
666 char *s = escape (line);
668 if (!s)
670 pwmd_free (inq.line);
671 return GPG_ERR_ENOMEM;
674 if (strlen (s) >= ASSUAN_LINELENGTH)
676 pwmd_free (inq.line);
677 pwmd_free (s);
678 return GPG_ERR_LINE_TOO_LONG;
681 strncpy (inq.line, s, ASSUAN_LINELENGTH - 1);
682 inq.len = strlen (s);
683 pwmd_free (s);
686 rc = pwmd_setopt (pwm, PWMD_OPTION_INQUIRE_TOTAL,
687 st.st_size ? st.st_size + strlen (inq.line) : 0);
688 if (rc)
690 pwmd_free (inq.line);
691 return rc;
694 if (*result == NULL)
695 *result = pwmd_malloc (sizeof (struct inquire_s));
696 else
698 if ((*result)->fd != -1 && (*result)->fd != STDIN_FILENO)
699 close ((*result)->fd);
701 pwmd_free ((*result)->line);
702 (*result)->line = NULL;
703 (*result)->fd = -1;
704 (*result)->len = 0;
707 memcpy (*result, &inq, sizeof (struct inquire_s));
708 memset (&inq, 0, sizeof (struct inquire_s));
709 return rc;
712 #ifdef HAVE_LIBREADLINE
713 static int
714 interactive_hook (void)
716 interactive_error = process_cmd ();
718 if (interactive_error)
719 rl_event_hook = NULL;
721 return 0;
724 static int
725 get_readline_char (FILE *fp)
727 if (rl_line_buffer
728 && (!strncmp (rl_line_buffer, ".set passphrase-file ", 16)
729 || !strncmp (rl_line_buffer, ".set new-passphrase-file ", 20)
730 || !strncmp (rl_line_buffer, ".set sign-passphrase-file ", 21)))
731 rl_inhibit_completion = 0;
732 else if (rl_line_buffer
733 && !strncmp (rl_line_buffer, ".redir ", 7))
735 char *p = strchr (rl_line_buffer, ' ');
737 if (p && strchr (++p, ' '))
738 rl_inhibit_completion = 1;
739 else
740 rl_inhibit_completion = 0;
742 else if (rl_line_buffer
743 && !strncmp (rl_line_buffer, ".read ", 6))
745 char *p = rl_line_buffer + 6;
747 if (strstr (p, "--prefix "))
749 p = strstr (p, "--prefix ");
750 p += 9;
751 p = strchr (p, ' ');
752 if (p)
753 p++;
756 if (!p || strchr (p, ' '))
757 rl_inhibit_completion = 1;
758 else
759 rl_inhibit_completion = 0;
761 else
762 rl_inhibit_completion = 1;
764 return fgetc (fp);
767 static void
768 print_help ()
770 fprintf (stderr,
772 ("------------------------------------------------------------\n"
773 "Elements are TAB delimited. Type HELP for protocol commands.\n"
774 "Type .help for pwmc commands. Press CTRL-D to quit.\n"
775 "------------------------------------------------------------\n"));
777 #endif
779 static char *
780 parse_arg (const char *src, char *dst, size_t len)
782 char *p = dst;
783 const char *s = src;
784 size_t n = 0;
786 for (; s && *s && *s != ' ' && n < len; s++, n++)
787 *p++ = *s;
789 *p = 0;
790 return dst;
793 static char *
794 parse_opt (char **line, const char *opt, gpg_error_t * rc)
796 static char result[ASSUAN_LINELENGTH] = { 0 }, *r = result;
797 char *s = strstr (*line, opt);
799 *rc = 0;
800 result[0] = 0;
801 r = result;
803 if (s)
805 size_t len = 0;
806 int quote = 0;
807 size_t rlen = strlen (opt);
808 char *p = s + rlen;
809 int lastc = 0;
811 while (*p && *p == ' ')
813 rlen++;
814 p++;
817 for (; *p && len < sizeof (result) - 1; p++, rlen++)
819 if (isspace (*p) && !quote)
820 break;
822 if (*p == '\"' && lastc != '\\')
824 quote = !quote;
825 lastc = *p;
826 continue;
829 *r++ = lastc = *p;
830 len++;
833 *r = 0;
835 if (len >= sizeof (result) - 1)
836 *rc = GPG_ERR_LINE_TOO_LONG;
837 else
839 p = s + rlen;
841 while (*p && *p == ' ')
842 p++;
844 *line = p;
848 return result;
851 static gpg_error_t
852 read_command (const char *line, char **result, size_t * len)
854 int fd;
855 gpg_error_t rc = 0;
856 char *file = NULL;
857 struct inquire_s *inq = NULL;
858 char *p = (char *) line;
859 const char *prefix = parse_opt (&p, "--prefix", &rc);
860 char filebuf[ASSUAN_LINELENGTH];
862 if (rc)
863 return rc;
865 rc = GPG_ERR_SYNTAX;
867 if (p && *p)
869 while (*p && isspace (*p))
870 p++;
872 file = parse_arg (p, filebuf, sizeof (filebuf));
873 if (file && *file)
875 p += strlen (file) + 1;
877 while (*p && isspace (*p))
878 p++;
880 if (*p)
881 rc = 0;
885 if (rc)
887 fprintf (stderr,
889 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
890 fprintf (stderr,
892 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\\ = \\)\n"));
893 return rc;
896 fd = open (file, O_RDONLY);
897 if (fd == -1)
898 return gpg_error_from_syserror ();
900 rc = set_inquire (fd, prefix && *prefix ? prefix : NULL, &inq);
901 if (rc)
903 close (fd);
904 return rc;
907 rc = pwmd_command (pwm, result, len, inquire_cb, inq, "%s", p);
908 free_inquire (inq);
909 return rc;
912 static gpg_error_t
913 redir_command (const char *line)
915 const char *p = line;
916 int fd;
917 gpg_error_t rc = GPG_ERR_SYNTAX;
918 char *file = NULL;
919 struct inquire_s *inq = NULL;
920 char *result = NULL;
921 size_t len = 0;
922 char filebuf[ASSUAN_LINELENGTH];
924 if (p && *p && *++p)
926 file = parse_arg (p, filebuf, sizeof (filebuf));
927 if (file && *file)
929 p += strlen (file) + 1;
931 while (*p && isspace (*p))
932 p++;
934 if (*p)
935 rc = 0;
939 if (rc)
941 fprintf (stderr, N_("Usage: .redir <filename> <command> [args]\n"));
942 return rc;
945 fd = open (file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
946 if (fd == -1)
947 return gpg_error_from_syserror ();
949 #ifdef HAVE_LIBREADLINE
950 rc = set_inquire (interactive ? STDIN_FILENO : inquirefd, NULL, &inq);
951 #else
952 rc = set_inquire (inquirefd, NULL, &inq);
953 #endif
954 if (rc)
956 close (fd);
957 return rc;
960 rc = parse_dotcommand (p, &result, &len, inq);
961 if (!rc && result && len--)
962 { // null byte which is always appended
963 if (write (fd, result, len) != len)
964 rc = GPG_ERR_TOO_SHORT;
965 pwmd_free (result);
968 free_inquire (inq);
969 close (fd);
970 return rc;
973 static gpg_error_t
974 help_command (const char *line)
976 (void)line;
977 fprintf (stderr,
978 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
979 " .redir <filename> <command>\n"
980 " redirect the output of a command to the specified file\n"
981 "\n"
982 " .open <filename>\n"
983 " open the specified filename losing any changes to the current one\n"
984 "\n"
985 " .read [--prefix <string>] <filename> <command> [args]\n"
986 " obtain data from the specified filename for an inquire command\n"
987 "\n"
988 " .set help | <name> [<value>]\n"
989 " set option <name> to <value>\n"
990 "\n"
991 " .genkey [args]\n"
992 " generate a new key\n"
993 "\n"
994 " .save [args]\n"
995 " write changes of the file to disk\n"
996 "\n"
997 " .passwd [args]\n"
998 " change the passphrase of a data file\n"
999 "\n"
1000 " .listkeys [--options] [pattern[,..]]\n"
1001 " show human readable output of the LISTKEYS command\n"
1002 "\n"
1003 " .help\n"
1004 " this help text\n"));
1005 return 0;
1008 static gpg_error_t
1009 open_command (char *line)
1011 struct inquire_s *inq = NULL;
1012 char *file = line, *tmp = NULL;
1013 gpg_error_t rc;
1014 int local;
1016 while (file && isspace (*file))
1017 file++;
1019 if (file && *file)
1021 char *p = strrchr (file, ' ');
1023 if (p)
1025 while (isspace (*p))
1026 p++;
1028 if (*p)
1030 file = tmp = pwmd_strdup (file + (strlen (file)-strlen (p)));
1031 if (!file || !*file)
1033 pwmd_free (file);
1034 file = tmp = NULL;
1037 else
1038 file = NULL;
1042 if (!file || !*file)
1044 fprintf (stderr, N_("Usage: .open [--options] <filename>\n"));
1045 return GPG_ERR_SYNTAX;
1048 #ifdef HAVE_LIBREADLINE
1049 if (interactive || !quiet)
1050 #else
1051 if (!quiet)
1052 #endif
1053 fprintf (stderr, N_("Opening data file \"%s\" ...\n"), file);
1055 #ifdef HAVE_LIBREADLINE
1056 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1057 #else
1058 rc = set_inquire (-1, NULL, &inq);
1059 #endif
1060 if (rc)
1062 if (tmp)
1063 pwmd_free (file);
1064 return rc;
1067 pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local);
1069 if (keyfile)
1071 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1072 if (!rc)
1073 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, 1);
1075 else
1076 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1078 if (!rc)
1079 rc = pwmd_open (pwm, file, inquire_cb, inq);
1081 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local);
1083 #ifdef HAVE_LIBREADLINE
1084 if (interactive)
1085 reset_keyfiles ();
1086 #endif
1088 free_inquire (inq);
1089 if (!rc)
1091 if (tmp)
1093 pwmd_free (filename);
1094 filename = tmp;
1096 else
1098 char *p = pwmd_strdup (file);
1100 pwmd_free (filename);
1101 filename = p;
1102 if (!filename)
1103 rc = GPG_ERR_ENOMEM;
1106 else
1108 pwmd_free (tmp);
1109 pwmd_free (filename);
1110 filename = NULL;
1113 return rc;
1116 static gpg_error_t
1117 set_command (const char *line)
1119 gpg_error_t rc = 0;
1120 char name[256] = { 0 };
1121 char value[512] = { 0 };
1122 char *namep;
1123 char *valuep;
1124 const char *p = line;
1126 while (p && *p && isspace (*p))
1127 p++;
1129 namep = parse_arg (p, name, sizeof (name));
1130 if (!namep || !*namep)
1132 fprintf (stderr, N_("Usage: .set help | <name> [<value>]\n"));
1133 return GPG_ERR_SYNTAX;
1136 p += strlen (namep);
1137 while (p && *p && isspace (*p))
1138 p++;
1140 valuep = parse_arg (p, value, sizeof (value));
1142 if (!strcmp (name, "passphrase-file") || !strcmp (name, "new-passphrase-file")
1143 || !strcmp (name, "sign-passphrase-file"))
1145 int is_newkeyfile = 1;
1146 int sign = !strcmp (name, "sign-passphrase-file");
1148 if (!strcmp (name, "passphrase-file") || sign)
1149 is_newkeyfile = 0;
1151 if (is_newkeyfile)
1153 pwmd_free (new_keyfile);
1154 new_keyfile = NULL;
1156 else if (sign)
1158 pwmd_free (sign_keyfile);
1159 sign_keyfile = NULL;
1161 else
1163 pwmd_free (keyfile);
1164 keyfile = NULL;
1167 if (!rc && *valuep)
1169 if (is_newkeyfile)
1170 new_keyfile = pwmd_strdup (value);
1171 else if (sign)
1172 sign_keyfile = pwmd_strdup (value);
1173 else
1174 keyfile = pwmd_strdup (value);
1176 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1178 else if (!local_pin && !no_pinentry)
1180 pwmd_socket_t t;
1182 pwmd_socket_type (pwm, &t);
1183 if (t == PWMD_SOCKET_LOCAL)
1184 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1187 else if (!strcmp(name, "pinentry-timeout"))
1189 char *e = NULL;
1190 int n = strtol(valuep, &e, 10);
1192 if (e && *e)
1193 return gpg_error (GPG_ERR_INV_VALUE);
1195 if (!*valuep)
1196 n = DEFAULT_PIN_TIMEOUT;
1198 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, n);
1200 else if (!strcmp (name, "help"))
1202 fprintf (stderr,
1204 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1205 "delimited. When no value is specified the option is unset.\n\n"
1206 "passphrase-file [<filename>]\n"
1207 " set or unset the file to be used when a passphrase is required (*)\n"
1208 "\n"
1209 "new-passphrase-file [<filename>]\n"
1210 " set or unset the file to be used when a new passphrase is required (*)\n"
1211 "\n"
1212 "sign-passphrase-file [<filename>]\n"
1213 " set or unset the file to be used when a passphrase is required for\n"
1214 " signing (symmetric) (*)\n"
1215 "\n"
1216 "pinentry-timeout <seconds>\n"
1217 " the amount of seconds before pinentry gives up waiting for input\n"
1218 "\n"
1219 "* = the next protocol command will unset this value\n"
1222 else
1223 rc = GPG_ERR_UNKNOWN_OPTION;
1225 return rc;
1228 static gpg_error_t
1229 do_save_passwd_command (const char *line, int which)
1231 struct inquire_s *inq = NULL;
1232 gpg_error_t rc;
1233 int local;
1235 #ifdef HAVE_LIBREADLINE
1236 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1237 #else
1238 rc = set_inquire (-1, NULL, &inq);
1239 #endif
1240 if (rc)
1241 return rc;
1243 pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local);
1245 if (new_keyfile || keyfile || sign_keyfile)
1247 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1248 if (!rc)
1249 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, 1);
1251 else
1252 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1254 if (!rc)
1256 if (which == SAVE_WHICH_SAVE)
1257 rc = pwmd_save (pwm, line, inquire_cb, inq);
1258 else if (which == SAVE_WHICH_PASSWD)
1259 rc = pwmd_passwd (pwm, line, inquire_cb, inq);
1260 else
1261 rc = pwmd_genkey (pwm, line, inquire_cb, inq);
1264 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local);
1266 #ifdef HAVE_LIBREADLINE
1267 if (interactive)
1268 reset_keyfiles ();
1269 #endif
1271 free_inquire (inq);
1272 return rc;
1275 static gpg_error_t
1276 save_command (const char *line)
1278 return do_save_passwd_command (line, SAVE_WHICH_SAVE);
1281 static void
1282 search_and_replace (char *str, const char *s, const char r)
1284 char *p;
1286 p = strstr (str, s);
1287 if (p)
1289 *p = r;
1290 while (*++p)
1291 *p = *(p+1);
1292 search_and_replace (str, s, r);
1293 return;
1297 static char *
1298 openpgp_unescape (char *str)
1300 search_and_replace (str, "\\x3a", ':');
1301 search_and_replace (str, "\\x5c", '\\');
1302 return str;
1305 static void
1306 free_listkeys (struct slist_s *keys)
1308 unsigned i, t;
1310 t = slist_length (keys);
1311 for (i = 0; i < t; i++)
1313 struct keyid_s *key = slist_nth_data (keys, i);
1314 unsigned n, nt;
1316 nt = slist_length (key->userids);
1317 for (n = 0; n < nt; n++)
1319 struct userid_s *userid = slist_nth_data (key->userids, n);
1321 pwmd_free (userid->userid);
1322 pwmd_free (userid->name);
1323 pwmd_free (userid->email);
1324 pwmd_free (userid->comment);
1325 pwmd_free (userid);
1328 slist_free (key->userids);
1329 nt = slist_length (key->subkeys);
1330 for (n = 0; n < nt; n++)
1332 struct keyid_s *sub = slist_nth_data (key->subkeys, n);
1334 pwmd_free (sub->keyid);
1335 pwmd_free (sub->fpr);
1336 pwmd_free (sub->grip);
1337 pwmd_free (sub->card);
1338 pwmd_free (sub->curve);
1339 pwmd_free (sub);
1342 slist_free (key->subkeys);
1343 pwmd_free (key);
1346 slist_free (keys);
1349 static const char *
1350 openpgp_algorithm (struct keyid_s *key)
1352 switch (key->algo)
1354 case 1:
1355 case 2:
1356 case 3:
1357 return "RSA";
1358 case 16:
1359 case 20:
1360 return "ELG";
1361 case 17:
1362 return "DSA";
1363 case 301:
1364 case 302:
1365 case 18:
1366 return "ECC";
1367 default:
1368 break;
1371 return N_("Unknown");
1374 static void
1375 display_listkeys (struct slist_s *keys)
1377 unsigned i, t;
1379 t = slist_length (keys);
1380 for (i = 0; i < t; i++)
1382 struct keyid_s *key = slist_nth_data (keys, i);
1383 unsigned st = slist_length (key->subkeys);
1384 unsigned s;
1385 unsigned ut = slist_length (key->userids);
1386 unsigned u;
1388 for (u = 0; u < ut; u++)
1390 struct userid_s *userid = slist_nth_data (key->userids, u);
1392 fprintf(stdout, N_("User ID: %s\n"), userid->userid);
1395 for (s = 0; s < st; s++)
1397 struct keyid_s *sub = slist_nth_data (key->subkeys, s);
1398 struct tm *tmp;
1399 const char *caps = NULL;
1400 char expires[11] = { 0 };
1401 char created[11] = { 0 };
1403 if (sub->expires)
1405 tmp = localtime (&sub->expires);
1406 strftime (expires, sizeof (expires), "%F", tmp);
1409 tmp = localtime (&sub->created);
1410 strftime (created, sizeof (created), "%F", tmp);
1412 if (sub->can_encrypt)
1413 caps = "E";
1414 else if (sub->can_sign)
1415 caps = "S";
1416 else if (sub->can_auth)
1417 caps = "A";
1418 else if (sub->can_certify)
1419 caps = "C";
1421 fprintf(stdout, N_(
1422 " Subkey %u: %s [%s]%s%s %s-%u%s%s\n"
1423 " Created: %s %s%s\n"
1424 " Fingerprint: %s\n"
1425 " Keygrip: %s\n"
1426 "%s%s%s"),
1427 s+1,
1428 sub->keyid,
1429 caps,
1430 sub->secret || sub->card ? "[P]" : "",
1431 sub->revoked ? "[R]" : "",
1432 openpgp_algorithm (sub),
1433 sub->bits,
1434 sub->curve ? "-" : "",
1435 sub->curve ? sub->curve : "",
1436 created,
1437 sub->expired ? N_("Expired: ") : expires[0] ? N_("Expires: ") : "",
1438 sub->expired || expires[0] ? expires : "",
1439 sub->fpr,
1440 sub->grip,
1441 sub->card ? N_(" Card: ") : "",
1442 sub->card ? sub->card : "",
1443 sub->card ? "\n" : "");
1446 if (i+1 < t)
1447 fprintf (stdout, "\n");
1451 static gpg_error_t
1452 listkeys_command (const char *pattern)
1454 gpg_error_t rc;
1455 char *result;
1456 char **lines = NULL, **p;
1457 struct slist_s *keys = NULL;
1459 rc = pwmd_command (pwm, &result, NULL, NULL, NULL, "LISTKEYS %s", pattern);
1460 if (rc)
1461 return rc;
1463 lines = str_split (result, "\n", 0);
1464 pwmd_free (result);
1465 if (!lines)
1466 return GPG_ERR_ENOMEM;
1468 for (p = lines; *p; p++)
1470 struct keyid_s *key;
1471 char **fields = str_split (*p, ":", 0);
1472 int i, f;
1473 unsigned s;
1474 unsigned n_subkeys = 0;
1475 struct slist_s *tlist;
1477 if (!fields)
1479 rc = GPG_ERR_ENOMEM;
1480 break;
1483 key = pwmd_calloc (1, sizeof (struct keyid_s));
1484 if (!key)
1486 strv_free (fields);
1487 rc = GPG_ERR_ENOMEM;
1488 break;
1491 for (f = i = 0; i < 17; i++, f++)
1493 int b = 0;
1495 if (i < 10)
1496 b = atoi (fields[f]) != 0;
1498 switch (i)
1500 case 0: key->revoked = b; break;
1501 case 1: key->expired = b; break;
1502 case 4: key->can_encrypt = b; break;
1503 case 5: key->can_sign = b; break;
1504 case 7: key->secret = b; break;
1505 case 16: n_subkeys = strtoul (fields[f], NULL, 10); break;
1506 default:
1507 break;
1511 for (s = 0; s < n_subkeys; s++)
1513 struct keyid_s *sub;
1514 int b = 0;
1516 sub = pwmd_calloc (1, sizeof (struct keyid_s));
1517 if (!sub)
1519 strv_free (fields);
1520 rc = GPG_ERR_ENOMEM;
1521 break;
1524 for (i = 0; i < 20; i++, f++)
1526 if (i < 11)
1527 b = atoi (fields[f]) != 0;
1529 switch (i)
1531 case 0: sub->revoked = b; break;
1532 case 1: sub->expired = b; break;
1533 case 4: sub->can_encrypt = b; break;
1534 case 5: sub->can_sign = b; break;
1535 case 6: sub->can_certify = b; break;
1536 case 7: sub->secret = b; break;
1537 case 8: sub->can_auth = b; break;
1538 case 11: sub->algo = atoi (fields[f]); break;
1539 case 12: sub->bits = atoi (fields[f]); break;
1540 case 13: sub->keyid = pwmd_strdup (fields[f]); break;
1541 case 14: sub->fpr = pwmd_strdup (fields[f]); break;
1542 case 15: sub->grip = pwmd_strdup (fields[f]); break;
1543 case 16: sub->created = strtoul (fields[f], NULL, 10); break;
1544 case 17: sub->expires = strtoul (fields[f], NULL, 10); break;
1545 case 18: sub->card = fields[f] && strlen(fields[f]) > 1
1546 ? pwmd_strdup (fields[f]) : NULL; break;
1547 case 19: sub->curve = strlen (fields[f]) > 1 ? pwmd_strdup (openpgp_unescape(fields[f])) : NULL; break;
1548 default:
1549 break;
1553 tlist = slist_append (key->subkeys, sub);
1554 if (!tlist)
1556 rc = GPG_ERR_ENOMEM;
1557 break;
1560 key->subkeys = tlist;
1563 if (rc)
1565 strv_free (fields);
1566 break;
1569 // Re-create a line containing the userIds.
1570 for (; f < strv_length (fields); f++)
1572 struct userid_s *userid;
1574 userid = pwmd_calloc (1, sizeof (struct userid_s));
1575 if (!userid)
1577 rc = GPG_ERR_ENOMEM;
1578 break;
1581 // Revoked.
1582 f++;
1583 // Invalid.
1584 f++;
1585 // Validity.
1586 f++;
1588 userid->userid = pwmd_strdup (openpgp_unescape (fields[f++]));
1589 userid->name = pwmd_strdup (openpgp_unescape (fields[f++]));
1590 userid->email = pwmd_strdup (openpgp_unescape (fields[f++]));
1591 userid->comment = pwmd_strdup (openpgp_unescape (fields[f]));
1593 tlist = slist_append (key->userids, userid);
1594 if (!tlist)
1596 rc = GPG_ERR_ENOMEM;
1597 break;
1600 key->userids = tlist;
1603 strv_free (fields);
1604 if (rc)
1605 break;
1607 tlist = slist_append (keys, key);
1608 if (!tlist)
1610 rc = GPG_ERR_ENOMEM;
1611 break;
1614 keys = tlist;
1617 strv_free (lines);
1619 if (!rc)
1620 display_listkeys (keys);
1622 free_listkeys (keys);
1623 return rc;
1626 static gpg_error_t
1627 parse_dotcommand (const char *line, char **result,
1628 size_t * len, struct inquire_s *inq)
1630 const char *p = line;
1631 gpg_error_t rc = 0;
1633 if (!strncmp (p, ".read", 5))
1634 rc = read_command (p + 5, result, len);
1635 else if (!strncmp (p, ".redir", 6))
1636 rc = redir_command (p + 6);
1637 else if (!strncmp (p, ".help", 5))
1638 rc = help_command (p + 5);
1639 else if (!strncmp (p, ".open", 5))
1640 rc = open_command ((char *)p + 5);
1641 else if (!strncmp (p, ".set", 4))
1642 rc = set_command (p + 4);
1643 else if (!strncmp (p, ".save", 5))
1644 rc = do_save_passwd_command (p + 5, SAVE_WHICH_SAVE);
1645 else if (!strncmp (p, ".passwd", 7))
1646 rc = do_save_passwd_command (p + 7, SAVE_WHICH_PASSWD);
1647 else if (!strncmp (p, ".genkey", 7))
1648 rc = do_save_passwd_command (p + 7, SAVE_WHICH_GENKEY);
1649 else if (!strncmp (p, ".listkeys", 9))
1650 rc = listkeys_command (p+9);
1651 else
1653 rc = pwmd_command (pwm, result, len, inquire_cb, inq, "%s", line);
1654 #ifdef HAVE_LIBREADLINE
1655 if (interactive)
1657 #endif
1658 reset_keyfiles ();
1659 #ifdef HAVE_LIBREADLINE
1661 #endif
1663 if (!rc && !strncasecmp (line, "RESET", 5))
1665 pwmd_free (filename);
1666 filename = NULL;
1670 return FINISH (rc);
1673 #ifdef HAVE_LIBREADLINE
1674 #ifdef HAVE_READLINE_HISTORY
1675 static void
1676 add_history_item (const char *line)
1678 HIST_ENTRY **list, *p = NULL;
1679 int i;
1681 list = history_list ();
1682 for (i = 0; list && list[i]; i++)
1684 if (!strcmp (list[i]->line, line))
1686 p = list[i];
1687 break;
1691 if (p)
1693 char *s;
1695 p = remove_history (i);
1696 #ifdef HAVE_FREE_HISTORY_ENTRY
1697 s = free_history_entry (p);
1698 #endif
1699 free (s);
1702 add_history (line);
1704 #endif
1706 static gpg_error_t
1707 do_interactive ()
1709 gpg_error_t rc;
1710 struct inquire_s *inq = NULL;
1712 rl_initialize ();
1713 rc = process_cmd ();
1714 if (rc)
1715 return rc;
1717 rc = set_inquire (STDIN_FILENO, NULL, &inq);
1718 if (rc)
1719 return rc;
1721 fprintf (stderr,
1722 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1723 print_help ();
1724 rl_event_hook = &interactive_hook;
1725 rl_getc_function = get_readline_char;
1726 rl_set_keyboard_input_timeout (100000);
1728 for (;;)
1730 char *line;
1731 char *result = NULL;
1732 size_t len;
1733 char buf[255];
1735 snprintf (buf, sizeof (buf), "pwmc%s%s> ",
1736 filename ? ":" : "", filename ? filename : "");
1737 line = readline (buf);
1738 if (interactive_error)
1740 free (line);
1741 rc = interactive_error;
1742 break;
1745 if (!line)
1747 rc = finalize ();
1748 if (!rc)
1749 break;
1751 if (gpg_err_code (rc) != GPG_ERR_CANCELED &&
1752 gpg_err_code (rc) != GPG_ERR_EOF)
1753 fprintf (stderr, "ERR %i: %s\n", rc, gpg_strerror (rc));
1755 continue;
1757 else if (!*line)
1759 free (line);
1760 continue;
1763 #ifdef HAVE_READLINE_HISTORY
1764 add_history_item (line);
1765 #endif
1766 rc = parse_dotcommand (line, &result, &len, inq);
1767 free (line);
1768 if (rc)
1770 char *tmp = NULL;
1772 if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
1773 (void) pwmd_command (pwm, &tmp, NULL, NULL, NULL,
1774 "GETINFO last_error");
1776 show_error (pwm, rc, tmp);
1777 pwmd_free (tmp);
1779 else if (result && len)
1780 printf ("%s%s", result, result[len - 1] != '\n' ? "\n" : "");
1782 pwmd_free (result);
1785 free_inquire (inq);
1786 return rc;
1788 #endif
1790 static gpg_error_t
1791 finalize ()
1793 gpg_error_t rc = 0;
1794 #ifdef HAVE_LIBREADLINE
1795 int quit = 0;
1797 if (interactive)
1799 int finished = 0;
1801 fprintf (stderr, "\n");
1805 char *p, buf[16];
1807 fprintf (stderr,
1809 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1810 p = fgets (buf, sizeof (buf), stdin);
1812 if (feof (stdin))
1814 clearerr (stdin);
1815 return GPG_ERR_EOF;
1818 switch (*p)
1820 case 'h':
1821 print_help ();
1822 break;
1823 case 'c':
1824 return GPG_ERR_CANCELED;
1825 case 'Q':
1826 return 0;
1827 case 'f':
1828 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1829 "CLEARCACHE %s", filename);
1830 if (rc)
1831 return rc;
1833 interactive_hook ();
1834 break;
1835 case 'S':
1836 quit = 1;
1837 case 's':
1838 save = 1;
1839 finished = 1;
1840 break;
1841 default:
1842 break;
1845 while (!finished);
1847 #endif
1849 if (save && !filename)
1851 fprintf (stderr,
1853 ("No filename was specified on the command line. Aborting.\n"));
1854 return GPG_ERR_CANCELED;
1857 if (save && filename)
1859 char *args =
1860 pwmd_strdup_printf ("%s %s%s %s%s %s",
1861 symmetric ? "--symmetric" : "",
1862 keyid ? "--keyid=" : "",
1863 keyid ? keyid : "",
1864 sign_keyid ? "--sign-keyid=" : "",
1865 sign_keyid ? sign_keyid : "",
1866 keyparams ? "--inquire-keyparam" : "");
1868 #ifdef HAVE_LIBREADLINE
1869 if (!quiet || interactive)
1871 #else
1872 if (!quiet)
1874 #endif
1875 fprintf (stderr, "\n");
1876 fprintf (stderr, N_("Saving changes ...\n"));
1879 rc = save_command (args);
1880 pwmd_free (args);
1883 #ifdef HAVE_LIBREADLINE
1884 if (interactive)
1885 return rc ? rc : quit ? 0 : GPG_ERR_CANCELED;
1886 #endif
1888 return rc;
1891 static void
1892 parse_status_ignore (char *str)
1894 char *s;
1896 strv_free (status_ignore);
1897 status_ignore = NULL;
1898 if (!str || !*str)
1899 return;
1901 while ((s = strsep (&str, ",")))
1903 char **p = strv_cat (status_ignore, pwmd_strdup (s));
1905 if (!p)
1907 strv_free (status_ignore);
1908 status_ignore = NULL;
1909 break;
1911 status_ignore = p;
1916 main (int argc, char *argv[])
1918 int connected = 0;
1919 int status_state = 0;
1920 gpg_error_t rc;
1921 int opt;
1922 char command[ASSUAN_LINELENGTH], *p = NULL;
1923 char *result = NULL;
1924 size_t len = 0;
1925 char *pinentry_path = NULL;
1926 char *display = NULL, *tty = NULL, *ttytype = NULL;
1927 char *lcctype = NULL, *lcmessages = NULL;
1928 int outfd = STDOUT_FILENO;
1929 FILE *outfp = stdout;
1930 int show_status = 1;
1931 const char *clientname = "pwmc";
1932 char *inquire = NULL;
1933 char *inquire_line = NULL;
1934 int timeout = 0;
1935 #ifdef WITH_SSH
1936 int use_ssh_agent = -1;
1937 char *knownhosts = NULL;
1938 char *identity = NULL;
1939 int needs_passphrase = 0;
1940 char *ssh_passphrase_file = NULL;
1941 #endif
1942 #ifdef WITH_GNUTLS
1943 char *cacert = NULL;
1944 char *clientcert = NULL;
1945 char *clientkey = NULL;
1946 char *prio = NULL;
1947 int tls_verify = -1;
1948 char *tls_fingerprint = NULL;
1949 #endif
1950 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1951 pwmd_socket_t socktype;
1952 long socket_timeout = 300;
1953 int connect_timeout = 120;
1954 #endif
1955 #ifdef HAVE_LIBREADLINE
1956 int no_interactive = 0;
1957 #endif
1958 int lock_on_open = -1;
1959 long lock_timeout = 50;
1960 char *url = NULL;
1961 char *tmp = NULL;
1962 /* The order is important. */
1963 enum
1965 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1966 OPT_SOCKET_TIMEOUT, OPT_CONNECT_TIMEOUT,
1967 #endif
1968 #ifdef WITH_SSH
1969 OPT_USE_SSH_AGENT, OPT_IDENTITY, OPT_KNOWNHOSTS, OPT_SSH_NEEDS_PASSPHRASE,
1970 OPT_SSH_PASSPHRASE_FILE,
1971 #endif
1972 #ifdef WITH_GNUTLS
1973 OPT_CACERT, OPT_CLIENTCERT, OPT_CLIENTKEY, OPT_PRIORITY, OPT_VERIFY,
1974 OPT_SERVER_FP,
1975 #endif
1976 OPT_URL, OPT_LOCAL, OPT_TTYNAME, OPT_TTYTYPE, OPT_DISPLAY, OPT_LC_CTYPE,
1977 OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES, OPT_PINENTRY, OPT_KEYFILE,
1978 OPT_PASSPHRASE_FILE, OPT_NEW_KEYFILE, OPT_NEW_PASSPHRASE_FILE,
1979 OPT_SIGN_KEYFILE, OPT_SIGN_PASSPHRASE_FILE, OPT_NOLOCK, OPT_LOCK_TIMEOUT,
1980 OPT_SAVE, OPT_OUTPUT_FD, OPT_INQUIRE, OPT_INQUIRE_FD, OPT_INQUIRE_FILE,
1981 OPT_INQUIRE_LINE, OPT_NO_STATUS, OPT_STATUS_IGNORE, OPT_STATUSFD, OPT_NAME,
1982 OPT_VERSION, OPT_HELP, OPT_KEYID, OPT_SIGN_KEYID, OPT_SYMMETRIC,
1983 OPT_KEYPARAMS, OPT_NO_PINENTRY, OPT_QUIET, OPT_STATUS_STATE,
1984 #ifdef HAVE_LIBREADLINE
1985 OPT_NO_INTERACTIVE,
1986 #endif
1988 const struct option long_opts[] = {
1989 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1990 {"socket-timeout", 1, 0, 0},
1991 {"connect-timeout", 1, 0, 0},
1992 #endif
1994 #ifdef WITH_SSH
1995 {"no-ssh-agent", 0, 0, 0},
1996 {"identity", 1, 0, 'i'},
1997 {"knownhosts", 1, 0, 'k'},
1998 {"ssh-needs-passphrase", 0, 0, 0},
1999 {"ssh-passphrase-file", 1, 0, 0},
2000 #endif
2001 #ifdef WITH_GNUTLS
2002 {"ca-cert", 1, 0, 0},
2003 {"client-cert", 1, 0, 0},
2004 {"client-key", 1, 0, 0},
2005 {"tls-priority", 1, 0, 0},
2006 {"no-tls-verify", 0, 0, 0},
2007 {"tls-fingerprint", 1, 0, 0},
2008 #endif
2009 {"url", 1, 0, 0},
2010 {"local-pinentry", 0, 0},
2011 {"ttyname", 1, 0, 'y'},
2012 {"ttytype", 1, 0, 't'},
2013 {"display", 1, 0, 'd'},
2014 {"lc-ctype", 1, 0, 0},
2015 {"lc-messages", 1, 0, 0},
2016 {"timeout", 1, 0, 0},
2017 {"tries", 1, 0, 0},
2018 {"pinentry", 1, 0, 0},
2019 {"key-file", 1, 0, 0},
2020 {"passphrase-file", 1, 0, 0},
2021 {"new-key-file", 1, 0, 0},
2022 {"new-passphrase-file", 1, 0, 0},
2023 {"sign-key-file", 1, 0, 0},
2024 {"sign-passphrase-file", 1, 0, 0},
2025 {"no-lock", 0, 0, 0},
2026 {"lock-timeout", 1, 0, 0},
2027 {"save", 0, 0, 'S'},
2028 {"output-fd", 1, 0, 0},
2029 {"inquire", 1, 0, 0},
2030 {"inquire-fd", 1, 0, 0},
2031 {"inquire-file", 1, 0, 0},
2032 {"inquire-line", 1, 0, 'L'},
2033 {"no-status", 0, 0, 0},
2034 {"status-ignore", 1, 0, 0},
2035 {"status-fd", 1, 0, 0},
2036 {"name", 1, 0, 'n'},
2037 {"version", 0, 0, 0},
2038 {"help", 0, 0, 0},
2039 {"keyid", 1, 0, 0},
2040 {"sign-keyid", 1, 0, 0},
2041 {"symmetric", 0, 0, 0},
2042 {"key-params", 1, 0, 0},
2043 {"no-pinentry", 0, 0, 0},
2044 {"quiet", 0, 0, 0},
2045 {"status-state", 0, 0, 0},
2046 #ifdef HAVE_LIBREADLINE
2047 {"no-interactive", 0, 0},
2048 #endif
2049 {0, 0, 0, 0}
2051 #ifdef WITH_SSH
2052 const char *optstring = "L:y:t:d:P:I:Sn:i:k:s";
2053 #else
2054 const char *optstring = "L:y:t:d:P:I:Sn:s";
2055 #endif
2056 int opt_index = 0;
2058 #ifdef ENABLE_NLS
2059 setlocale (LC_ALL, "");
2060 bindtextdomain ("libpwmd", LOCALEDIR);
2061 #endif
2063 tries = DEFAULT_PIN_TRIES;
2064 inquirefd = STDIN_FILENO;
2065 statusfd = STDERR_FILENO;
2066 statusfp = stderr;
2067 tmp = pwmd_strdup (DEFAULT_STATUS_IGNORE);
2068 parse_status_ignore (tmp);
2069 pwmd_free (tmp);
2070 no_pinentry = -1;
2071 local_pin = -1;
2073 while ((opt =
2074 getopt_long (argc, argv, optstring, long_opts, &opt_index)) != -1)
2076 switch (opt)
2078 /* Handle long options without a short option part. */
2079 case 0:
2080 switch (opt_index)
2082 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2083 case OPT_SOCKET_TIMEOUT:
2084 socket_timeout = strtol (optarg, &p, 10);
2085 break;
2086 case OPT_CONNECT_TIMEOUT:
2087 connect_timeout = strtol (optarg, &p, 10);
2088 break;
2089 #endif
2090 #ifdef WITH_SSH
2091 case OPT_USE_SSH_AGENT:
2092 use_ssh_agent = 0;
2093 break;
2094 case OPT_SSH_NEEDS_PASSPHRASE:
2095 needs_passphrase = 1;
2096 break;
2097 case OPT_SSH_PASSPHRASE_FILE:
2098 ssh_passphrase_file = optarg;
2099 break;
2100 #endif
2101 #ifdef WITH_GNUTLS
2102 case OPT_CACERT:
2103 cacert = optarg;
2104 break;
2105 case OPT_CLIENTCERT:
2106 clientcert = optarg;
2107 break;
2108 case OPT_CLIENTKEY:
2109 clientkey = optarg;
2110 break;
2111 case OPT_PRIORITY:
2112 prio = optarg;
2113 break;
2114 case OPT_VERIFY:
2115 tls_verify = 0;
2116 break;
2117 case OPT_SERVER_FP:
2118 tls_fingerprint = optarg;
2119 break;
2120 #endif
2121 case OPT_SYMMETRIC:
2122 symmetric = 1;
2123 break;
2124 case OPT_KEYPARAMS:
2125 keyparams = optarg;
2126 break;
2127 case OPT_KEYFILE:
2128 case OPT_PASSPHRASE_FILE:
2129 keyfile = pwmd_strdup (optarg);
2130 break;
2131 case OPT_NEW_KEYFILE:
2132 case OPT_NEW_PASSPHRASE_FILE:
2133 new_keyfile = pwmd_strdup (optarg);
2134 break;
2135 case OPT_SIGN_KEYFILE:
2136 case OPT_SIGN_PASSPHRASE_FILE:
2137 sign_keyfile = pwmd_strdup (optarg);
2138 break;
2139 case OPT_NOLOCK:
2140 lock_on_open = 0;
2141 break;
2142 case OPT_LOCK_TIMEOUT:
2143 lock_timeout = strtol (optarg, &p, 10);
2144 break;
2145 case OPT_URL:
2146 url = optarg;
2147 break;
2148 case OPT_LOCAL:
2149 local_pin = 1;
2150 break;
2151 case OPT_LC_CTYPE:
2152 lcctype = pwmd_strdup (optarg);
2153 break;
2154 case OPT_LC_MESSAGES:
2155 lcmessages = pwmd_strdup (optarg);
2156 break;
2157 case OPT_TIMEOUT:
2158 timeout = strtol (optarg, &p, 10);
2159 break;
2160 case OPT_TRIES:
2161 tries = strtol (optarg, &p, 10);
2162 break;
2163 case OPT_INQUIRE:
2164 inquire = escape (optarg);
2165 break;
2166 case OPT_INQUIRE_FD:
2167 inquirefd = strtol (optarg, &p, 10);
2168 break;
2169 case OPT_INQUIRE_FILE:
2170 inquirefd = open (optarg, O_RDONLY);
2171 if (inquirefd == -1)
2172 err (EXIT_FAILURE, "%s", optarg);
2173 break;
2174 case OPT_OUTPUT_FD:
2175 outfd = strtol (optarg, &p, 10);
2176 if (!p || !*p)
2178 outfp = fdopen (outfd, "w");
2179 if (!outfp)
2180 err (EXIT_FAILURE, "%i", outfd);
2182 break;
2183 case OPT_NO_STATUS:
2184 show_status = 0;
2185 break;
2186 case OPT_STATUSFD:
2187 statusfd = strtol (optarg, &p, 10);
2188 if (!p || !*p)
2190 statusfp = fdopen (statusfd, "w");
2191 if (!statusfp)
2192 err (EXIT_FAILURE, "%i", statusfd);
2194 break;
2195 case OPT_STATUS_IGNORE:
2196 parse_status_ignore (optarg);
2197 break;
2198 case OPT_VERSION:
2199 printf ("%s (pwmc)\n\n"
2200 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017\n"
2201 "%s\n"
2202 "Released under the terms of the LGPL v2.1. Use at your own risk.\n\n"
2203 "Compile-time features:\n"
2204 #ifdef HAVE_LIBREADLINE
2205 "+INTERACTIVE "
2206 #else
2207 "-INTERACTIVE "
2208 #endif
2209 #ifdef WITH_SSH
2210 "+SSH "
2211 #else
2212 "-SSH "
2213 #endif
2214 #ifdef WITH_GNUTLS
2215 "+GNUTLS "
2216 #else
2217 "-GNUTLS "
2218 #endif
2219 #ifdef WITH_PINENTRY
2220 "+PINENTRY "
2221 #else
2222 "-PINENTRY "
2223 #endif
2224 #ifdef WITH_QUALITY
2225 "+QUALITY "
2226 #else
2227 "-QUALITY "
2228 #endif
2229 #ifdef MEM_DEBUG
2230 "+MEM_DEBUG "
2231 #else
2232 "-MEM_DEBUG "
2233 #endif
2234 "\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
2235 exit (EXIT_SUCCESS);
2236 case OPT_PINENTRY:
2237 pinentry_path = optarg;
2238 break;
2239 case OPT_HELP:
2240 usage (argv[0], EXIT_SUCCESS);
2241 case OPT_KEYID:
2242 keyid = optarg;
2243 break;
2244 case OPT_SIGN_KEYID:
2245 sign_keyid = optarg;
2246 break;
2247 case OPT_QUIET:
2248 quiet = 1;
2249 show_status = 0;
2250 break;
2251 case OPT_STATUS_STATE:
2252 status_state = 1;
2253 break;
2254 case OPT_NO_PINENTRY:
2255 no_pinentry = 1;
2256 break;
2257 #ifdef HAVE_LIBREADLINE
2258 case OPT_NO_INTERACTIVE:
2259 no_interactive = 1;
2260 break;
2261 #endif
2262 default:
2263 usage (argv[0], EXIT_FAILURE);
2266 if (p && *p)
2268 fprintf (stderr, N_("%s: invalid argument for option '--%s'\n"),
2269 argv[0], long_opts[opt_index].name);
2270 usage (argv[0], EXIT_FAILURE);
2273 break;
2274 #ifdef WITH_SSH
2275 case 'i':
2276 identity = optarg;
2277 break;
2278 case 'k':
2279 knownhosts = optarg;
2280 break;
2281 #endif
2282 case 'L':
2283 inquire_line = optarg;
2284 break;
2285 case 'y':
2286 tty = optarg;
2287 break;
2288 case 't':
2289 ttytype = optarg;
2290 break;
2291 case 'd':
2292 display = optarg;
2293 break;
2294 case 'S':
2295 save = 1;
2296 break;
2297 case 'n':
2298 clientname = optarg;
2299 break;
2300 default:
2301 usage (argv[0], EXIT_FAILURE);
2305 #ifdef HAVE_LIBREADLINE
2306 if (isatty (STDIN_FILENO) && !inquire && !inquire_line && !no_interactive)
2307 interactive = 1;
2308 #endif
2310 pwmd_init ();
2311 rc = pwmd_new (clientname, &pwm);
2312 if (rc)
2313 goto done;
2315 filename = argv[optind] ? pwmd_strdup (argv[optind]) : NULL;
2316 if (no_pinentry != -1)
2317 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
2318 else
2319 rc = pwmd_getopt (pwm, PWMD_OPTION_NO_PINENTRY, &no_pinentry);
2320 if (rc)
2321 goto done;
2323 if (local_pin != -1)
2324 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local_pin);
2325 else
2326 rc = pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local_pin);
2327 if (rc)
2328 goto done;
2330 pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
2331 if (!quiet)
2332 fprintf (stderr, N_("Connecting ...\n"));
2334 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
2335 socktype = is_remote_url (url);
2336 if (socktype != PWMD_SOCKET_LOCAL)
2338 local_pin = 1;
2339 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2340 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, connect_timeout);
2341 if (rc)
2342 goto done;
2343 #endif
2345 if (socktype == PWMD_SOCKET_SSH)
2347 #ifdef WITH_SSH
2348 if (use_ssh_agent == -1)
2349 rc = pwmd_getopt (pwm, PWMD_OPTION_SSH_AGENT, &use_ssh_agent);
2351 if (!rc)
2353 if (!getenv ("SSH_AUTH_SOCK") || identity)
2354 use_ssh_agent = 0;
2356 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_AGENT, use_ssh_agent);
2357 if (rc)
2358 goto done;
2360 else
2361 goto done;
2363 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_NEEDS_PASSPHRASE,
2364 needs_passphrase);
2365 if (rc)
2366 goto done;
2368 if (ssh_passphrase_file)
2370 struct stat st;
2371 int fd;
2373 if (stat (ssh_passphrase_file, &st) == -1)
2375 rc = gpg_error_from_syserror ();
2376 fprintf(stderr, "%s: %s\n", ssh_passphrase_file,
2377 gpg_strerror (rc));
2378 goto done;
2381 result = pwmd_calloc (1, st.st_size+1);
2382 if (!result)
2384 rc = GPG_ERR_ENOMEM;
2385 goto done;
2388 fd = open (ssh_passphrase_file, O_RDONLY);
2389 if (fd != -1)
2391 len = read (fd, result, st.st_size);
2392 if (len == st.st_size)
2393 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_PASSPHRASE, result);
2394 else
2395 rc = gpg_error_from_syserror ();
2397 close (fd);
2399 else
2400 rc = gpg_error_from_syserror ();
2402 pwmd_free (result);
2403 result = NULL;
2404 len = 0;
2406 if (rc)
2408 fprintf(stderr, "%s: %s\n", ssh_passphrase_file,
2409 gpg_strerror (rc));
2410 goto done;
2414 rc = pwmd_connect (pwm, url, identity, knownhosts);
2415 #endif
2417 #ifdef WITH_GNUTLS
2418 else
2420 if (tls_verify != -1)
2422 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_VERIFY, tls_verify);
2423 if (rc)
2424 goto done;
2427 if (prio)
2428 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_PRIORITY, prio);
2430 if (!rc)
2431 rc = pwmd_connect (pwm, url, clientcert, clientkey, cacert,
2432 tls_fingerprint);
2434 #endif
2436 else
2437 rc = pwmd_connect (pwm, url);
2438 #else
2439 rc = pwmd_connect (pwm, url);
2440 #endif
2441 if (rc)
2442 goto done;
2444 if (!quiet)
2445 fprintf (stderr, N_("Connected.\n"));
2447 connected = 1;
2448 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2449 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, socket_timeout);
2450 if (rc)
2451 goto done;
2452 #endif
2454 if (lock_timeout)
2456 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
2457 "OPTION LOCK-TIMEOUT=%li", lock_timeout);
2458 if (rc)
2459 goto done;
2462 if (status_state)
2464 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "OPTION CLIENT-STATE=1");
2465 if (rc)
2466 goto done;
2469 if (lock_on_open != -1)
2471 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCK_ON_OPEN, lock_on_open);
2472 if (rc)
2473 goto done;
2476 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, NULL, NULL);
2477 if (rc)
2478 goto done;
2480 if (timeout > 0)
2482 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
2483 if (rc)
2484 goto done;
2487 if (pinentry_path)
2489 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
2490 if (rc)
2491 goto done;
2494 if (display)
2496 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
2497 if (rc)
2498 goto done;
2501 if (tty)
2503 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, tty);
2504 if (rc)
2505 goto done;
2508 if (ttytype)
2510 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
2511 if (rc)
2512 goto done;
2515 if (lcctype)
2517 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
2518 if (rc)
2519 goto done;
2522 if (lcmessages)
2524 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES, lcmessages);
2525 if (rc)
2526 goto done;
2529 if (show_status)
2531 rc = pwmd_setopt (pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
2532 if (rc)
2533 goto done;
2536 if (filename)
2538 rc = open_command (filename);
2539 if (rc)
2540 goto done;
2543 #ifdef HAVE_LIBREADLINE
2544 if (interactive)
2546 rc = do_interactive ();
2547 result = NULL;
2548 goto do_exit;
2550 #endif
2552 if (inquire)
2554 struct inquire_s *inq = NULL;
2556 rc = set_inquire (inquirefd, inquire_line, &inq);
2557 if (!rc)
2558 rc = pwmd_command (pwm, &result, &len, inquire_cb, inq, "%s", inquire);
2560 free_inquire (inq);
2561 goto done;
2564 #ifndef __MINGW32__
2565 if (fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK, 1) == -1)
2567 rc = gpg_error_from_errno (errno);
2568 goto done;
2570 #endif
2572 ssize_t n;
2574 for (;;)
2576 rc = process_cmd ();
2578 if (rc)
2579 goto done;
2581 n = read (STDIN_FILENO, command, sizeof (command)-1);
2582 if (n == -1)
2584 if (errno == EAGAIN)
2586 #ifdef __MINGW32__
2587 Sleep (100000);
2588 #else
2589 usleep (100000);
2590 #endif
2591 continue;
2594 rc = gpg_error_from_errno (errno);
2595 goto done;
2597 else if (!n)
2598 goto done;
2600 p = command;
2601 command[n] = 0;
2602 break;
2605 if (!p || !*p || !strcasecmp (p, "BYE"))
2606 goto done;
2609 struct inquire_s *inq = NULL;
2610 rc = set_inquire (inquirefd, inquire_line, &inq);
2611 if (!rc)
2613 rc = parse_dotcommand (command, &result, &len, inq);
2614 free_inquire (inq);
2617 if (rc)
2618 goto done;
2620 done:
2621 if (result)
2623 fwrite (result, 1, result[len - 1] == 0 ? len - 1 : len, outfp);
2624 fflush (outfp);
2625 pwmd_free (result);
2628 result = NULL;
2629 if (!rc)
2630 rc = finalize ();
2631 else if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
2632 (void) pwmd_command (pwm, &result, NULL, NULL, NULL,
2633 "GETINFO last_error");
2635 #ifdef HAVE_LIBREADLINE
2636 do_exit:
2637 #endif
2638 wipememory (command, 0, sizeof (command));
2640 if (rc && !quiet)
2641 show_error (pwm, rc, result);
2643 pwmd_close (pwm);
2644 reset_keyfiles ();
2645 pwmd_deinit ();
2646 pwmd_free (result);
2647 pwmd_free (filename);
2648 pwmd_free (inquire);
2649 strv_free (status_ignore);
2650 if (connected && !quiet)
2651 fprintf (stderr, N_("Connection closed.\n"));
2653 exit (rc ? EXIT_FAILURE : EXIT_SUCCESS);