contrib: Add helper to build Android dependencies.
[libpwmd.git] / src / pwmc.c
blob2481114bac61b57fcfaa26a54d12c8f1bea842d6
1 /*
2 Copyright (C) 2006-2023 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 version 2.1 as published by the Free Software Foundation.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
18 USA
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <string.h>
28 #include <libpwmd.h>
29 #include <assuan.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <libgen.h>
33 #include <ctype.h>
34 #include <time.h>
36 #ifdef HAVE_LIMITS_H
37 #include <limits.h>
38 #endif
39 #ifdef HAVE_STDINT_H
40 #include <stdint.h>
41 #endif
42 #ifdef HAVE_STRINGS_H
43 #include <strings.h>
44 #endif
45 #ifdef HAVE_STROPTS_H
46 #include <stropts.h>
47 #endif
48 #ifdef HAVE_UNISTD_H
49 #include <unistd.h>
50 #endif
51 #ifdef HAVE_FCNTL_H
52 #include <fcntl.h>
53 #endif
55 #ifndef __MINGW32__
56 #ifdef HAVE_TERMIOS_H
57 # include <termios.h>
58 #endif
59 #ifdef HAVE_ERR_H
60 # include <err.h>
61 #endif
62 #include <sys/select.h>
63 #endif
65 #include "util-string.h"
66 #include "util-slist.h"
68 #ifdef WITH_GNUTLS
69 #include <gnutls/gnutls.h>
70 #endif
72 #ifdef HAVE_LOCALE_H
73 #include <locale.h>
74 #endif
76 #ifdef HAVE_GETOPT_LONG
77 # ifdef HAVE_GETOPT_H
78 # include <getopt.h>
79 # endif
80 #else
81 # include "getopt_long.h"
82 #endif
84 #ifdef HAVE_LIBREADLINE
85 #if defined(HAVE_READLINE_READLINE_H)
86 # include <readline/readline.h>
87 #elif defined(HAVE_READLINE_H)
88 # include <readline.h>
89 #endif /* !defined(HAVE_READLINE_H) */
90 static int interactive_error;
91 static int interactive;
92 #endif /* HAVE_LIBREADLINE */
94 #ifdef HAVE_READLINE_HISTORY
95 # if defined(HAVE_READLINE_HISTORY_H)
96 # include <readline/history.h>
97 #elif defined(HAVE_HISTORY_H)
98 # include <history.h>
99 # endif
100 #endif /* HAVE_READLINE_HISTORY */
102 #ifndef LINE_MAX
103 #define LINE_MAX 2048
104 #endif
106 #include "gettext.h"
107 #define N_(msgid) gettext(msgid)
109 #include "mem.h"
110 #include "version.h"
112 #define DEFAULT_STATUS_IGNORE "KEEPALIVE,GPGME,PASSPHRASE_INFO,PASSPHRASE_HINT"
113 #define DEFAULT_PIN_TIMEOUT 30
114 #define DEFAULT_PIN_TRIES 3
116 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
117 ? gpg_error(rc) : rc
119 enum
121 SAVE_WHICH_SAVE,
122 SAVE_WHICH_PASSWD,
123 SAVE_WHICH_GENKEY
126 static int no_pinentry;
127 static pwm_t *pwm;
128 static char *filename;
129 static int save;
130 static char *keyid;
131 static char *sign_keyid;
132 static int symmetric;
133 static char *keyparams;
134 static char *keyfile;
135 static char *new_keyfile;
136 static char *sign_keyfile;
137 static int tries;
138 static int local_pin;
139 static int inquirefd;
140 static int statusfd;
141 FILE *statusfp;
142 static int quiet;
143 static char **status_ignore;
144 static int skip_pinentry_status;
146 struct inquire_s
148 int fd;
149 char *line;
150 size_t len;
151 size_t size; // from stat(2).
152 char *last_keyword;
155 struct userid_s {
156 char *userid;
157 char *name;
158 char *email;
159 char *comment;
162 struct keyid_s {
163 char *keyid;
164 char *fpr;
165 char *grip;
166 char *card;
167 int can_sign;
168 int can_encrypt;
169 int can_certify;
170 int can_auth;
171 int expired;
172 time_t expires;
173 time_t created;
174 int secret;
175 int revoked;
176 int algo;
177 unsigned bits;
178 char *curve;
179 struct slist_s *userids;
180 struct slist_s *subkeys;
183 static gpg_error_t finalize ();
184 static gpg_error_t set_inquire (int fd, const char *line,
185 struct inquire_s **result);
186 static gpg_error_t parse_dotcommand (const char *line, char **result,
187 size_t * len, struct inquire_s *inq);
188 static gpg_error_t open_command (char *line);
189 #ifndef HAVE_STRSEP
190 char *strsep (char **, const char *);
191 #endif
192 #if !defined (HAVE_ERR) && !defined (HAVE_ERR_H)
193 int err (int, const char *, ...);
194 #endif
196 static void
197 show_error (pwm_t *h, gpg_error_t rc, const char *str)
199 #ifdef WITH_GNUTLS
200 const char *tlsstr;
201 int e = pwmd_gnutls_error (h, &tlsstr);
203 if (e)
204 fprintf(stderr, "TLS: %s\n", tlsstr);
205 #else
206 (void)h;
207 #endif
208 fprintf (stderr, "ERR %i: %s%s%s%s", rc, gpg_strerror (rc),
209 str ? ": " : "", str ? str : "", str ? "" : "\n");
212 static void
213 reset_keyfiles ()
215 pwmd_free (keyfile);
216 pwmd_free (new_keyfile);
217 pwmd_free (sign_keyfile);
218 keyfile = new_keyfile = sign_keyfile = NULL;
221 static void
222 usage (const char *pn, int status)
224 fprintf (status == EXIT_FAILURE ? stderr : stdout,
225 N_("Usage: %s [options] [file]\n"
226 " --socket <string>\n"
227 " a url string to connect to (%s, see below)\n"
228 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
229 " --connect-timeout <seconds>\n"
230 " seconds before connecting to a remote host fails (0=disabled, 120)\n"
231 " --socket-timeout <seconds>\n"
232 " seconds before a remote command fails (0=disabled, 300)\n"
233 #endif
234 #ifdef WITH_GNUTLS
235 " --ca-cert <filename>\n"
236 " certificate authority (CA) used to sign the server cert\n"
237 " --client-cert <filename>\n"
238 " client certificate to use for authentication\n"
239 " --client-key <filename>\n"
240 " key file used to protect the client certificate\n"
241 " --tls-priority <string>\n"
242 " compression, cipher and hash algorithm string\n"
243 " (SECURE256:SECURE192:SECURE128:-VERS-SSL3.0:-VERS-TLS1.0)\n"
244 " --no-tls-verify\n"
245 " disable verifying the hostname against the server certificate\n"
246 " --tls-fingerprint <string>\n"
247 " a SHA-256 hash of the server fingerprint to verify against\n"
248 #endif
249 #ifdef WITH_SSH
250 " --no-ssh-agent\n"
251 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
252 " --identity, -i <filename>\n"
253 " the ssh identity file to use for authentication\n"
254 " --knownhosts, -k <filename>\n"
255 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
256 " --ssh-passphrase-file <filename>\n"
257 " read the SSH private key passphrase from filename\n"
258 #endif
259 " --no-lock\n"
260 " do not lock the data file upon opening it\n"
261 " --lock-timeout <N>\n"
262 " time in tenths of a second to wait for a locked data file (50)\n"
263 " --name, -n <string>\n"
264 " set the client name\n"
265 " --local-pinentry\n"
266 " force using a local pinentry\n"
267 " --no-pinentry\n"
268 " disable pinentry both remotely and locally\n"
269 " --ttyname, -y <path>\n"
270 " tty that pinentry will use\n"
271 " --ttytype, -t <string>\n"
272 " pinentry terminal type (default is $TERM)\n"
273 " --display, -d\n"
274 " pinentry display (default is $DISPLAY)\n"
275 " --lc-ctype <string>\n"
276 " locale setting for pinentry\n"
277 " --lc-messages <string>\n"
278 " locale setting for pinentry\n"
279 " --tries <N>\n"
280 " number of pinentry tries before failing (3)\n"
281 " --timeout <seconds>\n"
282 " pinentry timeout\n"
283 " --inquire <COMMAND>\n"
284 " the specified command (with any options) uses a server inquire while\n"
285 " command data is read via the inquire file descriptor (stdin)\n"
286 " --inquire-line, -L <STRING>\n"
287 " the initial line to send (i.e., element path) before the inquire data\n"
288 " --inquire-fd <FD>\n"
289 " read inquire data from the specified file descriptor (stdin)\n"
290 " --inquire-file <filename>\n"
291 " read inquire data from the specified filename\n"
292 " --output-fd <FD>\n"
293 " redirect command output to the specified file descriptor\n"
294 " --save, -S\n"
295 " send the SAVE command before exiting\n"
296 " --passphrase-file <filename>\n"
297 " obtain the passphrase from the specified filename\n"
298 " --new-passphrase-file <filename>\n"
299 " obtain the passphrase to save with from the specified filename\n"
300 " --sign-passphrase-file <filename>\n"
301 " obtain the passphrase to sign with from the specified filename\n"
302 " --key-params <filename>\n"
303 " key parameters to use for key generation (pwmd default)\n"
304 " --keyid <recipient>[,<recipient>]\n"
305 " the public key ID to u\n"
306 " --sign-keyid <string>\n"
307 " the key ID to sign the data file with\n"
308 " --symmetric\n"
309 " use conventional encryption with optional signer(s) for new files\n"
310 " --no-status\n"
311 " disable showing of status messages from the server\n"
312 " --status-state\n"
313 " enable receiving of client STATE status messages\n"
314 " --status-fd <FD>\n"
315 " redirect status messages to the specified file descriptor\n"
316 " --status-ignore <string[,...]>\n"
317 " prevent parsing of the specified status message keywords\n"
318 " --quiet\n"
319 " disable showing of extra messages (implies --no-status)\n"
320 #ifdef HAVE_LIBREADLINE
321 " --no-interactive\n"
322 " disable interactive mode\n"
323 #endif
324 " --version\n"
325 " --help\n"),
327 #ifdef DEFAULT_PWMD_SOCKET
328 DEFAULT_PWMD_SOCKET
329 #else
330 "~/.pwmd/socket"
331 #endif
333 fprintf (status == EXIT_FAILURE ? stderr : stdout,
334 N_("\n"
335 "An optional url may be in the form of:\n"
336 " --socket /path/to/socket\n"
337 " --socket file://[/path/to/socket]\n"
338 #ifdef WITH_SSH
339 " or\n"
340 " --socket ssh[46]://[username@]hostname[:port] (uses ssh-agent)\n"
341 " -i identity_file --socket ssh[46]://[username@]hostname[:port]\n"
342 #endif
343 #ifdef WITH_GNUTLS
344 " or\n"
345 " --socket tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
346 " --client-key filename\n"
347 #endif
348 #ifdef HAVE_LIBREADLINE
349 "\n"
350 "Interactive mode is used when input is from a terminal.\n"
351 #endif
353 exit (status);
356 static gpg_error_t
357 inquire_cb (void *user, const char *keyword, gpg_error_t rc,
358 char **data, size_t * size)
360 struct inquire_s *inq = user;
361 int is_password = 0;
362 int is_newpassword = 0;
363 int sign = 0;
364 int is_keyparam = 0;
366 *data = NULL;
367 *size = 0;
369 if (rc)
370 return rc;
372 if (!strcmp (keyword, "PASSPHRASE"))
373 is_password = 1;
374 else if (!strcmp (keyword, "SIGN_PASSPHRASE"))
375 sign = 1;
376 else if (!strcmp (keyword, "NEW_PASSPHRASE"))
377 is_newpassword = 1;
378 #ifdef HAVE_LIBREADLINE
379 else if (!strcmp (keyword, "KEYPARAM") && !interactive)
381 #else
382 else if (!strcmp (keyword, "KEYPARAM"))
384 #endif
385 int fd;
386 if (!keyparams || !*keyparams)
387 return gpg_error (GPG_ERR_INV_PARAMETER);
389 fd = open (keyparams, O_RDONLY);
390 if (fd == -1)
392 fprintf (stderr, "%s: %s\n", keyparams, strerror (errno));
393 return gpg_error_from_syserror ();
396 rc = set_inquire (fd, NULL, &inq);
397 if (rc)
399 close (fd);
400 return rc;
403 if (!quiet)
404 fprintf (stderr, N_("Using file '%s' as %s.\n"), keyparams, keyword);
406 is_keyparam = 1;
409 if ((is_password && !keyfile) || (is_newpassword && !new_keyfile)
410 || (sign && !sign_keyfile))
412 char *tmp;
413 int local;
415 /* Try to use the local pinentry between inquires (new/sign/passphrase).
416 * If --no-pinentry was specified then the passphrase is read from the
417 * terminal as usual. */
418 pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local);
419 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, 1);
420 rc = pwmd_password (pwm, keyword, &tmp, &inq->len);
421 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local);
422 if (rc && gpg_err_code (rc) != GPG_ERR_EOF)
423 return rc;
425 pwmd_free (inq->line);
426 inq->line = tmp;
427 *data = inq->line;
428 *size = inq->len;
429 rc = gpg_error (GPG_ERR_EOF);
430 goto done;
432 else if ((is_newpassword && new_keyfile) || (is_password && keyfile)
433 || (sign && sign_keyfile))
435 int fd;
437 if (sign)
438 fd = open (sign_keyfile, O_RDONLY);
439 else
440 fd = open (is_password || sign ? keyfile : new_keyfile, O_RDONLY);
442 if (fd == -1)
444 if (sign)
445 fprintf (stderr, "%s: %s\n", sign_keyfile, strerror (errno));
446 else
447 fprintf (stderr, "%s: %s\n", is_newpassword ? new_keyfile
448 : keyfile, strerror (errno));
449 return gpg_error_from_syserror ();
452 rc = set_inquire (fd, NULL, &inq);
453 if (rc)
455 close (fd);
456 return rc;
459 if (!quiet)
460 fprintf (stderr, N_("Using keyfile '%s' as %s.\n"),
461 sign ? sign_keyfile : is_newpassword ? new_keyfile
462 : keyfile, keyword);
464 #ifdef HAVE_LIBREADLINE
465 else if ((!inq->last_keyword || strcmp (keyword, inq->last_keyword))
466 && interactive && inq->fd == STDIN_FILENO)
468 fprintf (stderr,
470 ("%sPress CTRL-D to send the current line. Press twice to end. %s:\n"),
471 inq->last_keyword ? "\n" : "", keyword);
472 pwmd_free (inq->last_keyword);
473 inq->last_keyword = pwmd_strdup (keyword);
475 #endif
477 /* The first part of the command data. */
478 if (inq->len)
480 *data = inq->line;
481 *size = inq->len;
482 inq->len = 0;
483 rc = inq->fd == -1 ? gpg_error (GPG_ERR_EOF) : 0;
484 goto done;
487 *size = read (inq->fd, inq->line, ASSUAN_LINELENGTH);
488 if (*size == -1)
490 *size = 0;
491 return gpg_error (gpg_error_from_syserror ());
493 else if (*size)
494 *data = inq->line;
495 else if (inq->fd != STDIN_FILENO &&
496 (is_newpassword || is_password || sign || is_keyparam))
498 *inq->line = 0;
499 inq->size = 1;
500 *data = inq->line;
501 *size = 1;
504 if (((is_newpassword && new_keyfile) || (is_password && keyfile)
505 || (sign && sign_keyfile) || (keyparams && is_keyparam))
506 && *size == inq->size)
507 rc = gpg_error (GPG_ERR_EOF);
509 if (!rc)
510 rc = *size ? 0 : gpg_error (GPG_ERR_EOF);
512 done:
513 if (gpg_err_code (rc) == GPG_ERR_EOF)
515 pwmd_free (inq->last_keyword);
516 inq->last_keyword = NULL;
519 return rc;
522 static int
523 status_msg_cb (void *data, const char *line)
525 char *p = strchr (line, ' ');
526 char **s;
528 (void)data;
530 /* Ignore status messages specified by the client via --status-ignore. */
531 for (s = status_ignore; s && *s; s++)
533 char *tmp = strchr (line, ' ');
534 size_t len = tmp ? strlen (line) - strlen (tmp) : strlen (line);
536 if (!strncmp (line, *s, len) && len == strlen (*s))
537 return 0;
540 #ifdef HAVE_LIBREADLINE
541 if (interactive && !strncmp (line, "XFER ", 5)
542 #else
543 if (!strncmp (line, "XFER ", 5)
544 #endif
545 && *line != '#' && p && strchr (p, ' ') && *++p)
547 char *p1 = strchr (p, ' ');
548 int a = strtol (p, NULL, 10);
550 if (isdigit (*p) && p1)
552 int b = strtol (p1, NULL, 10);
553 int t = a && b ? a * 100 / b : 0;
555 fprintf (statusfp, "\rS:XFER %i/%i %i%%%s", a, b, t,
556 a == b ? "\n" : "");
557 fflush (statusfp);
558 return 0;
561 #ifdef HAVE_LIBREADLINE
562 else if (interactive && (!strncmp (line, "DECRYPT", 7)
563 || !strncmp (line, "ENCRYPT", 7)
564 || !strncmp (line, "GENKEY", 6)))
565 #else
566 else if (!strncmp (line, "DECRYPT", 7) || !strncmp (line, "ENCRYPT", 7)
567 || !strncmp (line, "GENKEY", 6))
568 #endif
570 if (skip_pinentry_status)
571 goto done;
574 fprintf (statusfp, "S:%s\n", line);
575 fflush (statusfp);
576 done:
577 #ifdef HAVE_LIBREADLINE
578 rl_on_new_line ();
579 #endif
580 return 0;
583 static gpg_error_t
584 process_cmd ()
586 return pwmd_process (pwm);
589 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
590 static pwmd_socket_t
591 is_remote_url (const char *str)
593 if (!str)
594 return PWMD_SOCKET_LOCAL;
596 #ifdef WITH_SSH
597 if (strstr (str, "ssh://") || strstr (str, "ssh4://")
598 || strstr (str, "ssh6://"))
599 return PWMD_SOCKET_SSH;
600 #endif
602 #ifdef WITH_GNUTLS
603 if (strstr (str, "tls://") || strstr (str, "tls4://")
604 || strstr (str, "tls6://"))
605 return PWMD_SOCKET_TLS;
606 #endif
608 return PWMD_SOCKET_LOCAL;
610 #endif
612 static char *
613 escape (const char *str)
615 const char *p;
616 char *buf = pwmd_malloc (ASSUAN_LINELENGTH + 1), *b = buf;
617 size_t len = 0;
619 for (p = str; *p; p++, len++)
621 if (len == ASSUAN_LINELENGTH)
622 break;
624 if (*p == '\\')
626 switch (*++p)
628 case 't':
629 *b++ = '\t';
630 break;
631 case 'n':
632 *b++ = '\n';
633 break;
634 case 'v':
635 *b++ = '\v';
636 break;
637 case 'b':
638 *b++ = '\b';
639 break;
640 case 'f':
641 *b++ = '\f';
642 break;
643 case 'r':
644 *b++ = '\r';
645 break;
646 default:
647 *b++ = *p;
648 break;
651 if (!*p)
652 break;
654 continue;
657 *b++ = *p;
660 *b = 0;
661 return buf;
664 static void
665 free_inquire (struct inquire_s *inq)
667 if (!inq)
668 return;
670 pwmd_free (inq->line);
672 if (inq->fd != -1 && inq->fd != STDIN_FILENO)
673 close (inq->fd);
675 pwmd_free (inq->last_keyword);
676 pwmd_free (inq);
679 /* When *result is not NULL it is updated to the new values and not
680 * reallocated. */
681 static gpg_error_t
682 set_inquire (int fd, const char *line, struct inquire_s **result)
684 struct inquire_s inq = { 0 };
685 struct stat st = { 0 };
686 gpg_error_t rc;
688 if (fd != -1)
690 if (fstat (fd, &st) == -1)
691 return gpg_error_from_syserror ();
693 inq.size = st.st_size;
696 inq.fd = fd;
697 inq.line = pwmd_calloc (1, ASSUAN_LINELENGTH);
698 if (!inq.line)
699 return GPG_ERR_ENOMEM;
701 if (line)
703 char *s = escape (line);
705 if (!s)
707 pwmd_free (inq.line);
708 return GPG_ERR_ENOMEM;
711 if (strlen (s) >= ASSUAN_LINELENGTH)
713 pwmd_free (inq.line);
714 pwmd_free (s);
715 return gpg_error (GPG_ERR_LINE_TOO_LONG);
718 strncpy (inq.line, s, ASSUAN_LINELENGTH - 1);
719 inq.len = strlen (s);
720 pwmd_free (s);
723 rc = pwmd_setopt (pwm, PWMD_OPTION_INQUIRE_TOTAL,
724 st.st_size ? st.st_size + strlen (inq.line) : 0);
725 if (rc)
727 pwmd_free (inq.line);
728 return rc;
731 if (*result == NULL)
732 *result = pwmd_malloc (sizeof (struct inquire_s));
733 else
735 if ((*result)->fd != -1 && (*result)->fd != STDIN_FILENO)
736 close ((*result)->fd);
738 pwmd_free ((*result)->line);
739 (*result)->line = NULL;
740 (*result)->fd = -1;
741 (*result)->len = 0;
744 memcpy (*result, &inq, sizeof (struct inquire_s));
745 memset (&inq, 0, sizeof (struct inquire_s));
746 return rc;
749 #ifdef HAVE_LIBREADLINE
750 static int
751 interactive_hook (void)
753 interactive_error = process_cmd ();
755 if (interactive_error)
756 rl_event_hook = NULL;
758 return 0;
761 static int
762 get_readline_char (FILE *fp)
764 if (rl_line_buffer
765 && (!strncmp (rl_line_buffer, ".set passphrase-file ", 16)
766 || !strncmp (rl_line_buffer, ".set new-passphrase-file ", 20)
767 || !strncmp (rl_line_buffer, ".set sign-passphrase-file ", 21)))
768 rl_inhibit_completion = 0;
769 else if (rl_line_buffer
770 && !strncmp (rl_line_buffer, ".redir ", 7))
772 char *p = strchr (rl_line_buffer, ' ');
774 if (p && strchr (++p, ' '))
775 rl_inhibit_completion = 1;
776 else
777 rl_inhibit_completion = 0;
779 else if (rl_line_buffer
780 && !strncmp (rl_line_buffer, ".read ", 6))
782 char *p = rl_line_buffer + 6;
784 if (strstr (p, "--prefix "))
786 p = strstr (p, "--prefix ");
787 p += 9;
788 p = strchr (p, ' ');
789 if (p)
790 p++;
793 if (!p || strchr (p, ' '))
794 rl_inhibit_completion = 1;
795 else
796 rl_inhibit_completion = 0;
798 else
799 rl_inhibit_completion = 1;
801 return fgetc (fp);
804 static void
805 print_help ()
807 fprintf (stderr,
809 ("------------------------------------------------------------\n"
810 "Elements are TAB delimited. Type HELP for protocol commands.\n"
811 "Type .help for pwmc commands. Press CTRL-D to quit.\n"
812 "------------------------------------------------------------\n"));
814 #endif
816 static char *
817 parse_arg (const char *src, char *dst, size_t len)
819 char *p = dst;
820 const char *s = src;
821 size_t n = 0;
823 for (; s && *s && *s != ' ' && n < len; s++, n++)
824 *p++ = *s;
826 *p = 0;
827 return dst;
830 static char *
831 parse_opt (char **line, const char *opt, gpg_error_t * rc)
833 static char result[ASSUAN_LINELENGTH] = { 0 }, *r = result;
834 char *s = strstr (*line, opt);
836 *rc = 0;
837 result[0] = 0;
838 r = result;
840 if (s)
842 size_t len = 0;
843 int quote = 0;
844 size_t rlen = strlen (opt);
845 char *p = s + rlen;
846 int lastc = 0;
848 while (*p && *p == ' ')
850 rlen++;
851 p++;
854 for (; *p && len < sizeof (result) - 1; p++, rlen++)
856 if (isspace (*p) && !quote)
857 break;
859 if (*p == '\"' && lastc != '\\')
861 quote = !quote;
862 lastc = *p;
863 continue;
866 *r++ = lastc = *p;
867 len++;
870 *r = 0;
872 if (len >= sizeof (result) - 1)
873 *rc = GPG_ERR_LINE_TOO_LONG;
874 else
876 p = s + rlen;
878 while (*p && *p == ' ')
879 p++;
881 *line = p;
885 return result;
888 static gpg_error_t
889 read_command (const char *line, char **result, size_t * len)
891 int fd;
892 gpg_error_t rc = 0;
893 char *file = NULL;
894 struct inquire_s *inq = NULL;
895 char *p = (char *) line;
896 const char *prefix = parse_opt (&p, "--prefix", &rc);
897 char filebuf[ASSUAN_LINELENGTH];
899 if (rc)
900 return rc;
902 rc = GPG_ERR_SYNTAX;
904 if (p && *p)
906 while (*p && isspace (*p))
907 p++;
909 file = parse_arg (p, filebuf, sizeof (filebuf));
910 if (file && *file)
912 p += strlen (file) + 1;
914 while (*p && isspace (*p))
915 p++;
917 if (*p)
918 rc = 0;
922 if (rc)
924 fprintf (stderr,
926 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
927 fprintf (stderr,
929 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\\ = \\)\n"));
930 return rc;
933 fd = open (file, O_RDONLY);
934 if (fd == -1)
935 return gpg_error_from_syserror ();
937 rc = set_inquire (fd, prefix && *prefix ? prefix : NULL, &inq);
938 if (rc)
940 close (fd);
941 return rc;
944 rc = pwmd_command (pwm, result, len, inquire_cb, inq, "%s", p);
945 free_inquire (inq);
946 return rc;
949 static gpg_error_t
950 redir_command (const char *line)
952 const char *p = line;
953 int fd;
954 gpg_error_t rc = GPG_ERR_SYNTAX;
955 char *file = NULL;
956 struct inquire_s *inq = NULL;
957 char *result = NULL;
958 size_t len = 0;
959 char filebuf[ASSUAN_LINELENGTH];
961 if (p && *p && *++p)
963 file = parse_arg (p, filebuf, sizeof (filebuf));
964 if (file && *file)
966 p += strlen (file) + 1;
968 while (*p && isspace (*p))
969 p++;
971 if (*p)
972 rc = 0;
976 if (rc)
978 fprintf (stderr, N_("Usage: .redir <filename> <command> [args]\n"));
979 return rc;
982 #ifdef __MINGW32__
983 fd = open (file, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0600);
984 #else
985 fd = open (file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
986 #endif
987 if (fd == -1)
988 return gpg_error_from_syserror ();
990 #ifdef HAVE_LIBREADLINE
991 rc = set_inquire (interactive ? STDIN_FILENO : inquirefd, NULL, &inq);
992 #else
993 rc = set_inquire (inquirefd, NULL, &inq);
994 #endif
995 if (rc)
997 close (fd);
998 return rc;
1001 rc = parse_dotcommand (p, &result, &len, inq);
1002 if (!rc && result && len--)
1003 { // null byte which is always appended
1004 if (write (fd, result, len) != len)
1005 rc = GPG_ERR_TOO_SHORT;
1006 pwmd_free (result);
1009 free_inquire (inq);
1010 close (fd);
1011 return rc;
1014 static gpg_error_t
1015 help_command (const char *line)
1017 (void)line;
1018 fprintf (stderr,
1019 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
1020 " .redir <filename> <command>\n"
1021 " redirect the output of a command to the specified file\n"
1022 "\n"
1023 " .open <filename>\n"
1024 " open the specified filename losing any changes to the current one\n"
1025 "\n"
1026 " .read [--prefix <string>] <filename> <command> [args]\n"
1027 " obtain data from the specified filename for an inquire command\n"
1028 "\n"
1029 " .set help | <name> [<value>]\n"
1030 " set option <name> to <value>\n"
1031 "\n"
1032 " .genkey [args]\n"
1033 " generate a new key\n"
1034 "\n"
1035 " .save [args]\n"
1036 " write changes of the file to disk\n"
1037 "\n"
1038 " .passwd [args]\n"
1039 " change the passphrase of a data file\n"
1040 "\n"
1041 " .listkeys [--options] [pattern[,..]]\n"
1042 " show human readable output of the LISTKEYS command\n"
1043 "\n"
1044 " .help\n"
1045 " this help text\n"));
1046 return 0;
1049 static gpg_error_t
1050 open_command (char *line)
1052 struct inquire_s *inq = NULL;
1053 char *file = line, *tmp = NULL;
1054 gpg_error_t rc;
1055 int local;
1057 while (file && isspace (*file))
1058 file++;
1060 if (file && *file)
1062 char *p = strrchr (file, ' ');
1064 if (p)
1066 while (isspace (*p))
1067 p++;
1069 if (*p)
1071 file = tmp = pwmd_strdup (file + (strlen (file)-strlen (p)));
1072 if (!file || !*file)
1074 pwmd_free (file);
1075 file = tmp = NULL;
1078 else
1079 file = NULL;
1083 if (!file || !*file)
1085 fprintf (stderr, N_("Usage: .open [--options] <filename>\n"));
1086 return GPG_ERR_SYNTAX;
1089 #ifdef HAVE_LIBREADLINE
1090 if (interactive || !quiet)
1091 #else
1092 if (!quiet)
1093 #endif
1094 fprintf (stderr, N_("Opening data file \"%s\" ...\n"), file);
1096 #ifdef HAVE_LIBREADLINE
1097 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1098 #else
1099 rc = set_inquire (-1, NULL, &inq);
1100 #endif
1101 if (rc)
1103 if (tmp)
1104 pwmd_free (file);
1105 return rc;
1108 pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local);
1110 if (keyfile)
1112 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1113 if (!rc)
1114 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, 1);
1116 else
1117 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1119 if (!rc)
1120 rc = pwmd_open (pwm, file, inquire_cb, inq);
1122 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local);
1124 #ifdef HAVE_LIBREADLINE
1125 if (interactive)
1126 reset_keyfiles ();
1127 #endif
1129 free_inquire (inq);
1130 if (!rc)
1132 if (tmp)
1134 pwmd_free (filename);
1135 filename = tmp;
1137 else
1139 char *p = pwmd_strdup (file);
1141 pwmd_free (filename);
1142 filename = p;
1143 if (!filename)
1144 rc = GPG_ERR_ENOMEM;
1147 else
1149 pwmd_free (tmp);
1150 pwmd_free (filename);
1151 filename = NULL;
1154 return rc;
1157 static gpg_error_t
1158 set_command (const char *line)
1160 gpg_error_t rc = 0;
1161 char name[256] = { 0 };
1162 char value[512] = { 0 };
1163 char *namep;
1164 char *valuep;
1165 const char *p = line;
1167 while (p && *p && isspace (*p))
1168 p++;
1170 namep = parse_arg (p, name, sizeof (name));
1171 if (!namep || !*namep)
1173 fprintf (stderr, N_("Usage: .set help | <name> [<value>]\n"));
1174 return GPG_ERR_SYNTAX;
1177 p += strlen (namep);
1178 while (p && *p && isspace (*p))
1179 p++;
1181 valuep = parse_arg (p, value, sizeof (value));
1183 if (!strcmp (name, "passphrase-file") || !strcmp (name, "new-passphrase-file")
1184 || !strcmp (name, "sign-passphrase-file"))
1186 int is_newkeyfile = 1;
1187 int sign = !strcmp (name, "sign-passphrase-file");
1189 if (!strcmp (name, "passphrase-file") || sign)
1190 is_newkeyfile = 0;
1192 if (is_newkeyfile)
1194 pwmd_free (new_keyfile);
1195 new_keyfile = NULL;
1197 else if (sign)
1199 pwmd_free (sign_keyfile);
1200 sign_keyfile = NULL;
1202 else
1204 pwmd_free (keyfile);
1205 keyfile = NULL;
1208 if (!rc && *valuep)
1210 if (is_newkeyfile)
1211 new_keyfile = pwmd_strdup (value);
1212 else if (sign)
1213 sign_keyfile = pwmd_strdup (value);
1214 else
1215 keyfile = pwmd_strdup (value);
1217 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1219 else if (!local_pin && !no_pinentry)
1221 pwmd_socket_t t;
1223 pwmd_socket_type (pwm, &t);
1224 if (t == PWMD_SOCKET_LOCAL)
1225 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1228 else if (!strcmp(name, "pinentry-timeout"))
1230 char *e = NULL;
1231 int n = strtol(valuep, &e, 10);
1233 if (e && *e)
1234 return gpg_error (GPG_ERR_INV_VALUE);
1236 if (!*valuep)
1237 n = DEFAULT_PIN_TIMEOUT;
1239 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, n);
1241 else if (!strcmp (name, "help"))
1243 fprintf (stderr,
1245 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1246 "delimited. When no value is specified the option is unset.\n\n"
1247 "passphrase-file [<filename>]\n"
1248 " set or unset the file to be used when a passphrase is required (*)\n"
1249 "\n"
1250 "new-passphrase-file [<filename>]\n"
1251 " set or unset the file to be used when a new passphrase is required (*)\n"
1252 "\n"
1253 "sign-passphrase-file [<filename>]\n"
1254 " set or unset the file to be used when a passphrase is required for\n"
1255 " signing (symmetric) (*)\n"
1256 "\n"
1257 "pinentry-timeout <seconds>\n"
1258 " the amount of seconds before pinentry gives up waiting for input\n"
1259 "\n"
1260 "* = the next protocol command will unset this value\n"
1263 else
1264 rc = GPG_ERR_UNKNOWN_OPTION;
1266 return rc;
1269 static gpg_error_t
1270 do_save_passwd_command (const char *line, int which)
1272 struct inquire_s *inq = NULL;
1273 gpg_error_t rc;
1274 int local;
1276 #ifdef HAVE_LIBREADLINE
1277 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1278 #else
1279 rc = set_inquire (-1, NULL, &inq);
1280 #endif
1281 if (rc)
1282 return rc;
1284 pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local);
1286 if (new_keyfile || keyfile || sign_keyfile)
1288 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1289 if (!rc)
1290 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, 1);
1292 else
1293 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1295 if (!rc)
1297 skip_pinentry_status = 1;
1299 if (which == SAVE_WHICH_SAVE)
1300 rc = pwmd_save (pwm, line, inquire_cb, inq);
1301 else if (which == SAVE_WHICH_PASSWD)
1302 rc = pwmd_passwd (pwm, line, inquire_cb, inq);
1303 else
1304 rc = pwmd_genkey (pwm, line, inquire_cb, inq);
1306 skip_pinentry_status = 0;
1309 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local);
1311 #ifdef HAVE_LIBREADLINE
1312 if (interactive)
1313 reset_keyfiles ();
1314 #endif
1316 free_inquire (inq);
1317 return rc;
1320 static gpg_error_t
1321 save_command (const char *line)
1323 return do_save_passwd_command (line, SAVE_WHICH_SAVE);
1326 static void
1327 search_and_replace (char *str, const char *s, const char r)
1329 char *p;
1331 p = strstr (str, s);
1332 if (p)
1334 *p = r;
1335 while (*++p)
1336 *p = *(p+1);
1337 search_and_replace (str, s, r);
1338 return;
1342 static char *
1343 openpgp_unescape (char *str)
1345 search_and_replace (str, "\\x3a", ':');
1346 search_and_replace (str, "\\x5c", '\\');
1347 return str;
1350 static void
1351 free_listkeys (struct slist_s *keys)
1353 unsigned i, t;
1355 t = slist_length (keys);
1356 for (i = 0; i < t; i++)
1358 struct keyid_s *key = slist_nth_data (keys, i);
1359 unsigned n, nt;
1361 nt = slist_length (key->userids);
1362 for (n = 0; n < nt; n++)
1364 struct userid_s *userid = slist_nth_data (key->userids, n);
1366 pwmd_free (userid->userid);
1367 pwmd_free (userid->name);
1368 pwmd_free (userid->email);
1369 pwmd_free (userid->comment);
1370 pwmd_free (userid);
1373 slist_free (key->userids);
1374 nt = slist_length (key->subkeys);
1375 for (n = 0; n < nt; n++)
1377 struct keyid_s *sub = slist_nth_data (key->subkeys, n);
1379 pwmd_free (sub->keyid);
1380 pwmd_free (sub->fpr);
1381 pwmd_free (sub->grip);
1382 pwmd_free (sub->card);
1383 pwmd_free (sub->curve);
1384 pwmd_free (sub);
1387 slist_free (key->subkeys);
1388 pwmd_free (key);
1391 slist_free (keys);
1394 static const char *
1395 openpgp_algorithm (struct keyid_s *key)
1397 switch (key->algo)
1399 case 1:
1400 case 2:
1401 case 3:
1402 return "RSA";
1403 case 16:
1404 case 20:
1405 return "ELG";
1406 case 17:
1407 return "DSA";
1408 case 301:
1409 case 302:
1410 case 18:
1411 return "ECDH";
1412 case 303:
1413 return "EDDSA";
1414 default:
1415 break;
1418 return N_("Unknown");
1421 static void
1422 display_listkeys (struct slist_s *keys)
1424 unsigned i, t;
1426 t = slist_length (keys);
1427 for (i = 0; i < t; i++)
1429 struct keyid_s *key = slist_nth_data (keys, i);
1430 unsigned st = slist_length (key->subkeys);
1431 unsigned s;
1432 unsigned ut = slist_length (key->userids);
1433 unsigned u;
1435 for (u = 0; u < ut; u++)
1437 struct userid_s *userid = slist_nth_data (key->userids, u);
1439 fprintf(stdout, N_("User ID: %s\n"), userid->userid);
1442 for (s = 0; s < st; s++)
1444 struct keyid_s *sub = slist_nth_data (key->subkeys, s);
1445 struct tm *tmp;
1446 const char *caps = NULL;
1447 char expires[11] = { 0 };
1448 char created[11] = { 0 };
1450 if (sub->expires)
1452 tmp = localtime (&sub->expires);
1453 strftime (expires, sizeof (expires), "%Y-%m-%d", tmp);
1456 tmp = localtime (&sub->created);
1457 strftime (created, sizeof (created), "%Y-%m-%d", tmp);
1459 if (sub->can_encrypt)
1460 caps = "E";
1461 else if (sub->can_sign)
1462 caps = "S";
1463 else if (sub->can_auth)
1464 caps = "A";
1465 else if (sub->can_certify)
1466 caps = "C";
1468 fprintf(stdout, N_(
1469 " Subkey %u: %s [%s]%s%s %s-%u%s%s\n"
1470 " Created: %s %s%s\n"
1471 " Fingerprint: %s\n"
1472 " Keygrip: %s\n"
1473 "%s%s%s"),
1474 s+1,
1475 sub->keyid,
1476 caps,
1477 sub->secret || sub->card ? "[P]" : "",
1478 sub->revoked ? "[R]" : "",
1479 openpgp_algorithm (sub),
1480 sub->bits,
1481 sub->curve ? "-" : "",
1482 sub->curve ? sub->curve : "",
1483 created,
1484 sub->expired ? N_("Expired: ") : expires[0] ? N_("Expires: ") : "",
1485 sub->expired || expires[0] ? expires : "",
1486 sub->fpr,
1487 sub->grip,
1488 sub->card ? N_(" Card: ") : "",
1489 sub->card ? sub->card : "",
1490 sub->card ? "\n" : "");
1493 if (i+1 < t)
1494 fprintf (stdout, "\n");
1498 static gpg_error_t
1499 listkeys_command (const char *pattern)
1501 gpg_error_t rc;
1502 char *result;
1503 char **lines = NULL, **p;
1504 struct slist_s *keys = NULL;
1506 rc = pwmd_command (pwm, &result, NULL, NULL, NULL, "LISTKEYS %s", pattern);
1507 if (rc)
1508 return rc;
1510 lines = str_split (result, "\n", 0);
1511 pwmd_free (result);
1512 if (!lines)
1513 return GPG_ERR_ENOMEM;
1515 for (p = lines; *p; p++)
1517 struct keyid_s *key;
1518 char **fields = str_split (*p, ":", 0);
1519 int i, f;
1520 unsigned s;
1521 unsigned n_subkeys = 0;
1522 struct slist_s *tlist;
1524 if (!fields)
1526 rc = GPG_ERR_ENOMEM;
1527 break;
1530 key = pwmd_calloc (1, sizeof (struct keyid_s));
1531 if (!key)
1533 strv_free (fields);
1534 rc = GPG_ERR_ENOMEM;
1535 break;
1538 for (f = i = 0; i < 17; i++, f++)
1540 int b = 0;
1542 if (i < 10)
1543 b = atoi (fields[f]) != 0;
1545 switch (i)
1547 case 0: key->revoked = b; break;
1548 case 1: key->expired = b; break;
1549 case 4: key->can_encrypt = b; break;
1550 case 5: key->can_sign = b; break;
1551 case 7: key->secret = b; break;
1552 case 16: n_subkeys = strtoul (fields[f], NULL, 10); break;
1553 default:
1554 break;
1558 for (s = 0; s < n_subkeys; s++)
1560 struct keyid_s *sub;
1561 int b = 0;
1563 sub = pwmd_calloc (1, sizeof (struct keyid_s));
1564 if (!sub)
1566 strv_free (fields);
1567 rc = GPG_ERR_ENOMEM;
1568 break;
1571 for (i = 0; i < 20; i++, f++)
1573 if (i < 11)
1574 b = atoi (fields[f]) != 0;
1576 switch (i)
1578 case 0: sub->revoked = b; break;
1579 case 1: sub->expired = b; break;
1580 case 4: sub->can_encrypt = b; break;
1581 case 5: sub->can_sign = b; break;
1582 case 6: sub->can_certify = b; break;
1583 case 7: sub->secret = b; break;
1584 case 8: sub->can_auth = b; break;
1585 case 11: sub->algo = atoi (fields[f]); break;
1586 case 12: sub->bits = atoi (fields[f]); break;
1587 case 13: sub->keyid = pwmd_strdup (fields[f]); break;
1588 case 14: sub->fpr = pwmd_strdup (fields[f]); break;
1589 case 15: sub->grip = pwmd_strdup (fields[f]); break;
1590 case 16: sub->created = strtoul (fields[f], NULL, 10); break;
1591 case 17: sub->expires = strtoul (fields[f], NULL, 10); break;
1592 case 18: sub->card = fields[f] && strlen(fields[f]) > 1
1593 ? pwmd_strdup (fields[f]) : NULL; break;
1594 case 19: sub->curve = strlen (fields[f]) > 1 ? pwmd_strdup (openpgp_unescape(fields[f])) : NULL; break;
1595 default:
1596 break;
1600 tlist = slist_append (key->subkeys, sub);
1601 if (!tlist)
1603 rc = GPG_ERR_ENOMEM;
1604 break;
1607 key->subkeys = tlist;
1610 if (rc)
1612 strv_free (fields);
1613 break;
1616 // Re-create a line containing the userIds.
1617 for (; f < strv_length (fields); f++)
1619 struct userid_s *userid;
1621 userid = pwmd_calloc (1, sizeof (struct userid_s));
1622 if (!userid)
1624 rc = GPG_ERR_ENOMEM;
1625 break;
1628 // Revoked.
1629 f++;
1630 // Invalid.
1631 f++;
1632 // Validity.
1633 f++;
1635 userid->userid = pwmd_strdup (openpgp_unescape (fields[f++]));
1636 userid->name = pwmd_strdup (openpgp_unescape (fields[f++]));
1637 userid->email = pwmd_strdup (openpgp_unescape (fields[f++]));
1638 userid->comment = pwmd_strdup (openpgp_unescape (fields[f]));
1640 tlist = slist_append (key->userids, userid);
1641 if (!tlist)
1643 rc = GPG_ERR_ENOMEM;
1644 break;
1647 key->userids = tlist;
1650 strv_free (fields);
1651 if (rc)
1652 break;
1654 tlist = slist_append (keys, key);
1655 if (!tlist)
1657 rc = GPG_ERR_ENOMEM;
1658 break;
1661 keys = tlist;
1664 strv_free (lines);
1666 if (!rc)
1667 display_listkeys (keys);
1669 free_listkeys (keys);
1670 return rc;
1673 static gpg_error_t
1674 parse_dotcommand (const char *line, char **result,
1675 size_t * len, struct inquire_s *inq)
1677 const char *p = line;
1678 gpg_error_t rc = 0;
1680 if (!strncmp (p, ".read", 5) && (p[5] == ' ' || p[5] == 0))
1681 rc = read_command (p + 5, result, len);
1682 else if (!strncmp (p, ".redir", 6) && (p[6] == ' ' || p[6] == 0))
1683 rc = redir_command (p + 6);
1684 else if (!strncmp (p, ".help", 5) && (p[5] == ' ' || p[5] == 0))
1685 rc = help_command (p + 5);
1686 else if (!strncmp (p, ".open", 5) && (p[5] == ' ' || p[5] == 0))
1687 rc = open_command ((char *)p + 5);
1688 else if (!strncmp (p, ".set", 4) && (p[4] == ' ' || p[4] == 0))
1689 rc = set_command (p + 4);
1690 else if (!strncmp (p, ".save", 5) && (p[5] == ' ' || p[5] == 0))
1691 rc = do_save_passwd_command (p + 5, SAVE_WHICH_SAVE);
1692 else if (!strncmp (p, ".passwd", 7) && (p[7] == ' ' || p[7] == 0))
1693 rc = do_save_passwd_command (p + 7, SAVE_WHICH_PASSWD);
1694 else if (!strncmp (p, ".genkey", 7) && (p[7] == ' ' || p[7] == 0))
1695 rc = do_save_passwd_command (p + 7, SAVE_WHICH_GENKEY);
1696 else if (!strncmp (p, ".listkeys", 9) && (p[9] == ' ' || p[9] == 0))
1697 rc = listkeys_command (p+9);
1698 else
1700 rc = pwmd_command (pwm, result, len, inquire_cb, inq, "%s", line);
1701 #ifdef HAVE_LIBREADLINE
1702 if (interactive)
1703 reset_keyfiles ();
1704 #else
1705 reset_keyfiles ();
1706 #endif
1708 if (!rc && !strncasecmp (line, "RESET", 5) && (p[5] == ' ' || p[5] == 0))
1710 pwmd_free (filename);
1711 filename = NULL;
1715 return FINISH (rc);
1718 #ifdef HAVE_LIBREADLINE
1719 #ifdef HAVE_READLINE_HISTORY
1720 static void
1721 add_history_item (const char *line)
1723 int i;
1724 HIST_ENTRY *h = NULL;
1726 for (i = 0; i < history_length; i++)
1728 h = history_get (i + history_base);
1729 if (h && !strcmp (h->line, line))
1730 break;
1733 if (h)
1735 char *s = NULL;
1737 h = remove_history (i);
1738 #ifdef HAVE_FREE_HISTORY_ENTRY
1739 s = free_history_entry (h);
1740 #endif
1741 if (s)
1742 wipememory (s, 0, strlen (s));
1743 free (s);
1746 add_history (line);
1748 #endif
1750 static gpg_error_t
1751 do_interactive ()
1753 gpg_error_t rc;
1754 struct inquire_s *inq = NULL;
1756 rl_initialize ();
1757 rc = process_cmd ();
1758 if (rc)
1759 return rc;
1761 rc = set_inquire (STDIN_FILENO, NULL, &inq);
1762 if (rc)
1763 return rc;
1765 fprintf (stderr,
1766 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1767 print_help ();
1768 rl_event_hook = &interactive_hook;
1769 rl_getc_function = get_readline_char;
1770 rl_set_keyboard_input_timeout (100000);
1772 for (;;)
1774 char *line;
1775 char *result = NULL;
1776 size_t len;
1777 char buf[255];
1779 snprintf (buf, sizeof (buf), "pwmc%s%s> ",
1780 filename ? ":" : "", filename ? filename : "");
1781 line = readline (buf);
1782 if (interactive_error)
1784 if (line)
1785 wipememory (line, 0, strlen (line));
1787 free (line);
1788 rc = interactive_error;
1789 break;
1792 if (!line)
1794 rc = finalize ();
1795 if (!rc)
1796 break;
1798 if (gpg_err_code (rc) != GPG_ERR_CANCELED &&
1799 gpg_err_code (rc) != GPG_ERR_EOF)
1800 fprintf (stderr, "ERR %i: %s\n", rc, gpg_strerror (rc));
1802 continue;
1804 else if (!*line)
1806 free (line);
1807 continue;
1810 #ifdef HAVE_READLINE_HISTORY
1811 add_history_item (line);
1812 #endif
1813 rc = parse_dotcommand (line, &result, &len, inq);
1814 wipememory (line, 0, strlen (line));
1815 free (line);
1816 if (rc)
1818 char *tmp = NULL;
1820 if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
1821 (void) pwmd_command (pwm, &tmp, NULL, NULL, NULL,
1822 "GETINFO last_error");
1824 show_error (pwm, rc, tmp);
1825 pwmd_free (tmp);
1827 else if (result && len)
1828 printf ("%s%s", result, result[len - 1] != '\n' ? "\n" : "");
1830 pwmd_free (result);
1833 free_inquire (inq);
1834 return rc;
1836 #endif
1838 static gpg_error_t
1839 finalize ()
1841 gpg_error_t rc = 0;
1842 #ifdef HAVE_LIBREADLINE
1843 int quit = 0;
1845 if (interactive)
1847 int finished = 0;
1849 fprintf (stderr, "\n");
1853 char *p, buf[16];
1855 fprintf (stderr,
1857 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1858 p = fgets (buf, sizeof (buf), stdin);
1860 if (feof (stdin))
1862 clearerr (stdin);
1863 return GPG_ERR_EOF;
1866 switch (*p)
1868 case 'h':
1869 print_help ();
1870 break;
1871 case 'c':
1872 return GPG_ERR_CANCELED;
1873 case 'Q':
1874 return 0;
1875 case 'f':
1876 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1877 "CLEARCACHE %s", filename);
1878 if (rc)
1879 return rc;
1881 interactive_hook ();
1882 break;
1883 case 'S':
1884 quit = 1;
1885 case 's':
1886 save = 1;
1887 finished = 1;
1888 break;
1889 default:
1890 break;
1893 while (!finished);
1895 #endif
1897 if (save && !filename)
1899 fprintf (stderr,
1901 ("No filename was specified on the command line. Aborting.\n"));
1902 return GPG_ERR_CANCELED;
1905 if (save && filename)
1907 char *args =
1908 pwmd_strdup_printf ("%s %s%s %s%s %s",
1909 symmetric ? "--symmetric" : "",
1910 keyid ? "--keyid=" : "",
1911 keyid ? keyid : "",
1912 sign_keyid ? "--sign-keyid=" : "",
1913 sign_keyid ? sign_keyid : "",
1914 keyparams ? "--inquire-keyparam" : "");
1916 #ifdef HAVE_LIBREADLINE
1917 if (!quiet || interactive)
1919 #else
1920 if (!quiet)
1922 #endif
1923 fprintf (stderr, "\n");
1924 fprintf (stderr, N_("Saving changes ...\n"));
1927 rc = save_command (args);
1928 pwmd_free (args);
1931 #ifdef HAVE_LIBREADLINE
1932 if (interactive)
1933 return rc ? rc : quit ? 0 : GPG_ERR_CANCELED;
1934 #endif
1936 return rc;
1939 static void
1940 parse_status_ignore (char *str)
1942 char *s;
1944 strv_free (status_ignore);
1945 status_ignore = NULL;
1946 if (!str || !*str)
1947 return;
1949 while ((s = strsep (&str, ",")))
1951 char **p = strv_cat (status_ignore, pwmd_strdup (s));
1953 if (!p)
1955 strv_free (status_ignore);
1956 status_ignore = NULL;
1957 break;
1959 status_ignore = p;
1964 main (int argc, char *argv[])
1966 int connected = 0;
1967 int status_state = 0;
1968 gpg_error_t rc;
1969 int opt;
1970 char command[ASSUAN_LINELENGTH], *p = NULL;
1971 char *result = NULL;
1972 size_t len = 0;
1973 char *display = NULL, *tty = NULL, *ttytype = NULL;
1974 char *lcctype = NULL, *lcmessages = NULL;
1975 int outfd = STDOUT_FILENO;
1976 FILE *outfp = stdout;
1977 int show_status = 1;
1978 const char *clientname = "pwmc";
1979 char *inquire = NULL;
1980 char *inquire_line = NULL;
1981 int timeout = 0;
1982 #ifdef WITH_SSH
1983 int use_ssh_agent = -1;
1984 char *knownhosts = NULL;
1985 char *identity = NULL;
1986 int needs_passphrase = 0;
1987 char *ssh_passphrase_file = NULL;
1988 #endif
1989 #ifdef WITH_GNUTLS
1990 char *cacert = NULL;
1991 char *clientcert = NULL;
1992 char *clientkey = NULL;
1993 char *prio = NULL;
1994 int tls_verify = -1;
1995 char *tls_fingerprint = NULL;
1996 #endif
1997 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1998 pwmd_socket_t socktype;
1999 long socket_timeout = 300;
2000 int connect_timeout = 120;
2001 #endif
2002 #ifdef HAVE_LIBREADLINE
2003 int no_interactive = 0;
2004 #endif
2005 int lock_on_open = -1;
2006 long lock_timeout = -2;
2007 char *url = NULL;
2008 char *tmp = NULL;
2009 /* The order is important. */
2010 enum
2012 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2013 OPT_SOCKET_TIMEOUT, OPT_CONNECT_TIMEOUT,
2014 #endif
2015 #ifdef WITH_SSH
2016 OPT_USE_SSH_AGENT, OPT_IDENTITY, OPT_KNOWNHOSTS, OPT_SSH_NEEDS_PASSPHRASE,
2017 OPT_SSH_PASSPHRASE_FILE,
2018 #endif
2019 #ifdef WITH_GNUTLS
2020 OPT_CACERT, OPT_CLIENTCERT, OPT_CLIENTKEY, OPT_PRIORITY, OPT_VERIFY,
2021 OPT_SERVER_FP,
2022 #endif
2023 OPT_URL, OPT_SOCKET, OPT_LOCAL, OPT_TTYNAME, OPT_TTYTYPE, OPT_DISPLAY,
2024 OPT_LC_CTYPE, OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES, OPT_PINENTRY,
2025 OPT_KEYFILE, OPT_PASSPHRASE_FILE, OPT_NEW_KEYFILE, OPT_NEW_PASSPHRASE_FILE,
2026 OPT_SIGN_KEYFILE, OPT_SIGN_PASSPHRASE_FILE, OPT_NOLOCK, OPT_LOCK_TIMEOUT,
2027 OPT_SAVE, OPT_OUTPUT_FD, OPT_INQUIRE, OPT_INQUIRE_FD, OPT_INQUIRE_FILE,
2028 OPT_INQUIRE_LINE, OPT_NO_STATUS, OPT_STATUS_IGNORE, OPT_STATUSFD, OPT_NAME,
2029 OPT_VERSION, OPT_HELP, OPT_KEYID, OPT_SIGN_KEYID, OPT_SYMMETRIC,
2030 OPT_KEYPARAMS, OPT_NO_PINENTRY, OPT_QUIET, OPT_STATUS_STATE,
2031 #ifdef HAVE_LIBREADLINE
2032 OPT_NO_INTERACTIVE,
2033 #endif
2035 const struct option long_opts[] = {
2036 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2037 {"socket-timeout", 1, 0, 0},
2038 {"connect-timeout", 1, 0, 0},
2039 #endif
2041 #ifdef WITH_SSH
2042 {"no-ssh-agent", 0, 0, 0},
2043 {"identity", 1, 0, 'i'},
2044 {"knownhosts", 1, 0, 'k'},
2045 {"ssh-needs-passphrase", 0, 0, 0},
2046 {"ssh-passphrase-file", 1, 0, 0},
2047 #endif
2048 #ifdef WITH_GNUTLS
2049 {"ca-cert", 1, 0, 0},
2050 {"client-cert", 1, 0, 0},
2051 {"client-key", 1, 0, 0},
2052 {"tls-priority", 1, 0, 0},
2053 {"no-tls-verify", 0, 0, 0},
2054 {"tls-fingerprint", 1, 0, 0},
2055 #endif
2056 {"socket", 1, 0, 0},
2057 {"url", 1, 0, 0},
2058 {"local-pinentry", 0, 0},
2059 {"ttyname", 1, 0, 'y'},
2060 {"ttytype", 1, 0, 't'},
2061 {"display", 1, 0, 'd'},
2062 {"lc-ctype", 1, 0, 0},
2063 {"lc-messages", 1, 0, 0},
2064 {"timeout", 1, 0, 0},
2065 {"tries", 1, 0, 0},
2066 {"pinentry", 1, 0, 0},
2067 {"key-file", 1, 0, 0},
2068 {"passphrase-file", 1, 0, 0},
2069 {"new-key-file", 1, 0, 0},
2070 {"new-passphrase-file", 1, 0, 0},
2071 {"sign-key-file", 1, 0, 0},
2072 {"sign-passphrase-file", 1, 0, 0},
2073 {"no-lock", 0, 0, 0},
2074 {"lock-timeout", 1, 0, 0},
2075 {"save", 0, 0, 'S'},
2076 {"output-fd", 1, 0, 0},
2077 {"inquire", 1, 0, 0},
2078 {"inquire-fd", 1, 0, 0},
2079 {"inquire-file", 1, 0, 0},
2080 {"inquire-line", 1, 0, 'L'},
2081 {"no-status", 0, 0, 0},
2082 {"status-ignore", 1, 0, 0},
2083 {"status-fd", 1, 0, 0},
2084 {"name", 1, 0, 'n'},
2085 {"version", 0, 0, 0},
2086 {"help", 0, 0, 0},
2087 {"keyid", 1, 0, 0},
2088 {"sign-keyid", 1, 0, 0},
2089 {"symmetric", 0, 0, 0},
2090 {"key-params", 1, 0, 0},
2091 {"no-pinentry", 0, 0, 0},
2092 {"quiet", 0, 0, 0},
2093 {"status-state", 0, 0, 0},
2094 #ifdef HAVE_LIBREADLINE
2095 {"no-interactive", 0, 0},
2096 #endif
2097 {0, 0, 0, 0}
2099 #ifdef WITH_SSH
2100 const char *optstring = "L:y:t:d:P:I:Sn:i:k:s";
2101 #else
2102 const char *optstring = "L:y:t:d:P:I:Sn:s";
2103 #endif
2104 int opt_index = 0;
2106 #ifdef ENABLE_NLS
2107 setlocale (LC_ALL, "");
2108 bindtextdomain ("libpwmd", LOCALEDIR);
2109 #endif
2111 tries = DEFAULT_PIN_TRIES;
2112 inquirefd = STDIN_FILENO;
2113 statusfd = STDERR_FILENO;
2114 statusfp = stderr;
2115 tmp = pwmd_strdup (DEFAULT_STATUS_IGNORE);
2116 parse_status_ignore (tmp);
2117 pwmd_free (tmp);
2118 no_pinentry = -1;
2119 local_pin = -1;
2121 while ((opt =
2122 getopt_long (argc, argv, optstring, long_opts, &opt_index)) != -1)
2124 switch (opt)
2126 /* Handle long options without a short option part. */
2127 case 0:
2128 switch (opt_index)
2130 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2131 case OPT_SOCKET_TIMEOUT:
2132 socket_timeout = strtol (optarg, &p, 10);
2133 break;
2134 case OPT_CONNECT_TIMEOUT:
2135 connect_timeout = strtol (optarg, &p, 10);
2136 break;
2137 #endif
2138 #ifdef WITH_SSH
2139 case OPT_USE_SSH_AGENT:
2140 use_ssh_agent = 0;
2141 break;
2142 case OPT_SSH_NEEDS_PASSPHRASE:
2143 needs_passphrase = 1;
2144 break;
2145 case OPT_SSH_PASSPHRASE_FILE:
2146 ssh_passphrase_file = optarg;
2147 break;
2148 #endif
2149 #ifdef WITH_GNUTLS
2150 case OPT_CACERT:
2151 cacert = optarg;
2152 break;
2153 case OPT_CLIENTCERT:
2154 clientcert = optarg;
2155 break;
2156 case OPT_CLIENTKEY:
2157 clientkey = optarg;
2158 break;
2159 case OPT_PRIORITY:
2160 prio = optarg;
2161 break;
2162 case OPT_VERIFY:
2163 tls_verify = 0;
2164 break;
2165 case OPT_SERVER_FP:
2166 tls_fingerprint = optarg;
2167 break;
2168 #endif
2169 case OPT_SYMMETRIC:
2170 symmetric = 1;
2171 break;
2172 case OPT_KEYPARAMS:
2173 keyparams = optarg;
2174 break;
2175 case OPT_KEYFILE:
2176 case OPT_PASSPHRASE_FILE:
2177 keyfile = pwmd_strdup (optarg);
2178 break;
2179 case OPT_NEW_KEYFILE:
2180 case OPT_NEW_PASSPHRASE_FILE:
2181 new_keyfile = pwmd_strdup (optarg);
2182 break;
2183 case OPT_SIGN_KEYFILE:
2184 case OPT_SIGN_PASSPHRASE_FILE:
2185 sign_keyfile = pwmd_strdup (optarg);
2186 break;
2187 case OPT_NOLOCK:
2188 lock_on_open = 0;
2189 break;
2190 case OPT_LOCK_TIMEOUT:
2191 lock_timeout = strtol (optarg, &p, 10);
2192 break;
2193 case OPT_URL:
2194 case OPT_SOCKET:
2195 url = optarg;
2196 break;
2197 case OPT_LOCAL:
2198 local_pin = 1;
2199 break;
2200 case OPT_LC_CTYPE:
2201 lcctype = pwmd_strdup (optarg);
2202 break;
2203 case OPT_LC_MESSAGES:
2204 lcmessages = pwmd_strdup (optarg);
2205 break;
2206 case OPT_TIMEOUT:
2207 timeout = strtol (optarg, &p, 10);
2208 break;
2209 case OPT_TRIES:
2210 tries = strtol (optarg, &p, 10);
2211 break;
2212 case OPT_INQUIRE:
2213 inquire = escape (optarg);
2214 break;
2215 case OPT_INQUIRE_FD:
2216 inquirefd = strtol (optarg, &p, 10);
2217 break;
2218 case OPT_INQUIRE_FILE:
2219 inquirefd = open (optarg, O_RDONLY);
2220 if (inquirefd == -1)
2221 err (EXIT_FAILURE, "%s", optarg);
2222 break;
2223 case OPT_OUTPUT_FD:
2224 outfd = strtol (optarg, &p, 10);
2225 if (!p || !*p)
2227 outfp = fdopen (outfd, "wb");
2228 if (!outfp)
2229 err (EXIT_FAILURE, "%i", outfd);
2231 break;
2232 case OPT_NO_STATUS:
2233 show_status = 0;
2234 break;
2235 case OPT_STATUSFD:
2236 statusfd = strtol (optarg, &p, 10);
2237 if (!p || !*p)
2239 statusfp = fdopen (statusfd, "wb");
2240 if (!statusfp)
2241 err (EXIT_FAILURE, "%i", statusfd);
2243 break;
2244 case OPT_STATUS_IGNORE:
2245 parse_status_ignore (optarg);
2246 break;
2247 case OPT_VERSION:
2248 printf ("%s (pwmc)\n\n"
2249 "Copyright (C) 2006-2023\n"
2250 "%s\n"
2251 "Released under the terms of the LGPL v2.1.\n\n"
2252 "Compile-time features:\n"
2253 #ifdef HAVE_LIBREADLINE
2254 "+INTERACTIVE "
2255 #else
2256 "-INTERACTIVE "
2257 #endif
2258 #ifdef WITH_SSH
2259 "+SSH "
2260 #else
2261 "-SSH "
2262 #endif
2263 #ifdef WITH_GNUTLS
2264 "+GNUTLS "
2265 #else
2266 "-GNUTLS "
2267 #endif
2268 #ifdef WITH_PINENTRY
2269 "+PINENTRY "
2270 #else
2271 "-PINENTRY "
2272 #endif
2273 #ifdef WITH_QUALITY
2274 "+QUALITY "
2275 #else
2276 "-QUALITY "
2277 #endif
2278 #ifdef MEM_DEBUG
2279 "+MEM_DEBUG "
2280 #else
2281 "-MEM_DEBUG "
2282 #endif
2283 "\n", PACKAGE_STRING LIBPWMD_GIT_HASH, PACKAGE_BUGREPORT);
2284 exit (EXIT_SUCCESS);
2285 case OPT_PINENTRY:
2286 break;
2287 case OPT_HELP:
2288 usage (argv[0], EXIT_SUCCESS);
2289 case OPT_KEYID:
2290 keyid = optarg;
2291 break;
2292 case OPT_SIGN_KEYID:
2293 sign_keyid = optarg;
2294 break;
2295 case OPT_QUIET:
2296 quiet = 1;
2297 show_status = 0;
2298 break;
2299 case OPT_STATUS_STATE:
2300 status_state = 1;
2301 break;
2302 case OPT_NO_PINENTRY:
2303 no_pinentry = 1;
2304 break;
2305 #ifdef HAVE_LIBREADLINE
2306 case OPT_NO_INTERACTIVE:
2307 no_interactive = 1;
2308 break;
2309 #endif
2310 default:
2311 usage (argv[0], EXIT_FAILURE);
2314 if (p && *p)
2316 fprintf (stderr, N_("%s: invalid argument for option '--%s'\n"),
2317 argv[0], long_opts[opt_index].name);
2318 usage (argv[0], EXIT_FAILURE);
2321 break;
2322 #ifdef WITH_SSH
2323 case 'i':
2324 identity = optarg;
2325 break;
2326 case 'k':
2327 knownhosts = optarg;
2328 break;
2329 #endif
2330 case 'L':
2331 inquire_line = optarg;
2332 break;
2333 case 'y':
2334 tty = optarg;
2335 break;
2336 case 't':
2337 ttytype = optarg;
2338 break;
2339 case 'd':
2340 display = optarg;
2341 break;
2342 case 'S':
2343 save = 1;
2344 break;
2345 case 'n':
2346 clientname = optarg;
2347 break;
2348 default:
2349 usage (argv[0], EXIT_FAILURE);
2353 #ifdef HAVE_LIBREADLINE
2354 if (isatty (STDIN_FILENO) && !inquire && !inquire_line && !no_interactive)
2355 interactive = 1;
2356 #endif
2358 pwmd_init ();
2359 rc = pwmd_new (clientname, &pwm);
2360 if (rc)
2361 goto done;
2363 filename = argv[optind] ? pwmd_strdup (argv[optind]) : NULL;
2364 if (no_pinentry != -1)
2365 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
2366 else
2367 rc = pwmd_getopt (pwm, PWMD_OPTION_NO_PINENTRY, &no_pinentry);
2368 if (rc)
2369 goto done;
2371 if (local_pin != -1)
2372 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local_pin);
2373 else
2374 rc = pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local_pin);
2375 if (rc)
2376 goto done;
2378 pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
2379 if (!quiet)
2380 fprintf (stderr, N_("Connecting ...\n"));
2382 if (status_state)
2384 rc = pwmd_setopt (pwm, PWMD_OPTION_STATE_STATUS, 1);
2385 if (rc)
2386 goto done;
2389 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
2390 socktype = is_remote_url (url);
2391 if (socktype != PWMD_SOCKET_LOCAL)
2393 local_pin = 1;
2394 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2395 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, connect_timeout);
2396 if (rc)
2397 goto done;
2398 #endif
2400 if (socktype == PWMD_SOCKET_SSH)
2402 #ifdef WITH_SSH
2403 if (use_ssh_agent == -1)
2404 rc = pwmd_getopt (pwm, PWMD_OPTION_SSH_AGENT, &use_ssh_agent);
2406 if (!rc)
2408 if (use_ssh_agent != 0)
2410 char *t = getenv ("SSH_AUTH_SOCK");
2412 use_ssh_agent = t && *t ? 1 : 0;
2415 if (identity)
2416 use_ssh_agent = 0;
2418 if (!identity && !use_ssh_agent)
2420 pwmd_close (pwm);
2421 fprintf (stderr, N_("No identity specified and no SSH_AUTH_SOCK environment variable.\n"));
2422 usage (argv [0], EXIT_FAILURE);
2425 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_AGENT, use_ssh_agent);
2426 if (rc)
2427 goto done;
2429 else
2430 goto done;
2432 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_NEEDS_PASSPHRASE,
2433 needs_passphrase);
2434 if (rc)
2435 goto done;
2437 if (ssh_passphrase_file)
2439 struct stat st;
2440 int fd;
2442 if (stat (ssh_passphrase_file, &st) == -1)
2444 rc = gpg_error_from_syserror ();
2445 fprintf(stderr, "%s: %s\n", ssh_passphrase_file,
2446 gpg_strerror (rc));
2447 goto done;
2450 result = pwmd_calloc (1, st.st_size+1);
2451 if (!result)
2453 rc = GPG_ERR_ENOMEM;
2454 goto done;
2457 fd = open (ssh_passphrase_file, O_RDONLY);
2458 if (fd != -1)
2460 len = read (fd, result, st.st_size);
2461 if (len == st.st_size)
2462 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_PASSPHRASE, result);
2463 else
2464 rc = gpg_error_from_syserror ();
2466 close (fd);
2468 else
2469 rc = gpg_error_from_syserror ();
2471 pwmd_free (result);
2472 result = NULL;
2473 len = 0;
2475 if (rc)
2477 fprintf(stderr, "%s: %s\n", ssh_passphrase_file,
2478 gpg_strerror (rc));
2479 goto done;
2483 rc = pwmd_connect (pwm, url, identity, knownhosts);
2484 #endif
2486 #ifdef WITH_GNUTLS
2487 else
2489 if (tls_verify != -1)
2491 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_VERIFY, tls_verify);
2492 if (rc)
2493 goto done;
2496 if (prio)
2497 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_PRIORITY, prio);
2499 if (!rc)
2500 rc = pwmd_connect (pwm, url, clientcert, clientkey, cacert,
2501 tls_fingerprint);
2503 #endif
2505 else
2506 rc = pwmd_connect (pwm, url);
2507 #else
2508 rc = pwmd_connect (pwm, url);
2509 #endif
2510 if (rc)
2511 goto done;
2513 if (!quiet)
2514 fprintf (stderr, N_("Connected.\n"));
2516 connected = 1;
2517 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2518 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, socket_timeout);
2519 if (rc)
2520 goto done;
2521 #endif
2523 if (lock_on_open != -1)
2525 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCK_ON_OPEN, lock_on_open);
2526 if (rc)
2527 goto done;
2530 if (lock_timeout != -2)
2532 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCK_TIMEOUT, lock_timeout);
2533 if (rc)
2534 goto done;
2537 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, NULL, NULL);
2538 if (rc)
2539 goto done;
2541 if (timeout > 0)
2543 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
2544 if (rc)
2545 goto done;
2548 if (display)
2550 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
2551 if (rc)
2552 goto done;
2555 if (tty)
2557 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, tty);
2558 if (rc)
2559 goto done;
2562 if (ttytype)
2564 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
2565 if (rc)
2566 goto done;
2569 if (lcctype)
2571 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
2572 if (rc)
2573 goto done;
2576 if (lcmessages)
2578 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES, lcmessages);
2579 if (rc)
2580 goto done;
2583 if (show_status)
2585 rc = pwmd_setopt (pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
2586 if (rc)
2587 goto done;
2590 if (filename)
2592 rc = open_command (filename);
2593 if (rc)
2594 goto done;
2597 #ifdef HAVE_LIBREADLINE
2598 if (interactive)
2600 rc = do_interactive ();
2601 result = NULL;
2602 while (history_length)
2604 char *s = NULL;
2605 HIST_ENTRY *h = remove_history (0);
2606 #ifdef HAVE_FREE_HISTORY_ENTRY
2607 s = free_history_entry (h);
2608 #else
2609 (void)h;
2610 #endif
2611 if (s)
2612 wipememory (s, 0, strlen (s));
2613 free (s);
2615 goto do_exit;
2617 #endif
2619 if (inquire)
2621 struct inquire_s *inq = NULL;
2623 rc = set_inquire (inquirefd, inquire_line, &inq);
2624 if (!rc)
2625 rc = pwmd_command (pwm, &result, &len, inquire_cb, inq, "%s", inquire);
2627 free_inquire (inq);
2628 goto done;
2631 #ifndef __MINGW32__
2632 if (fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK, 1) == -1)
2634 rc = gpg_error_from_errno (errno);
2635 goto done;
2637 #endif
2639 ssize_t n;
2641 for (;;)
2643 rc = process_cmd ();
2645 if (rc)
2646 goto done;
2648 n = read (STDIN_FILENO, command, sizeof (command)-1);
2649 if (n == -1)
2651 if (errno == EAGAIN)
2653 #ifdef __MINGW32__
2654 Sleep (100000);
2655 #else
2656 usleep (100000);
2657 #endif
2658 continue;
2661 rc = gpg_error_from_errno (errno);
2662 goto done;
2664 else if (!n)
2665 goto done;
2667 p = command;
2668 command[n] = 0;
2669 break;
2672 if (!p || !*p || !strcasecmp (p, "BYE"))
2673 goto done;
2676 struct inquire_s *inq = NULL;
2677 rc = set_inquire (inquirefd, inquire_line, &inq);
2678 if (!rc)
2680 rc = parse_dotcommand (command, &result, &len, inq);
2681 free_inquire (inq);
2684 if (rc)
2685 goto done;
2687 done:
2688 if (result)
2690 fwrite (result, 1, result[len - 1] == 0 ? len - 1 : len, outfp);
2691 fflush (outfp);
2692 pwmd_free (result);
2695 result = NULL;
2696 if (!rc)
2697 rc = finalize ();
2698 else if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
2699 (void) pwmd_command (pwm, &result, NULL, NULL, NULL,
2700 "GETINFO last_error");
2702 #ifdef HAVE_LIBREADLINE
2703 do_exit:
2704 #endif
2705 wipememory (command, 0, sizeof (command));
2707 if (rc && !quiet)
2708 show_error (pwm, rc, result);
2710 pwmd_close (pwm);
2711 reset_keyfiles ();
2712 pwmd_deinit ();
2713 pwmd_free (result);
2714 pwmd_free (filename);
2715 pwmd_free (inquire);
2716 strv_free (status_ignore);
2717 if (connected && !quiet)
2718 fprintf (stderr, N_("Connection closed.\n"));
2720 exit (rc ? EXIT_FAILURE : EXIT_SUCCESS);