pwmc: inquire now uses heap memory when reading data.
[libpwmd.git] / src / pwmc.c
blob6e90eac707d57282c934dd5092ceda99f3fff0cc
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
56 #define PWMD_LINEMAX ASSUAN_LINELENGTH
58 pwm_t *pwm;
60 static void show_error(gpg_error_t error)
62 fprintf(stderr, "ERR %i %s\n", gpg_err_code(error), pwmd_strerror(error));
65 static void usage(const char *pn, int status)
67 fprintf(status == EXIT_FAILURE ? stderr : stdout, N_(
68 "Read a PWMD protocol command from standard input.\n\n"
69 "Usage: pwmc [options] [file]\n"
70 #ifdef DEBUG
71 " --debug <N>\n"
72 " pinentry method (0=pwmd, 1=libpwmd, 2=pwmd async, "
73 "3=libpwmd async)\n"
74 #endif
75 "\n"
76 #ifdef WITH_TCP
77 " --host, -h <hostname>\n"
78 " connect to the specified hostname\n"
79 "\n"
80 " --port\n"
81 " alterate port (22)\n"
82 "\n"
83 " --user\n"
84 " SSH username (default is the invoking user)\n"
85 "\n"
86 " --identity, -i <filename>\n"
87 " SSH identity file\n"
88 "\n"
89 " --known-hosts, -k <filename>\n"
90 " known host's file (for server validation)\n"
91 "\n"
92 " --get-hostkey, -g\n"
93 " retrieve the remote SSH host key and exit\n"
94 "\n"
95 " --ipv4, -4\n"
96 " try connecting via IPv4 only\n"
97 "\n"
98 " --ipv6, -6\n"
99 " try connecting via IPv6 only\n"
100 "\n"
101 #endif
102 " --url <string>\n"
103 " a url string to parse\n"
104 "\n"
105 " --no-status\n"
106 " disable showing of status messages from the server\n"
107 "\n"
108 " --name, -n <string>\n"
109 " set the client name\n"
110 "\n"
111 " --socket <filename>\n"
112 " local socket to connect to (~/.pwmd/socket)\n"
113 "\n"
114 " --passphrase, -P <string>\n"
115 " passphrase to use (disables pinentry use)\n"
116 "\n"
117 " --timeout <seconds>\n"
118 " pinentry timeout\n"
119 "\n"
120 " --tries <N>\n"
121 " number of pinentry tries before failing (3)\n"
122 "\n"
123 " --pinentry <path>\n"
124 " the full path to the pinentry binary (server default)\n"
125 "\n"
126 " --ttyname, -y <path>\n"
127 " tty that pinentry will use\n"
128 "\n"
129 " --ttytype, -t <string>\n"
130 " pinentry terminal type (default is TERM)\n"
131 "\n"
132 " --display, -d\n"
133 " pinentry display (default is DISPLAY)\n"
134 "\n"
135 " --lc-ctype <string>\n"
136 " locale setting for pinentry\n"
137 "\n"
138 " --lc-messages <string>\n"
139 " locale setting for pinentry\n"
140 "\n"
142 " --local-pinentry\n"
143 " force using a local pinentry\n"
144 "\n"
145 " --output-fd <FD>\n"
146 " redirect command output to the specified file descriptor\n"
147 "\n"
148 " --inquire-fd <FD>\n"
149 " read inquire data from the specified file descriptor\n"
150 "\n"
151 " --cipher <string>\n"
152 " the cipher to use when saving\n"
153 "\n"
154 " --save, -S\n"
155 " send the SAVE command before exiting\n"
156 "\n"
157 " --force-save\n"
158 " like --save, but ask for a passphrase\n"
159 "\n"
160 " --iterations, -I <N>\n"
161 " encrypt with the specified number of iterations when saving\n"
162 "\n"
163 " --version\n"
164 " --help\n"));
165 fprintf(status == EXIT_FAILURE ? stderr : stdout, N_(
166 "\n"
167 "A url string (specified with --url) may be in the form of:\n"
168 " file://[path/to/socket]\n"
169 #ifdef WITH_TCP
170 " ssh[46]://[username@]hostname[:port],identity,known_hosts\n"
171 #endif
173 exit(status);
176 struct inquire_s {
177 FILE *fp;
178 char *data;
179 size_t len;
180 void *p;
183 static gpg_error_t do_inquire(void *data, const char *keyword, gpg_error_t rc,
184 char **result, size_t *result_len)
186 int c;
187 char *p;
188 size_t len = 0;
189 struct inquire_s *inq = (struct inquire_s *)data;
191 *result = NULL;
192 *result_len = 0;
194 if (inq->p) {
195 pwmd_free(inq->p);
196 inq->p = NULL;
199 if (rc)
200 return rc;
202 inq->p = pwmd_malloc(PWMD_LINEMAX);
204 if (!inq->p)
205 return GPG_ERR_ENOMEM;
207 p = inq->p;
209 if (inq->data) {
210 memcpy(inq->p, inq->data, inq->len);
211 pwmd_free(inq->data);
212 inq->data = NULL;
213 len = inq->len;
214 p = inq->p + len;
217 while (len < PWMD_LINEMAX && (c = fgetc(inq->fp)) != EOF) {
218 *p++ = c;
219 len++;
222 if (!len)
223 return GPG_ERR_EOF;
225 *result = inq->p;
226 *result_len = len;
227 return 0;
230 static int status_msg_cb(void *data, const char *line)
232 fprintf(stderr, "%s\n", line);
233 return 0;
236 static gpg_error_t process_cmd(pwm_t *pwm, char **result, int input)
238 gpg_error_t rc;
239 pwmd_async_t s;
241 do {
242 int i, n;
243 fd_set rfds;
244 int nfds = 5;
245 pwmd_fd_t pfds[nfds];
247 FD_ZERO(&rfds);
248 rc = pwmd_get_fds(pwm, pfds, &nfds);
250 if (rc)
251 return rc;
253 if (!nfds) {
254 s = pwmd_process(pwm, &rc, result);
255 break;
258 for (i = 0, n = 0; i < nfds; i++) {
259 FD_SET(pfds[i].fd, &rfds);
260 n = pfds[i].fd > n ? pfds[i].fd : n;
263 if (input)
264 FD_SET(STDIN_FILENO, &rfds);
266 nfds = select(n+1, &rfds, NULL, NULL, NULL);
268 if (nfds == -1) {
269 rc = gpg_error_from_errno(errno);
270 return rc;
273 if (input && FD_ISSET(STDIN_FILENO, &rfds))
274 return 0;
276 s = pwmd_process(pwm, &rc, result);
277 } while (s == ASYNC_PROCESS);
279 return rc;
282 static gpg_error_t knownhost_cb(void *data, const char *host, const char *key,
283 size_t len)
285 gpg_error_t rc;
286 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);
288 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TITLE, buf);
289 pwmd_free(buf);
291 if (rc)
292 return rc;
294 return pwmd_getpin(pwm, NULL, NULL, PWMD_PINENTRY_CONFIRM);
297 int main(int argc, char *argv[])
299 int opt;
300 char *password = NULL;
301 char *filename = NULL;
302 char *socketpath = NULL;
303 char command[PWMD_LINEMAX], *p;
304 int ret = EXIT_SUCCESS;
305 gpg_error_t error;
306 char *result = NULL;
307 int save = 0;
308 char *pinentry_path = NULL;
309 char *display = NULL, *tty = NULL, *ttytype = NULL, *lcctype = NULL,
310 *lcmessages = NULL;
311 int outfd = STDOUT_FILENO;
312 FILE *outfp = stdout;
313 int inquirefd = STDIN_FILENO;
314 FILE *inquirefp = stdin;
315 int show_status = 1;
316 char *clientname = "pwmc";
317 char *inquire = NULL;
318 long iter = -2;
319 int have_iter = 0;
320 int timeout = 0;
321 int local_pin = 0;
322 int force_save = 0;
323 char *cipher = NULL;
324 #ifdef WITH_TCP
325 char *host = NULL;
326 int port = DEFAULT_PORT;
327 char *username = NULL;
328 char *ident = NULL;
329 char *known_hosts = NULL;
330 int get = 0;
331 int prot = PWMD_IP_ANY;
332 #endif
333 int tries = 0;
334 int local_tries = 3;
335 int try = 0;
336 pwmd_socket_t s;
337 #ifdef DEBUG
338 int method = 0;
339 fd_set rfds;
340 #endif
341 char *url_string = NULL;
342 /* The order is important. */
343 enum {
344 #ifdef DEBUG
345 OPT_DEBUG,
346 #endif
347 #ifdef WITH_TCP
348 OPT_HOST, OPT_PORT, OPT_IDENTITY, OPT_KNOWN_HOSTS, OPT_USER,
349 OPT_GET_HOSTKEY, OPT_IPV4, OPT_IPV6,
350 #endif
351 OPT_URL, OPT_LOCAL, OPT_FORCE_SAVE, OPT_TTYNAME, OPT_TTYTYPE,
352 OPT_DISPLAY, OPT_LC_CTYPE, OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES,
353 OPT_PINENTRY, OPT_PASSPHRASE, OPT_SOCKET, OPT_SAVE, OPT_ITERATIONS,
354 OPT_OUTPUT_FD, OPT_INQUIRE_FD, OPT_NO_STATUS, OPT_NAME, OPT_VERSION,
355 OPT_HELP, OPT_CIPHER,
357 const struct option long_opts[] = {
358 #ifdef DEBUG
359 { "debug", 1, 0, 0 },
360 #endif
361 #ifdef WITH_TCP
362 { "host", 1, 0, 'h' },
363 { "port", 1, 0, 'p' },
364 { "identity", 1, 0, 'i' },
365 { "known-hosts", 1, 0, 'k' },
366 { "user", 1, 0, 'u' },
367 { "get-hostkey", 0, 0, 'g' },
368 { "ipv4", 0, 0, '4' },
369 { "ipv6", 0, 0, '6' },
370 #endif
371 { "url", 1, 0, 0 },
372 { "local-pinentry", 0, 0 },
373 { "force-save", 0, 0 },
374 { "ttyname", 1, 0, 'y' },
375 { "ttytype", 1, 0, 't' },
376 { "display", 1, 0, 'd' },
377 { "lc-ctype", 1, 0, 0 },
378 { "lc-messages", 1, 0, 0 },
379 { "timeout", 1, 0, 0 },
380 { "tries", 1, 0, 0 },
381 { "pinentry", 1, 0, 0 },
382 { "passphrase", 1, 0, 'P' },
383 { "socket", 1, 0, 0 },
384 { "save", 0, 0, 'S' },
385 { "iterations", 1, 0, 'I' },
386 { "output-fd", 1, 0, 0 },
387 { "inquire-fd", 1, 0, 0 },
388 { "no-status", 0, 0, 0 },
389 { "name", 1, 0, 'n' },
390 { "version", 0, 0, 0 },
391 { "help", 0, 0, 0 },
392 { "cipher", 1, 0, 0 },
393 { 0, 0, 0, 0}
395 #ifdef WITH_TCP
396 const char *optstring = "46h:p:i:k:u:gy:t:d:P:I:Sn:";
397 #else
398 const char *optstring = "y:t:d:P:I:Sn:";
399 #endif
400 int opt_index = 0;
402 #ifdef ENABLE_NLS
403 setlocale(LC_ALL, "");
404 bindtextdomain("libpwmd", LOCALEDIR);
405 #endif
407 while ((opt = getopt_long(argc, argv, optstring, long_opts, &opt_index)) != -1) {
408 switch (opt) {
409 /* Handle long options without a short option part. */
410 case 0:
411 switch (opt_index) {
412 #ifdef DEBUG
413 case OPT_DEBUG:
414 method = atoi(optarg);
416 if (method > 3)
417 method = 3;
418 break;
419 #endif
420 case OPT_URL:
421 url_string = optarg;
422 break;
423 case OPT_LOCAL:
424 local_pin = 1;
425 break;
426 case OPT_FORCE_SAVE:
427 save = force_save = 1;
428 break;
429 case OPT_LC_CTYPE:
430 lcctype = pwmd_strdup(optarg);
431 break;
432 case OPT_LC_MESSAGES:
433 lcmessages = pwmd_strdup(optarg);
434 break;
435 case OPT_TIMEOUT:
436 timeout = atoi(optarg);
437 break;
438 case OPT_TRIES:
439 tries = atoi(optarg);
440 local_tries = tries;
441 break;
442 case OPT_SOCKET:
443 socketpath = pwmd_strdup(optarg);
444 break;
445 case OPT_INQUIRE_FD:
446 inquirefd = atoi(optarg);
447 inquirefp = fdopen(inquirefd, "r");
449 if (!inquirefp) {
450 pwmd_free(password);
451 err(EXIT_FAILURE, "%i", inquirefd);
453 break;
454 case OPT_OUTPUT_FD:
455 outfd = atoi(optarg);
456 outfp = fdopen(outfd, "w");
458 if (!outfp) {
459 pwmd_free(password);
460 err(EXIT_FAILURE, "%i", outfd);
462 break;
463 case OPT_NO_STATUS:
464 show_status = 0;
465 break;
466 case OPT_VERSION:
467 pwmd_free(password);
468 printf("%s (pwmc)\n%s\n\n"
469 "Compile-time features:\n"
470 #ifdef WITH_TCP
471 "+SSH "
472 #else
473 "-SSH "
474 #endif
475 #ifdef WITH_PINENTRY
476 "+PINENTRY "
477 #else
478 "-PINENTRY "
479 #endif
480 #ifdef WITH_QUALITY
481 "+QUALITY "
482 #else
483 "-QUALITY "
484 #endif
485 #ifdef MEM_DEBUG
486 "+MEM_DEBUG "
487 #else
488 "-MEM_DEBUG "
489 #endif
490 "\n"
491 , PACKAGE_STRING, PACKAGE_BUGREPORT);
492 exit(EXIT_SUCCESS);
493 case OPT_PINENTRY:
494 pinentry_path = optarg;
495 break;
496 case OPT_HELP:
497 usage(argv[0], EXIT_SUCCESS);
498 case OPT_CIPHER:
499 cipher = optarg;
500 break;
501 default:
502 usage(argv[0], EXIT_FAILURE);
505 break;
506 #ifdef WITH_TCP
507 case '4':
508 prot = PWMD_IPV4;
509 break;
510 case '6':
511 prot = PWMD_IPV6;
512 break;
513 case 'h':
514 host = pwmd_strdup(optarg);
515 break;
516 case 'p':
517 port = atoi(optarg);
518 break;
519 case 'i':
520 ident = pwmd_strdup(optarg);
521 break;
522 case 'u':
523 username = pwmd_strdup(optarg);
524 break;
525 case 'k':
526 known_hosts = pwmd_strdup(optarg);
527 break;
528 case 'g':
529 get = 1;
530 break;
531 #endif
532 case 'y':
533 tty = optarg;
534 break;
535 case 't':
536 ttytype = optarg;
537 break;
538 case 'd':
539 display = optarg;
540 break;
541 case 'S':
542 save = 1;
543 break;
544 case 'I':
545 iter = strtol(optarg, NULL, 10);
546 have_iter = 1;
547 break;
548 case 'P':
549 password = pwmd_strdup(optarg);
550 memset(optarg, 0, strlen(optarg));
551 break;
552 case 'n':
553 clientname = optarg;
554 break;
555 default:
556 pwmd_free(password);
557 usage(argv[0], EXIT_FAILURE);
561 #ifdef DEBUG
562 if (!url_string) {
563 #endif
564 #ifdef WITH_TCP
565 if (host && !get && (!known_hosts || !ident)) {
566 pwmd_free(password);
567 usage(argv[0], EXIT_FAILURE);
570 if (get && !host) {
571 pwmd_free(password);
572 usage(argv[0], EXIT_FAILURE);
574 #endif
575 #ifdef DEBUG
577 #endif
579 filename = argv[optind];
580 pwmd_init();
581 pwm = pwmd_new(clientname);
582 #ifdef DEBUG
583 FD_ZERO(&rfds);
584 #endif
586 #ifdef WITH_TCP
587 if (host) {
588 if (prot != PWMD_IP_ANY) {
589 error = pwmd_setopt(pwm, PWMD_OPTION_IP_VERSION, prot);
591 if (error)
592 goto done;
595 error = pwmd_setopt(pwm, PWMD_OPTION_KNOWNHOST_CB, knownhost_cb);
597 if (error)
598 goto done;
600 error = pwmd_setopt(pwm, PWMD_OPTION_KNOWNHOST_DATA, clientname);
602 if (error)
603 goto done;
605 #ifdef DEBUG
606 if (method >= 2) {
607 if (get) {
608 char *hostkey;
610 error = pwmd_get_hostkey_async(pwm, host, port);
612 if (error)
613 errx(EXIT_FAILURE, "%s: %s", host, pwmd_strerror(error));
615 error = process_cmd(pwm, &hostkey, 0);
617 if (error)
618 goto done;
620 printf("%s", hostkey);
621 pwmd_free(hostkey);
622 pwmd_free(password);
623 pwmd_close(pwm);
624 exit(EXIT_SUCCESS);
627 if (url_string)
628 error = pwmd_connect_url_async(pwm, url_string);
629 else
630 error = pwmd_ssh_connect_async(pwm, host, port, ident, username,
631 known_hosts);
633 if (error)
634 goto done;
636 error = process_cmd(pwm, NULL, 0);
638 if (error)
639 goto done;
641 else {
642 #endif
643 if (get) {
644 char *hostkey;
646 error = pwmd_get_hostkey(pwm, host, port, &hostkey);
648 if (error)
649 goto done;
651 printf("%s", hostkey);
652 pwmd_free(hostkey);
653 pwmd_free(password);
654 pwmd_close(pwm);
655 exit(EXIT_SUCCESS);
658 if (url_string)
659 error = pwmd_connect_url(pwm, url_string);
660 else
661 error = pwmd_ssh_connect(pwm, host, port, ident, username, known_hosts);
663 if (error)
664 goto done;
665 #ifdef DEBUG
667 #endif
669 else {
670 #endif
671 if (url_string)
672 error = pwmd_connect_url(pwm, url_string);
673 else
674 error = pwmd_connect(pwm, socketpath);
676 if (error)
677 goto done;
678 #ifdef WITH_TCP
680 #endif
682 error = pwmd_socket_type(pwm, &s);
684 if (error)
685 goto done;
687 if (s == PWMD_SOCKET_SSH && force_save && !local_pin) {
688 error = GPG_ERR_WRONG_KEY_USAGE;
689 goto done;
692 if (have_iter) {
693 error = pwmd_command(pwm, &result, "VERSION");
695 if (error)
696 goto done;
698 pwmd_free(result);
700 if (iter < 0) {
701 pwmd_free(password);
702 pwmd_close(pwm);
703 usage(argv[0], EXIT_FAILURE);
707 if (timeout > 0) {
708 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
710 if (error)
711 goto done;
714 if (local_pin && filename) {
715 error = pwmd_command(pwm, NULL, "ISCACHED %s", filename);
717 if (error == GPG_ERR_NOT_FOUND) {
718 local_password:
719 if (try++ == local_tries)
720 goto done;
722 if (password)
723 pwmd_free(password);
725 password = NULL;
727 if (try > 1)
728 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, 0);
730 error = pwmd_getpin(pwm, filename, &password,
731 try > 1 ? PWMD_PINENTRY_OPEN_FAILED : PWMD_PINENTRY_OPEN);
733 if (error)
734 goto done;
736 error = pwmd_setopt(pwm, PWMD_OPTION_PASSPHRASE, password);
738 if (error)
739 goto done;
741 if (try > 1)
742 goto do_open;
744 else if (error && error != GPG_ERR_ENOENT)
745 goto done;
748 if (password) {
749 error = pwmd_setopt(pwm, PWMD_OPTION_PASSPHRASE, password);
751 if (error)
752 goto done;
754 else {
755 if (pinentry_path) {
756 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
758 if (error)
759 goto done;
762 if (display) {
763 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
765 if (error)
766 goto done;
769 if (tty) {
770 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TTY, tty);
772 if (error)
773 goto done;
776 if (ttytype) {
777 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
779 if (error)
780 goto done;
783 if (lcctype) {
784 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
786 if (error)
787 goto done;
790 if (lcmessages) {
791 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES,
792 lcmessages);
794 if (error)
795 goto done;
798 if (tries > 0) {
799 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
801 if (error)
802 goto done;
806 if (show_status) {
807 error = pwmd_setopt(pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
809 if (error)
810 goto done;
813 do_open:
814 if (filename) {
815 #ifdef DEBUG
816 switch (method) {
817 case 0:
818 error = pwmd_open(pwm, filename);
819 break;
820 case 1:
821 error = pwmd_open2(pwm, filename);
822 break;
823 case 2:
824 error = pwmd_open_async(pwm, filename);
826 break;
827 case 3:
828 error = pwmd_open_async2(pwm, filename);
829 break;
832 if (error && local_pin && error == GPG_ERR_INV_PASSPHRASE)
833 goto local_password;
835 if (error)
836 goto done;
838 if (method >= 2)
839 error = process_cmd(pwm, &result, 0);
840 #else
841 error = pwmd_open(pwm, filename);
843 if (error && local_pin && error == GPG_ERR_INV_PASSPHRASE)
844 goto local_password;
845 #endif
847 if (error)
848 goto done;
851 if (filename) {
852 error = pwmd_command(pwm, &result, "LOCK");
854 if (error)
855 goto done;
858 fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
859 ssize_t n;
861 for (;;) {
862 error = process_cmd(pwm, NULL, 1);
864 if (error)
865 goto done;
867 n = read(STDIN_FILENO, command, sizeof(command));
869 if (n == -1) {
870 if (errno == EAGAIN)
871 continue;
873 error = gpg_error_from_errno(errno);
874 goto done;
876 else if (!n)
877 goto done;
879 p = command;
880 break;
883 if (!p || !*p)
884 goto done;
887 * This is a known INQUIRE command. We use pwmd_inquire() to send the
888 * data from the do_inquire() callback function.
890 if (n > 6 && (!memcmp(p, "STORE ", 6) || !memcmp(p, "store ", 6))) {
891 p += 6;
892 n -= 6;
893 inquire = (char *)"STORE";
895 else if (n > 7 && (!memcmp(p, "IMPORT ", 7) || !memcmp(p, "import ", 7))) {
896 p += 7;
897 n -= 7;
898 inquire = (char *)"IMPORT";
901 if (inquire) {
902 struct inquire_s *inq = (struct inquire_s *)pwmd_malloc(sizeof(struct inquire_s));
903 struct stat st;
904 int fd;
906 if (!inq) {
907 error = gpg_error_from_errno(ENOMEM);
908 goto done;
911 fd = fileno(inquirefp);
913 if (fd == -1) {
914 error = gpg_error_from_errno(errno);
915 goto done;
918 if (fstat(fd, &st) == -1) {
919 error = gpg_error_from_errno(errno);
920 goto done;
923 error = pwmd_setopt(pwm, PWMD_OPTION_INQUIRE_TOTAL,
924 st.st_size ? (size_t)st.st_size+strlen(p) : 0);
926 if (error)
927 goto done;
929 inq->data = pwmd_malloc(n);
931 if (!inq->data) {
932 error = GPG_ERR_ENOMEM;
933 goto done;
936 memcpy(inq->data, p, n);
937 inq->len = n;
938 inq->fp = inquirefp;
939 inq->p = NULL;
940 error = pwmd_inquire(pwm, inquire, do_inquire, inq);
941 pwmd_free(inq);
942 goto done;
945 if (strcasecmp(p, "BYE") == 0)
946 goto done;
948 error = pwmd_command(pwm, &result, command);
949 memset(command, 0, sizeof(command));
951 if (error)
952 goto done;
954 if (result) {
955 fwrite(result, 1, strlen(result), outfp);
956 pwmd_free(result);
959 done:
960 memset(command, 0, sizeof(command));
961 pwmd_free(password);
962 password = NULL;
964 if (!error && save && filename) {
965 if (iter != -2) {
966 error = pwmd_command(pwm, &result, "SET ITERATIONS=%i", iter);
968 if (error)
969 goto done;
972 if (cipher) {
973 error = pwmd_command(pwm, NULL, "SET CIPHER=%s", cipher);
975 if (error)
976 goto done;
979 if (local_pin) {
980 char *p1;
981 again:
982 if (!force_save) {
983 error = pwmd_command(pwm, NULL, "ISCACHED %s", filename);
985 if (error && error != GPG_ERR_NOT_FOUND &&
986 error != GPG_ERR_ENOENT)
987 goto done;
988 else if (!error)
989 goto do_save;
992 error = pwmd_getpin(pwm, filename, &p1, PWMD_PINENTRY_SAVE);
994 if (error)
995 goto done;
997 error = pwmd_getpin(pwm, filename, &password,
998 PWMD_PINENTRY_SAVE_CONFIRM);
1000 if (error) {
1001 pwmd_free(p1);
1002 goto done;
1005 if ((p1 || password) && ((!p1 && password) || (!password && p1) ||
1006 strcmp(p1, password))) {
1007 pwmd_free(p1);
1008 pwmd_free(password);
1009 password = NULL;
1010 goto again;
1013 if (p1)
1014 pwmd_free(p1);
1016 error = pwmd_setopt(pwm, PWMD_OPTION_PASSPHRASE, password);
1018 if (password)
1019 pwmd_free(password);
1021 if (error)
1022 goto done;
1025 if (force_save) {
1026 error = pwmd_command(pwm, NULL, "CLEARCACHE %s", filename);
1028 if (error)
1029 goto done;
1031 if (!local_pin) {
1032 error = pwmd_setopt(pwm, PWMD_OPTION_PASSPHRASE, NULL);
1034 if (error)
1035 goto done;
1039 do_save:
1040 #ifdef DEBUG
1041 switch (method) {
1042 case 0:
1043 error = pwmd_save(pwm);
1044 break;
1045 case 1:
1046 error = pwmd_save2(pwm);
1047 break;
1048 case 2:
1049 error = pwmd_save_async(pwm);
1050 break;
1051 case 3:
1052 error = pwmd_save_async2(pwm);
1053 break;
1056 if (!error && method >= 2)
1057 error = process_cmd(pwm, NULL, 0);
1059 #else
1060 error = pwmd_save(pwm);
1061 #endif
1064 if (!error && filename)
1065 error = pwmd_command(pwm, &result, "UNLOCK");
1067 if (error) {
1068 show_error(error);
1069 ret = EXIT_FAILURE;
1072 pwmd_close(pwm);
1074 if (socketpath)
1075 pwmd_free(socketpath);
1077 exit(ret);