pwmc: changed how inquires are done. No longer use hard-coded command
[libpwmd.git] / src / pwmc.c
blob025a26e0006d7c41b589927fc3f451bc38333389
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2007-2009 Ben Kibbey <bjk@luxsci.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program 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
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110-1301 USA
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <err.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <libpwmd.h>
26 #include <assuan.h>
27 #ifdef DEBUG
28 #include <sys/select.h>
29 #endif
30 #include <fcntl.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
38 #ifdef HAVE_LOCALE_H
39 #include <locale.h>
40 #endif
42 #ifdef HAVE_GETOPT_LONG
43 #ifdef HAVE_GETOPT_H
44 #include <getopt.h>
45 #endif
46 #else
47 #include "getopt_long.h"
48 #endif
50 #include "gettext.h"
51 #define N_(msgid) gettext(msgid)
53 #include "mem.h"
55 #define DEFAULT_PORT 22
57 pwm_t *pwm;
59 static void show_error(gpg_error_t error)
61 fprintf(stderr, "ERR %i %s\n", gpg_err_code(error), pwmd_strerror(error));
64 static void usage(const char *pn, int status)
66 fprintf(status == EXIT_FAILURE ? stderr : stdout, N_(
67 "Read a PWMD protocol command from standard input.\n\n"
68 "Usage: pwmc [options] [file]\n"
69 #ifdef DEBUG
70 " --debug <N>\n"
71 " pinentry method (0=pwmd, 1=libpwmd, 2=pwmd async, "
72 "3=libpwmd async)\n"
73 #endif
74 "\n"
75 #ifdef WITH_TCP
76 " --host, -h <hostname>\n"
77 " connect to the specified hostname\n"
78 "\n"
79 " --port <N>\n"
80 " alterate port (22)\n"
81 "\n"
82 " --user <username>\n"
83 " SSH username (default is the invoking user)\n"
84 "\n"
85 " --identity, -i <filename>\n"
86 " SSH identity file\n"
87 "\n"
88 " --known-hosts, -k <filename>\n"
89 " known host's file (for server validation)\n"
90 "\n"
91 " --get-hostkey, -g\n"
92 " retrieve the remote SSH host key and exit\n"
93 "\n"
94 " --ipv4, -4\n"
95 " try connecting via IPv4 only\n"
96 "\n"
97 " --ipv6, -6\n"
98 " try connecting via IPv6 only\n"
99 "\n"
100 #endif
101 " --url <string>\n"
102 " a url string to parse\n"
103 "\n"
104 " --no-status\n"
105 " disable showing of status messages from the server\n"
106 "\n"
107 " --name, -n <string>\n"
108 " set the client name\n"
109 "\n"
110 " --socket <filename>\n"
111 " local socket to connect to (~/.pwmd/socket)\n"
112 "\n"
113 " --passphrase, -P <string>\n"
114 " passphrase to use (disables pinentry use)\n"
115 "\n"
116 " --key-file <filename>\n"
117 " obtain the passphrase from the specified filename\n"
118 "\n"
119 " --base64\n"
120 " the passphrase is base64 encoded\n"
121 "\n"
122 " --timeout <seconds>\n"
123 " pinentry timeout\n"
124 "\n"
125 " --tries <N>\n"
126 " number of pinentry tries before failing (3)\n"
127 "\n"
128 " --pinentry <path>\n"
129 " the full path to the pinentry binary (server default)\n"
130 "\n"
131 " --ttyname, -y <path>\n"
132 " tty that pinentry will use\n"
133 "\n"
134 " --ttytype, -t <string>\n"
135 " pinentry terminal type (default is $TERM)\n"
136 "\n"
137 " --display, -d\n"
138 " pinentry display (default is $DISPLAY)\n"
139 "\n"
140 " --lc-ctype <string>\n"
141 " locale setting for pinentry\n"
142 "\n"
143 " --lc-messages <string>\n"
144 " locale setting for pinentry\n"
145 "\n"
147 " --local-pinentry\n"
148 " force using a local pinentry\n"
149 "\n"
150 " --output-fd <FD>\n"
151 " redirect command output to the specified file descriptor\n"
152 "\n"
153 " --inquire <COMMAND>\n"
154 " the specified command (with any options) uses a server inquire while\n"
155 " command data is read via the inquire file descriptor (stdin)\n"
156 "\n"
157 " --inquire-fd <FD>\n"
158 " read inquire data from the specified file descriptor (stdin)\n"
159 "\n"
160 " --cipher <string>\n"
161 " the cipher to use when saving (see pwmd(1))\n"
162 "\n"
163 " --save, -S\n"
164 " send the SAVE command before exiting\n"
165 "\n"
166 " --force-save\n"
167 " like --save, but ask for a passphrase\n"
168 "\n"
169 " --iterations, -I <N>\n"
170 " encrypt with the specified number of iterations when saving\n"
171 "\n"
172 " --version\n"
173 " --help\n"));
174 fprintf(status == EXIT_FAILURE ? stderr : stdout, N_(
175 "\n"
176 "A url string (specified with --url) may be in the form of:\n"
177 " file://[path/to/socket]\n"
178 #ifdef WITH_TCP
179 " ssh[46]://[username@]hostname[:port],identity,known_hosts\n"
180 #endif
182 exit(status);
185 struct inquire_s {
186 int fd;
187 char *line;
188 size_t len;
191 static gpg_error_t inquire_cb(void *user, const char *cmd, gpg_error_t rc,
192 char **data, size_t *len)
194 struct inquire_s *inq = user;
196 *data = NULL;
197 *len = 0;
199 if (rc)
200 return rc;
202 /* The first part of the command data. */
203 if (inq->len) {
204 *data = inq->line;
205 *len = inq->len;
206 inq->len = 0;
207 return 0;
210 *len = read(inq->fd, inq->line, ASSUAN_LINELENGTH);
212 if (*len == -1)
213 return gpg_error_from_syserror();
215 if (*len)
216 *data = inq->line;
218 return *len ? 0 : GPG_ERR_EOF;
221 static int status_msg_cb(void *data, const char *line)
223 fprintf(stderr, "%s\n", line);
224 return 0;
227 static gpg_error_t process_cmd(pwm_t *pwm, char **result, int input)
229 gpg_error_t rc;
230 pwmd_async_t s;
232 do {
233 int i, n;
234 fd_set rfds;
235 int nfds = 5;
236 pwmd_fd_t pfds[nfds];
238 FD_ZERO(&rfds);
239 rc = pwmd_get_fds(pwm, pfds, &nfds);
241 if (rc)
242 return rc;
244 if (!nfds) {
245 s = pwmd_process(pwm, &rc, result);
246 break;
249 for (i = 0, n = 0; i < nfds; i++) {
250 FD_SET(pfds[i].fd, &rfds);
251 n = pfds[i].fd > n ? pfds[i].fd : n;
254 if (input)
255 FD_SET(STDIN_FILENO, &rfds);
257 nfds = select(n+1, &rfds, NULL, NULL, NULL);
259 if (nfds == -1) {
260 rc = gpg_error_from_errno(errno);
261 return rc;
264 if (input && FD_ISSET(STDIN_FILENO, &rfds))
265 return 0;
267 s = pwmd_process(pwm, &rc, result);
268 } while (s == ASYNC_PROCESS);
270 return rc;
273 #ifdef WITH_TCP
274 static gpg_error_t knownhost_cb(void *data, const char *host, const char *key,
275 size_t len)
277 gpg_error_t rc;
278 char *buf = pwmd_strdup_printf(N_("Password Manager Daemon: %s\n\nWhile attempting an SSH connection to %s there was a problem verifying it's hostkey against the known and trusted hosts file because it's hostkey was not found.\n\nWould you like to treat this connection as trusted for this and future connections by adding %s's hostkey to the known hosts file?"), (char *)data, host, host);
280 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TITLE, buf);
281 pwmd_free(buf);
283 if (rc)
284 return rc;
286 return pwmd_getpin(pwm, NULL, NULL, PWMD_PINENTRY_CONFIRM);
289 static int is_remote_url(const char *str)
291 if (strstr(str, "file://") || strstr(str, "local://"))
292 return 0;
294 return 1;
296 #endif
298 int main(int argc, char *argv[])
300 int opt;
301 char *password = NULL;
302 char *keyfile = NULL;
303 int base64 = 0;
304 char *filename = NULL;
305 char *socketpath = NULL;
306 char command[ASSUAN_LINELENGTH], *p;
307 int ret = EXIT_SUCCESS;
308 gpg_error_t error;
309 char *result = NULL;
310 int save = 0;
311 char *pinentry_path = NULL;
312 char *display = NULL, *tty = NULL, *ttytype = NULL, *lcctype = NULL,
313 *lcmessages = NULL;
314 int outfd = STDOUT_FILENO;
315 FILE *outfp = stdout;
316 int inquirefd = STDIN_FILENO;
317 FILE *inquirefp = stdin;
318 int show_status = 1;
319 char *clientname = "pwmc";
320 char *inquire = NULL;
321 long iter = -2;
322 int have_iter = 0;
323 int timeout = 0;
324 int local_pin = 0;
325 int force_save = 0;
326 char *cipher = NULL;
327 #ifdef WITH_TCP
328 char *host = NULL;
329 int port = DEFAULT_PORT;
330 char *username = NULL;
331 char *ident = NULL;
332 char *known_hosts = NULL;
333 int get = 0;
334 int prot = PWMD_IP_ANY;
335 #endif
336 int tries = 0;
337 int local_tries = 3;
338 int try = 0;
339 pwmd_socket_t s;
340 int lock_on_open = 1;
341 #ifdef DEBUG
342 int method = 0;
343 fd_set rfds;
344 #endif
345 char *url_string = NULL;
346 /* The order is important. */
347 enum {
348 #ifdef DEBUG
349 OPT_DEBUG,
350 #endif
351 #ifdef WITH_TCP
352 OPT_HOST, OPT_PORT, OPT_IDENTITY, OPT_KNOWN_HOSTS, OPT_USER,
353 OPT_GET_HOSTKEY, OPT_IPV4, OPT_IPV6,
354 #endif
355 OPT_URL, OPT_LOCAL, OPT_FORCE_SAVE, OPT_TTYNAME, OPT_TTYTYPE,
356 OPT_DISPLAY, OPT_LC_CTYPE, OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES,
357 OPT_PINENTRY, OPT_PASSPHRASE, OPT_KEYFILE, OPT_BASE64, OPT_SOCKET,
358 OPT_NOLOCK, OPT_SAVE, OPT_ITERATIONS, OPT_OUTPUT_FD, OPT_INQUIRE,
359 OPT_INQUIRE_FD, OPT_NO_STATUS, OPT_NAME, OPT_VERSION, OPT_HELP,
360 OPT_CIPHER,
362 const struct option long_opts[] = {
363 #ifdef DEBUG
364 { "debug", 1, 0, 0 },
365 #endif
366 #ifdef WITH_TCP
367 { "host", 1, 0, 'h' },
368 { "port", 1, 0, 'p' },
369 { "identity", 1, 0, 'i' },
370 { "known-hosts", 1, 0, 'k' },
371 { "user", 1, 0, 'u' },
372 { "get-hostkey", 0, 0, 'g' },
373 { "ipv4", 0, 0, '4' },
374 { "ipv6", 0, 0, '6' },
375 #endif
376 { "url", 1, 0, 0 },
377 { "local-pinentry", 0, 0 },
378 { "force-save", 0, 0 },
379 { "ttyname", 1, 0, 'y' },
380 { "ttytype", 1, 0, 't' },
381 { "display", 1, 0, 'd' },
382 { "lc-ctype", 1, 0, 0 },
383 { "lc-messages", 1, 0, 0 },
384 { "timeout", 1, 0, 0 },
385 { "tries", 1, 0, 0 },
386 { "pinentry", 1, 0, 0 },
387 { "passphrase", 1, 0, 'P' },
388 { "key-file", 1, 0, 0 },
389 { "base64", 0, 0, 0 },
390 { "socket", 1, 0, 0 },
391 { "no-lock", 0, 0, 0 },
392 { "save", 0, 0, 'S' },
393 { "iterations", 1, 0, 'I' },
394 { "output-fd", 1, 0, 0 },
395 { "inquire", 1, 0, 0 },
396 { "inquire-fd", 1, 0, 0 },
397 { "no-status", 0, 0, 0 },
398 { "name", 1, 0, 'n' },
399 { "version", 0, 0, 0 },
400 { "help", 0, 0, 0 },
401 { "cipher", 1, 0, 0 },
402 { 0, 0, 0, 0}
404 #ifdef WITH_TCP
405 const char *optstring = "46h:p:i:k:u:gy:t:d:P:I:Sn:";
406 #else
407 const char *optstring = "y:t:d:P:I:Sn:";
408 #endif
409 int opt_index = 0;
411 #ifdef ENABLE_NLS
412 setlocale(LC_ALL, "");
413 bindtextdomain("libpwmd", LOCALEDIR);
414 #endif
416 while ((opt = getopt_long(argc, argv, optstring, long_opts, &opt_index)) != -1) {
417 switch (opt) {
418 /* Handle long options without a short option part. */
419 case 0:
420 switch (opt_index) {
421 #ifdef DEBUG
422 case OPT_DEBUG:
423 method = atoi(optarg);
425 if (method > 3)
426 method = 3;
427 break;
428 #endif
429 case OPT_KEYFILE:
430 keyfile = optarg;
431 break;
432 case OPT_BASE64:
433 base64 = 1;
434 break;
435 case OPT_NOLOCK:
436 lock_on_open = 0;
437 break;
438 case OPT_URL:
439 url_string = optarg;
440 break;
441 case OPT_LOCAL:
442 local_pin = 1;
443 break;
444 case OPT_FORCE_SAVE:
445 save = force_save = 1;
446 break;
447 case OPT_LC_CTYPE:
448 lcctype = pwmd_strdup(optarg);
449 break;
450 case OPT_LC_MESSAGES:
451 lcmessages = pwmd_strdup(optarg);
452 break;
453 case OPT_TIMEOUT:
454 timeout = atoi(optarg);
455 break;
456 case OPT_TRIES:
457 tries = atoi(optarg);
458 local_tries = tries;
459 break;
460 case OPT_SOCKET:
461 socketpath = pwmd_strdup(optarg);
462 break;
463 case OPT_INQUIRE:
464 inquire = optarg;
465 break;
466 case OPT_INQUIRE_FD:
467 inquirefd = atoi(optarg);
468 inquirefp = fdopen(inquirefd, "r");
470 if (!inquirefp) {
471 pwmd_free(password);
472 err(EXIT_FAILURE, "%i", inquirefd);
474 break;
475 case OPT_OUTPUT_FD:
476 outfd = atoi(optarg);
477 outfp = fdopen(outfd, "w");
479 if (!outfp) {
480 pwmd_free(password);
481 err(EXIT_FAILURE, "%i", outfd);
483 break;
484 case OPT_NO_STATUS:
485 show_status = 0;
486 break;
487 case OPT_VERSION:
488 pwmd_free(password);
489 printf("%s (pwmc)\n%s\n\n"
490 "Compile-time features:\n"
491 #ifdef WITH_TCP
492 "+SSH "
493 #else
494 "-SSH "
495 #endif
496 #ifdef WITH_PINENTRY
497 "+PINENTRY "
498 #else
499 "-PINENTRY "
500 #endif
501 #ifdef WITH_QUALITY
502 "+QUALITY "
503 #else
504 "-QUALITY "
505 #endif
506 #ifdef MEM_DEBUG
507 "+MEM_DEBUG "
508 #else
509 "-MEM_DEBUG "
510 #endif
511 "\n"
512 , PACKAGE_STRING, PACKAGE_BUGREPORT);
513 exit(EXIT_SUCCESS);
514 case OPT_PINENTRY:
515 pinentry_path = optarg;
516 break;
517 case OPT_HELP:
518 usage(argv[0], EXIT_SUCCESS);
519 case OPT_CIPHER:
520 cipher = optarg;
521 break;
522 default:
523 usage(argv[0], EXIT_FAILURE);
526 break;
527 #ifdef WITH_TCP
528 case '4':
529 prot = PWMD_IPV4;
530 break;
531 case '6':
532 prot = PWMD_IPV6;
533 break;
534 case 'h':
535 host = pwmd_strdup(optarg);
536 break;
537 case 'p':
538 port = atoi(optarg);
539 break;
540 case 'i':
541 ident = pwmd_strdup(optarg);
542 break;
543 case 'u':
544 username = pwmd_strdup(optarg);
545 break;
546 case 'k':
547 known_hosts = pwmd_strdup(optarg);
548 break;
549 case 'g':
550 get = 1;
551 break;
552 #endif
553 case 'y':
554 tty = optarg;
555 break;
556 case 't':
557 ttytype = optarg;
558 break;
559 case 'd':
560 display = optarg;
561 break;
562 case 'S':
563 save = 1;
564 break;
565 case 'I':
566 iter = strtol(optarg, NULL, 10);
567 have_iter = 1;
568 break;
569 case 'P':
570 password = pwmd_strdup(optarg);
571 memset(optarg, 0, strlen(optarg));
572 break;
573 case 'n':
574 clientname = optarg;
575 break;
576 default:
577 pwmd_free(password);
578 usage(argv[0], EXIT_FAILURE);
582 #ifdef DEBUG
583 if (!url_string) {
584 #endif
585 #ifdef WITH_TCP
586 if (host && !get && !ident) {
587 pwmd_free(password);
588 usage(argv[0], EXIT_FAILURE);
591 if (get && !host) {
592 pwmd_free(password);
593 usage(argv[0], EXIT_FAILURE);
595 #endif
596 #ifdef DEBUG
598 #endif
600 filename = argv[optind];
601 pwmd_init();
602 pwm = pwmd_new(clientname);
603 #ifdef DEBUG
604 FD_ZERO(&rfds);
605 #endif
607 #ifdef WITH_TCP
608 if (host || url_string) {
609 local_pin = 1;
611 if (prot != PWMD_IP_ANY) {
612 error = pwmd_setopt(pwm, PWMD_OPTION_IP_VERSION, prot);
614 if (error)
615 goto done;
618 error = pwmd_setopt(pwm, PWMD_OPTION_KNOWNHOST_CB, knownhost_cb);
620 if (error)
621 goto done;
623 error = pwmd_setopt(pwm, PWMD_OPTION_KNOWNHOST_DATA, clientname);
625 if (error)
626 goto done;
628 #ifdef DEBUG
629 if (method >= 2) {
630 if (get) {
631 char *hostkey;
633 error = pwmd_get_hostkey_async(pwm, host, port);
635 if (error)
636 errx(EXIT_FAILURE, "%s: %s", host, pwmd_strerror(error));
638 error = process_cmd(pwm, &hostkey, 0);
640 if (error)
641 goto done;
643 printf("%s", hostkey);
644 pwmd_free(hostkey);
645 pwmd_free(password);
646 pwmd_close(pwm);
647 exit(EXIT_SUCCESS);
650 if (url_string)
651 error = pwmd_connect_url_async(pwm, url_string);
652 else
653 error = pwmd_ssh_connect_async(pwm, host, port, ident, username,
654 known_hosts);
656 if (error)
657 goto done;
659 error = process_cmd(pwm, NULL, 0);
661 if (error)
662 goto done;
664 else {
665 #endif
666 if (get) {
667 char *hostkey;
669 error = pwmd_get_hostkey(pwm, host, port, &hostkey);
671 if (error)
672 goto done;
674 printf("%s", hostkey);
675 pwmd_free(hostkey);
676 pwmd_free(password);
677 pwmd_close(pwm);
678 exit(EXIT_SUCCESS);
681 if (url_string)
682 error = pwmd_connect_url(pwm, url_string);
683 else
684 error = pwmd_ssh_connect(pwm, host, port, ident, username, known_hosts);
686 if (error)
687 goto done;
688 #ifdef DEBUG
690 #endif
692 else {
693 #endif
694 if (url_string)
695 error = pwmd_connect_url(pwm, url_string);
696 else
697 error = pwmd_connect(pwm, socketpath);
699 if (error)
700 goto done;
701 #ifdef WITH_TCP
703 #endif
705 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TITLE, NULL);
706 error = pwmd_socket_type(pwm, &s);
708 if (error)
709 goto done;
711 if (s == PWMD_SOCKET_SSH && force_save && !local_pin) {
712 error = GPG_ERR_WRONG_KEY_USAGE;
713 goto done;
716 if (have_iter) {
717 error = pwmd_command(pwm, &result, "VERSION");
719 if (error)
720 goto done;
722 pwmd_free(result);
724 if (iter < 0) {
725 pwmd_free(password);
726 pwmd_close(pwm);
727 usage(argv[0], EXIT_FAILURE);
731 if (filename && lock_on_open) {
732 error = pwmd_setopt(pwm, PWMD_OPTION_LOCK_ON_OPEN, 1);
734 if (error)
735 goto done;
738 if (base64) {
739 error = pwmd_setopt(pwm, PWMD_OPTION_BASE64, 1);
741 if (error)
742 goto done;
745 if (timeout > 0) {
746 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
748 if (error)
749 goto done;
752 if (local_pin && filename && !keyfile) {
753 error = pwmd_command(pwm, NULL, "ISCACHED %s", filename);
755 if (error == GPG_ERR_NOT_FOUND) {
756 local_password:
757 if (try++ == local_tries)
758 goto done;
760 if (password)
761 pwmd_free(password);
763 password = NULL;
765 if (try > 1)
766 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, 0);
768 error = pwmd_getpin(pwm, filename, &password,
769 try > 1 ? PWMD_PINENTRY_OPEN_FAILED : PWMD_PINENTRY_OPEN);
771 if (error)
772 goto done;
774 error = pwmd_setopt(pwm, PWMD_OPTION_PASSPHRASE, password);
776 if (error)
777 goto done;
779 if (try > 1)
780 goto do_open;
782 else if (error && error != GPG_ERR_ENOENT)
783 goto done;
786 if (password) {
787 error = pwmd_setopt(pwm, PWMD_OPTION_PASSPHRASE, password);
789 if (error)
790 goto done;
792 else {
793 if (pinentry_path) {
794 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
796 if (error)
797 goto done;
800 if (display) {
801 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
803 if (error)
804 goto done;
807 if (tty) {
808 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TTY, tty);
810 if (error)
811 goto done;
814 if (ttytype) {
815 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
817 if (error)
818 goto done;
821 if (lcctype) {
822 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
824 if (error)
825 goto done;
828 if (lcmessages) {
829 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES,
830 lcmessages);
832 if (error)
833 goto done;
836 if (tries > 0) {
837 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
839 if (error)
840 goto done;
844 if (show_status) {
845 error = pwmd_setopt(pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
847 if (error)
848 goto done;
851 do_open:
852 if (filename) {
853 #ifdef WITH_TCP
854 if (keyfile && (!local_pin || host || is_remote_url(url_string))) {
855 struct inquire_s inq;
857 memset(&inq, 0, sizeof(inq));
858 inq.fd = open(keyfile, O_RDONLY);
860 if (inq.fd == -1) {
861 error = gpg_error_from_syserror();
862 goto done;
865 inq.line = pwmd_calloc(1, ASSUAN_LINELENGTH);
867 if (!inq.line) {
868 error = GPG_ERR_ENOMEM;
869 goto done;
872 error = pwmd_open_inquire(pwm, filename, inquire_cb, &inq);
873 pwmd_free(inq.line);
874 close(inq.fd);
876 if (error)
877 goto done;
879 goto read_command;
881 #endif
882 #ifdef DEBUG
883 switch (method) {
884 case 0:
885 error = pwmd_open(pwm, filename);
886 break;
887 case 1:
888 error = pwmd_open2(pwm, filename);
889 break;
890 case 2:
891 error = pwmd_open_async(pwm, filename);
893 break;
894 case 3:
895 error = pwmd_open_async2(pwm, filename);
896 break;
899 if (error && local_pin && error == GPG_ERR_INV_PASSPHRASE)
900 goto local_password;
902 if (error)
903 goto done;
905 if (method >= 2)
906 error = process_cmd(pwm, &result, 0);
907 #else
908 #ifdef WITH_TCP
909 if (host)
910 error = pwmd_open2(pwm, filename);
911 else
912 #endif
913 error = pwmd_open(pwm, filename);
915 if (error && local_pin && error == GPG_ERR_INV_PASSPHRASE)
916 goto local_password;
917 #endif
919 if (error)
920 goto done;
923 #ifdef WITH_TCP
924 read_command:
925 #endif
926 if (inquire) {
927 struct inquire_s inq;
928 struct stat st;
930 memset(&inq, 0, sizeof(inq));
931 inq.fd = fileno(inquirefp);
933 if (inq.fd == -1) {
934 error = gpg_error_from_syserror();
935 goto done;
938 if (fstat(inq.fd, &st) == -1) {
939 error = gpg_error_from_syserror();
940 goto done;
943 error = pwmd_setopt(pwm, PWMD_OPTION_INQUIRE_TOTAL,
944 st.st_size ? (size_t)st.st_size+strlen(p) : 0);
946 if (error)
947 goto done;
949 inq.line = pwmd_calloc(1, ASSUAN_LINELENGTH);
951 if (!inq.line) {
952 error = GPG_ERR_ENOMEM;
953 goto done;
956 inq.len = 0;
957 error = pwmd_inquire(pwm, inquire, inquire_cb, &inq);
958 pwmd_free(inq.line);
959 close(inq.fd);
960 goto done;
963 fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
964 ssize_t n;
966 for (;;) {
967 error = process_cmd(pwm, NULL, 1);
969 if (error)
970 goto done;
972 n = read(STDIN_FILENO, command, sizeof(command));
974 if (n == -1) {
975 if (errno == EAGAIN)
976 continue;
978 error = gpg_error_from_errno(errno);
979 goto done;
981 else if (!n)
982 goto done;
984 p = command;
985 command[n] = 0;
986 break;
989 if (!p || !*p)
990 goto done;
992 if (strcasecmp(p, "BYE") == 0)
993 goto done;
995 error = pwmd_command(pwm, &result, command);
996 memset(command, 0, sizeof(command));
998 if (error)
999 goto done;
1001 if (result) {
1002 fwrite(result, 1, strlen(result), outfp);
1003 pwmd_free(result);
1006 done:
1007 memset(command, 0, sizeof(command));
1009 if (password)
1010 pwmd_free(password);
1012 password = NULL;
1014 if (!error && save && filename) {
1015 if (iter != -2) {
1016 error = pwmd_setopt(pwm, PWMD_OPTION_ITERATIONS, iter);
1018 if (error)
1019 goto do_exit;
1022 if (cipher) {
1023 error = pwmd_setopt(pwm, PWMD_OPTION_CIPHER, cipher);
1025 if (error)
1026 goto do_exit;
1029 if (local_pin) {
1030 char *p1;
1031 again:
1032 if (!force_save) {
1033 error = pwmd_command(pwm, NULL, "ISCACHED %s", filename);
1035 if (error && error != GPG_ERR_NOT_FOUND &&
1036 error != GPG_ERR_ENOENT)
1037 goto do_exit;
1038 else if (!error)
1039 goto do_save;
1042 error = pwmd_getpin(pwm, filename, &p1, PWMD_PINENTRY_SAVE);
1044 if (error)
1045 goto do_exit;
1047 error = pwmd_getpin(pwm, filename, &password,
1048 PWMD_PINENTRY_SAVE_CONFIRM);
1050 if (error) {
1051 pwmd_free(p1);
1052 goto do_exit;
1055 if ((p1 || password) && ((!p1 && password) || (!password && p1) ||
1056 strcmp(p1, password))) {
1057 pwmd_free(p1);
1058 pwmd_free(password);
1059 password = NULL;
1060 goto again;
1063 if (p1)
1064 pwmd_free(p1);
1066 error = pwmd_setopt(pwm, PWMD_OPTION_PASSPHRASE, password);
1068 if (password)
1069 pwmd_free(password);
1071 if (error)
1072 goto do_exit;
1075 if (force_save) {
1076 error = pwmd_command(pwm, NULL, "CLEARCACHE %s", filename);
1078 if (error)
1079 goto do_exit;
1081 if (!local_pin) {
1082 error = pwmd_setopt(pwm, PWMD_OPTION_PASSPHRASE, NULL);
1084 if (error)
1085 goto do_exit;
1089 do_save:
1090 if (keyfile && !local_pin) {
1091 struct inquire_s inq;
1093 memset(&inq, 0, sizeof(inq));
1094 inq.fd = open(keyfile, O_RDONLY);
1096 if (inq.fd == -1) {
1097 error = gpg_error_from_syserror();
1098 goto do_exit;
1101 inq.line = pwmd_calloc(1, ASSUAN_LINELENGTH);
1103 if (!inq.line) {
1104 error = GPG_ERR_ENOMEM;
1105 goto do_exit;
1108 error = pwmd_save_inquire(pwm, inquire_cb, &inq);
1109 pwmd_free(inq.line);
1110 close(inq.fd);
1112 else {
1113 #ifdef DEBUG
1114 switch (method) {
1115 case 0:
1116 error = pwmd_save(pwm);
1117 break;
1118 case 1:
1119 error = pwmd_save2(pwm);
1120 break;
1121 case 2:
1122 error = pwmd_save_async(pwm);
1123 break;
1124 case 3:
1125 error = pwmd_save_async2(pwm);
1126 break;
1129 if (!error && method >= 2)
1130 error = process_cmd(pwm, NULL, 0);
1132 #else
1133 #ifdef WITH_TCP
1134 if (host)
1135 error = pwmd_save2(pwm);
1136 else
1137 #endif
1138 error = pwmd_save(pwm);
1139 #endif
1143 do_exit:
1144 if (error) {
1145 show_error(error);
1146 ret = EXIT_FAILURE;
1149 pwmd_close(pwm);
1151 if (socketpath)
1152 pwmd_free(socketpath);
1154 exit(ret);