pwmc: Minor --help text fix.
[libpwmd.git] / src / pwmc.c
blob700874475992893139723af12d0302100af64ede
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 pwm_t *pwm;
58 static void show_error(gpg_error_t error)
60 fprintf(stderr, "ERR %i %s\n", gpg_err_code(error), pwmd_strerror(error));
63 static void usage(const char *pn, int status)
65 fprintf(status == EXIT_FAILURE ? stderr : stdout, N_(
66 "Read a PWMD protocol command from standard input.\n\n"
67 "Usage: pwmc [options] [file]\n"
68 #ifdef DEBUG
69 " --debug <N>\n"
70 " pinentry method (0=pwmd, 1=libpwmd, 2=pwmd async, "
71 "3=libpwmd async)\n"
72 #endif
73 "\n"
74 #ifdef WITH_TCP
75 " --host, -h <hostname>\n"
76 " connect to the specified hostname\n"
77 "\n"
78 " --port\n"
79 " alterate port (22)\n"
80 "\n"
81 " --user\n"
82 " SSH username (default is the invoking user)\n"
83 "\n"
84 " --identity, -i <filename>\n"
85 " SSH identity file\n"
86 "\n"
87 " --known-hosts, -k <filename>\n"
88 " known host's file (for server validation)\n"
89 "\n"
90 " --get-hostkey, -g\n"
91 " retrieve the remote SSH host key and exit\n"
92 "\n"
93 " --ipv4, -4\n"
94 " try connecting via IPv4 only\n"
95 "\n"
96 " --ipv6, -6\n"
97 " try connecting via IPv6 only\n"
98 "\n"
99 #endif
100 " --url <string>\n"
101 " a url string to parse\n"
102 "\n"
103 " --no-status\n"
104 " disable showing of status messages from the server\n"
105 "\n"
106 " --name, -n <string>\n"
107 " set the client name\n"
108 "\n"
109 " --socket <filename>\n"
110 " local socket to connect to (~/.pwmd/socket)\n"
111 "\n"
112 " --passphrase, -P <string>\n"
113 " passphrase to use (disables pinentry use)\n"
114 "\n"
115 " --timeout <seconds>\n"
116 " pinentry timeout\n"
117 "\n"
118 " --tries <N>\n"
119 " number of pinentry tries before failing (3)\n"
120 "\n"
121 " --pinentry <path>\n"
122 " the full path to the pinentry binary (server default)\n"
123 "\n"
124 " --ttyname, -y <path>\n"
125 " tty that pinentry will use\n"
126 "\n"
127 " --ttytype, -t <string>\n"
128 " pinentry terminal type (default is TERM)\n"
129 "\n"
130 " --display, -d\n"
131 " pinentry display (default is DISPLAY)\n"
132 "\n"
133 " --lc-ctype <string>\n"
134 " locale setting for pinentry\n"
135 "\n"
136 " --lc-messages <string>\n"
137 " locale setting for pinentry\n"
138 "\n"
140 " --local-pinentry\n"
141 " force using a local pinentry\n"
142 "\n"
143 " --output-fd <FD>\n"
144 " redirect command output to the specified file descriptor\n"
145 "\n"
146 " --inquire-fd <FD>\n"
147 " read inquire data from the specified file descriptor\n"
148 "\n"
149 " --cipher <string>\n"
150 " the cipher to use when saving\n"
151 "\n"
152 " --save, -S\n"
153 " send the SAVE command before exiting\n"
154 "\n"
155 " --force-save\n"
156 " like --save, but ask for a passphrase\n"
157 "\n"
158 " --iterations, -I <N>\n"
159 " encrypt with the specified number of iterations when saving\n"
160 "\n"
161 " --version\n"
162 " --help\n"));
163 fprintf(status == EXIT_FAILURE ? stderr : stdout, N_(
164 "\n"
165 "A url string (specified with --url) may be in the form of:\n"
166 " file://[path/to/socket]\n"
167 #ifdef WITH_TCP
168 " ssh[46]://[username@]hostname[:port],identity,known_hosts\n"
169 #endif
171 exit(status);
174 struct inquire_s {
175 FILE *fp;
176 char *data;
179 static gpg_error_t do_inquire(void *data, const char *keyword, gpg_error_t rc,
180 char **result, size_t *result_len)
182 int c;
183 static char buf[ASSUAN_LINELENGTH];
184 char *p;
185 size_t len = 0;
186 struct inquire_s *inq = (struct inquire_s *)data;
188 if (rc) {
189 memset(buf, 0, sizeof(buf));
190 return rc;
193 buf[0] = 0;
194 p = buf;
196 if (inq->data) {
197 snprintf(buf, sizeof(buf), "%s", inq->data);
198 pwmd_free(inq->data);
199 inq->data = NULL;
200 len = strlen(buf);
201 p = buf + len;
204 while ((c = fgetc(inq->fp)) != EOF) {
205 if (len == sizeof(buf)) {
206 ungetc(c, inq->fp);
207 break;
210 *p++ = c;
211 len++;
214 if (!buf[0]) {
215 memset(buf, 0, sizeof(buf));
216 return GPG_ERR_EOF;
219 *result = buf;
220 *result_len = len;
221 return 0;
224 static int status_msg_cb(void *data, const char *line)
226 fprintf(stderr, "%s\n", line);
227 return 0;
230 static gpg_error_t process_cmd(pwm_t *pwm, char **result, int input)
232 gpg_error_t rc;
233 pwmd_async_t s;
235 do {
236 int i, n;
237 fd_set rfds;
238 int nfds = 5;
239 pwmd_fd_t pfds[nfds];
241 FD_ZERO(&rfds);
242 rc = pwmd_get_fds(pwm, pfds, &nfds);
244 if (rc)
245 return rc;
247 if (!nfds) {
248 s = pwmd_process(pwm, &rc, result);
249 break;
252 for (i = 0, n = 0; i < nfds; i++) {
253 FD_SET(pfds[i].fd, &rfds);
254 n = pfds[i].fd > n ? pfds[i].fd : n;
257 if (input)
258 FD_SET(STDIN_FILENO, &rfds);
260 nfds = select(n+1, &rfds, NULL, NULL, NULL);
262 if (nfds == -1) {
263 rc = gpg_error_from_errno(errno);
264 return rc;
267 if (input && FD_ISSET(STDIN_FILENO, &rfds))
268 return 0;
270 s = pwmd_process(pwm, &rc, result);
271 } while (s == ASYNC_PROCESS);
273 return rc;
276 static gpg_error_t knownhost_cb(void *data, const char *host, const char *key,
277 size_t len)
279 gpg_error_t rc;
280 char *buf = pwmd_strdup_printf(N_("Password Manager Daemon: %s\n\nWhile attepting an SSH connection to %s, there was a problem verifying it's hostkey against the known and trusted hosts file. Would you like to treat this connection as trusted for this and future connections?"), (char *)data, host);
282 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TITLE, buf);
283 pwmd_free(buf);
285 if (rc)
286 return rc;
288 return pwmd_getpin(pwm, NULL, NULL, PWMD_PINENTRY_CONFIRM);
291 int main(int argc, char *argv[])
293 int opt;
294 char *password = NULL;
295 char *filename = NULL;
296 char *socketpath = NULL;
297 char command[ASSUAN_LINELENGTH], *p;
298 int ret = EXIT_SUCCESS;
299 gpg_error_t error;
300 char *result = NULL;
301 int save = 0;
302 char *pinentry_path = NULL;
303 char *display = NULL, *tty = NULL, *ttytype = NULL, *lcctype = NULL,
304 *lcmessages = NULL;
305 int outfd = STDOUT_FILENO;
306 FILE *outfp = stdout;
307 int inquirefd = STDIN_FILENO;
308 FILE *inquirefp = stdin;
309 int show_status = 1;
310 char *clientname = "pwmc";
311 char *inquire = NULL;
312 long iter = -2;
313 int have_iter = 0;
314 int timeout = 0;
315 int local_pin = 0;
316 int force_save = 0;
317 char *cipher = NULL;
318 #ifdef WITH_TCP
319 char *host = NULL;
320 int port = DEFAULT_PORT;
321 char *username = NULL;
322 char *ident = NULL;
323 char *known_hosts = NULL;
324 int get = 0;
325 int prot = PWMD_IP_ANY;
326 #endif
327 int tries = 0;
328 int local_tries = 3;
329 int try = 0;
330 pwmd_socket_t s;
331 #ifdef DEBUG
332 int method = 0;
333 fd_set rfds;
334 #endif
335 char *url_string = NULL;
336 /* The order is important. */
337 enum {
338 #ifdef DEBUG
339 OPT_DEBUG,
340 #endif
341 #ifdef WITH_TCP
342 OPT_HOST, OPT_PORT, OPT_IDENTITY, OPT_KNOWN_HOSTS, OPT_USER,
343 OPT_GET_HOSTKEY, OPT_IPV4, OPT_IPV6,
344 #endif
345 OPT_URL, OPT_LOCAL, OPT_FORCE_SAVE, OPT_TTYNAME, OPT_TTYTYPE,
346 OPT_DISPLAY, OPT_LC_CTYPE, OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES,
347 OPT_PINENTRY, OPT_PASSPHRASE, OPT_SOCKET, OPT_SAVE, OPT_ITERATIONS,
348 OPT_OUTPUT_FD, OPT_INQUIRE_FD, OPT_NO_STATUS, OPT_NAME, OPT_VERSION,
349 OPT_HELP, OPT_CIPHER,
351 const struct option long_opts[] = {
352 #ifdef DEBUG
353 { "debug", 1, 0, 0 },
354 #endif
355 #ifdef WITH_TCP
356 { "host", 1, 0, 'h' },
357 { "port", 1, 0, 'p' },
358 { "identity", 1, 0, 'i' },
359 { "known-hosts", 1, 0, 'k' },
360 { "user", 1, 0, 'u' },
361 { "get-hostkey", 0, 0, 'g' },
362 { "ipv4", 0, 0, '4' },
363 { "ipv6", 0, 0, '6' },
364 #endif
365 { "url", 1, 0, 0 },
366 { "local-pinentry", 0, 0 },
367 { "force-save", 0, 0 },
368 { "ttyname", 1, 0, 'y' },
369 { "ttytype", 1, 0, 't' },
370 { "display", 1, 0, 'd' },
371 { "lc-ctype", 1, 0, 0 },
372 { "lc-messages", 1, 0, 0 },
373 { "timeout", 1, 0, 0 },
374 { "tries", 1, 0, 0 },
375 { "pinentry", 1, 0, 0 },
376 { "passphrase", 1, 0, 'P' },
377 { "socket", 1, 0, 0 },
378 { "save", 0, 0, 'S' },
379 { "iterations", 1, 0, 'I' },
380 { "output-fd", 1, 0, 0 },
381 { "inquire-fd", 1, 0, 0 },
382 { "no-status", 0, 0, 0 },
383 { "name", 1, 0, 'n' },
384 { "version", 0, 0, 0 },
385 { "help", 0, 0, 0 },
386 { "cipher", 1, 0, 0 },
387 { 0, 0, 0, 0}
389 #ifdef WITH_TCP
390 const char *optstring = "46h:p:i:k:u:gy:t:d:P:I:Sn:";
391 #else
392 const char *optstring = "y:t:d:P:I:Sn:";
393 #endif
394 int opt_index = 0;
396 #ifdef ENABLE_NLS
397 setlocale(LC_ALL, "");
398 bindtextdomain("libpwmd", LOCALEDIR);
399 #endif
401 while ((opt = getopt_long(argc, argv, optstring, long_opts, &opt_index)) != -1) {
402 switch (opt) {
403 /* Handle long options without a short option part. */
404 case 0:
405 switch (opt_index) {
406 #ifdef DEBUG
407 case OPT_DEBUG:
408 method = atoi(optarg);
410 if (method > 3)
411 method = 3;
412 break;
413 #endif
414 case OPT_URL:
415 url_string = optarg;
416 break;
417 case OPT_LOCAL:
418 local_pin = 1;
419 break;
420 case OPT_FORCE_SAVE:
421 save = force_save = 1;
422 break;
423 case OPT_LC_CTYPE:
424 lcctype = pwmd_strdup(optarg);
425 break;
426 case OPT_LC_MESSAGES:
427 lcmessages = pwmd_strdup(optarg);
428 break;
429 case OPT_TIMEOUT:
430 timeout = atoi(optarg);
431 break;
432 case OPT_TRIES:
433 tries = atoi(optarg);
434 local_tries = tries;
435 break;
436 case OPT_SOCKET:
437 socketpath = pwmd_strdup(optarg);
438 break;
439 case OPT_INQUIRE_FD:
440 inquirefd = atoi(optarg);
441 inquirefp = fdopen(inquirefd, "r");
443 if (!inquirefp) {
444 pwmd_free(password);
445 err(EXIT_FAILURE, "%i", inquirefd);
447 break;
448 case OPT_OUTPUT_FD:
449 outfd = atoi(optarg);
450 outfp = fdopen(outfd, "w");
452 if (!outfp) {
453 pwmd_free(password);
454 err(EXIT_FAILURE, "%i", outfd);
456 break;
457 case OPT_NO_STATUS:
458 show_status = 0;
459 break;
460 case OPT_VERSION:
461 pwmd_free(password);
462 printf("%s (pwmc)\n%s\n\n"
463 "Compile-time features:\n"
464 #ifdef WITH_TCP
465 "+SSH "
466 #else
467 "-SSH "
468 #endif
469 #ifdef WITH_PINENTRY
470 "+PINENTRY "
471 #else
472 "-PINENTRY "
473 #endif
474 #ifdef WITH_QUALITY
475 "+QUALITY "
476 #else
477 "-QUALITY "
478 #endif
479 #ifdef MEM_DEBUG
480 "+MEM_DEBUG "
481 #else
482 "-MEM_DEBUG "
483 #endif
484 "\n"
485 , PACKAGE_STRING, PACKAGE_BUGREPORT);
486 exit(EXIT_SUCCESS);
487 case OPT_PINENTRY:
488 pinentry_path = optarg;
489 break;
490 case OPT_HELP:
491 usage(argv[0], EXIT_SUCCESS);
492 case OPT_CIPHER:
493 cipher = optarg;
494 break;
495 default:
496 usage(argv[0], EXIT_FAILURE);
499 break;
500 #ifdef WITH_TCP
501 case '4':
502 prot = PWMD_IPV4;
503 break;
504 case '6':
505 prot = PWMD_IPV6;
506 break;
507 case 'h':
508 host = pwmd_strdup(optarg);
509 break;
510 case 'p':
511 port = atoi(optarg);
512 break;
513 case 'i':
514 ident = pwmd_strdup(optarg);
515 break;
516 case 'u':
517 username = pwmd_strdup(optarg);
518 break;
519 case 'k':
520 known_hosts = pwmd_strdup(optarg);
521 break;
522 case 'g':
523 get = 1;
524 break;
525 #endif
526 case 'y':
527 tty = optarg;
528 break;
529 case 't':
530 ttytype = optarg;
531 break;
532 case 'd':
533 display = optarg;
534 break;
535 case 'S':
536 save = 1;
537 break;
538 case 'I':
539 iter = strtol(optarg, NULL, 10);
540 have_iter = 1;
541 break;
542 case 'P':
543 password = pwmd_strdup(optarg);
544 memset(optarg, 0, strlen(optarg));
545 break;
546 case 'n':
547 clientname = optarg;
548 break;
549 default:
550 pwmd_free(password);
551 usage(argv[0], EXIT_FAILURE);
555 #ifdef DEBUG
556 if (!url_string) {
557 #endif
558 #ifdef WITH_TCP
559 if (host && !get && (!known_hosts || !ident)) {
560 pwmd_free(password);
561 usage(argv[0], EXIT_FAILURE);
564 if (get && !host) {
565 pwmd_free(password);
566 usage(argv[0], EXIT_FAILURE);
568 #endif
569 #ifdef DEBUG
571 #endif
573 filename = argv[optind];
574 pwmd_init();
575 pwm = pwmd_new(clientname);
576 #ifdef DEBUG
577 FD_ZERO(&rfds);
578 #endif
580 #ifdef WITH_TCP
581 if (host) {
582 if (prot != PWMD_IP_ANY) {
583 error = pwmd_setopt(pwm, PWMD_OPTION_IP_VERSION, prot);
585 if (error)
586 goto done;
589 error = pwmd_setopt(pwm, PWMD_OPTION_KNOWNHOST_CB, knownhost_cb);
591 if (error)
592 goto done;
594 error = pwmd_setopt(pwm, PWMD_OPTION_KNOWNHOST_DATA, clientname);
596 if (error)
597 goto done;
599 #ifdef DEBUG
600 if (method >= 2) {
601 if (get) {
602 char *hostkey;
604 error = pwmd_get_hostkey_async(pwm, host, port);
606 if (error)
607 errx(EXIT_FAILURE, "%s: %s", host, pwmd_strerror(error));
609 error = process_cmd(pwm, &hostkey, 0);
611 if (error)
612 goto done;
614 printf("%s", hostkey);
615 pwmd_free(hostkey);
616 pwmd_free(password);
617 pwmd_close(pwm);
618 exit(EXIT_SUCCESS);
621 if (url_string)
622 error = pwmd_connect_url_async(pwm, url_string);
623 else
624 error = pwmd_ssh_connect_async(pwm, host, port, ident, username,
625 known_hosts);
627 if (error)
628 goto done;
630 error = process_cmd(pwm, NULL, 0);
632 if (error)
633 goto done;
635 else {
636 #endif
637 if (get) {
638 char *hostkey;
640 error = pwmd_get_hostkey(pwm, host, port, &hostkey);
642 if (error)
643 goto done;
645 printf("%s", hostkey);
646 pwmd_free(hostkey);
647 pwmd_free(password);
648 pwmd_close(pwm);
649 exit(EXIT_SUCCESS);
652 if (url_string)
653 error = pwmd_connect_url(pwm, url_string);
654 else
655 error = pwmd_ssh_connect(pwm, host, port, ident, username, known_hosts);
657 if (error)
658 goto done;
659 #ifdef DEBUG
661 #endif
663 else {
664 #endif
665 if (url_string)
666 error = pwmd_connect_url(pwm, url_string);
667 else
668 error = pwmd_connect(pwm, socketpath);
670 if (error)
671 goto done;
672 #ifdef WITH_TCP
674 #endif
676 error = pwmd_socket_type(pwm, &s);
678 if (error)
679 goto done;
681 if (s == PWMD_SOCKET_SSH && force_save && !local_pin) {
682 error = GPG_ERR_WRONG_KEY_USAGE;
683 goto done;
686 if (have_iter) {
687 error = pwmd_command(pwm, &result, "VERSION");
689 if (error)
690 goto done;
692 pwmd_free(result);
694 if (iter < 0) {
695 pwmd_free(password);
696 pwmd_close(pwm);
697 usage(argv[0], EXIT_FAILURE);
701 if (timeout > 0) {
702 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
704 if (error)
705 goto done;
708 if (local_pin && filename) {
709 error = pwmd_command(pwm, NULL, "ISCACHED %s", filename);
711 if (error == GPG_ERR_NOT_FOUND) {
712 local_password:
713 if (try++ == local_tries)
714 goto done;
716 if (password)
717 pwmd_free(password);
719 password = NULL;
721 if (try > 1)
722 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, 0);
724 error = pwmd_getpin(pwm, filename, &password,
725 try > 1 ? PWMD_PINENTRY_OPEN_FAILED : PWMD_PINENTRY_OPEN);
727 if (error)
728 goto done;
730 error = pwmd_setopt(pwm, PWMD_OPTION_PASSPHRASE, password);
732 if (error)
733 goto done;
735 if (try > 1)
736 goto do_open;
738 else if (error && error != GPG_ERR_ENOENT)
739 goto done;
742 if (password) {
743 error = pwmd_setopt(pwm, PWMD_OPTION_PASSPHRASE, password);
745 if (error)
746 goto done;
748 else {
749 if (pinentry_path) {
750 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
752 if (error)
753 goto done;
756 if (display) {
757 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
759 if (error)
760 goto done;
763 if (tty) {
764 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TTY, tty);
766 if (error)
767 goto done;
770 if (ttytype) {
771 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
773 if (error)
774 goto done;
777 if (lcctype) {
778 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
780 if (error)
781 goto done;
784 if (lcmessages) {
785 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES,
786 lcmessages);
788 if (error)
789 goto done;
792 if (tries > 0) {
793 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
795 if (error)
796 goto done;
800 if (show_status) {
801 error = pwmd_setopt(pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
803 if (error)
804 goto done;
807 do_open:
808 if (filename) {
809 #ifdef DEBUG
810 switch (method) {
811 case 0:
812 error = pwmd_open(pwm, filename);
813 break;
814 case 1:
815 error = pwmd_open2(pwm, filename);
816 break;
817 case 2:
818 error = pwmd_open_async(pwm, filename);
820 break;
821 case 3:
822 error = pwmd_open_async2(pwm, filename);
823 break;
826 if (error && local_pin && error == GPG_ERR_INV_PASSPHRASE)
827 goto local_password;
829 if (error)
830 goto done;
832 if (method >= 2)
833 error = process_cmd(pwm, &result, 0);
834 #else
835 error = pwmd_open(pwm, filename);
837 if (error && local_pin && error == GPG_ERR_INV_PASSPHRASE)
838 goto local_password;
839 #endif
841 if (error)
842 goto done;
845 if (filename) {
846 error = pwmd_command(pwm, &result, "LOCK");
848 if (error)
849 goto done;
852 fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
854 for (;;) {
855 ssize_t n;
857 error = process_cmd(pwm, NULL, 1);
859 if (error)
860 goto done;
862 n = read(STDIN_FILENO, command, sizeof(command));
864 if (n == -1) {
865 if (errno == EAGAIN)
866 continue;
868 error = gpg_error_from_errno(errno);
869 goto done;
871 else if (!n)
872 goto done;
874 command[n] = 0;
876 if (n && command[strlen(command)-1] == '\n')
877 command[strlen(command)-1] = 0;
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 (strncasecmp(p, "STORE ", 6) == 0) {
891 p += 6;
892 inquire = (char *)"STORE";
894 else if (strncasecmp(p, "IMPORT ", 7) == 0) {
895 p += 7;
896 inquire = (char *)"IMPORT";
899 if (inquire) {
900 struct inquire_s *inq = (struct inquire_s *)pwmd_malloc(sizeof(struct inquire_s));
901 struct stat st;
902 int fd;
904 if (!inq) {
905 error = gpg_error_from_errno(ENOMEM);
906 goto done;
909 fd = fileno(inquirefp);
911 if (fd == -1) {
912 error = gpg_error_from_errno(errno);
913 goto done;
916 if (fstat(fd, &st) == -1) {
917 error = gpg_error_from_errno(errno);
918 goto done;
921 error = pwmd_setopt(pwm, PWMD_OPTION_INQUIRE_TOTAL,
922 st.st_size ? (size_t)st.st_size+strlen(p) : 0);
924 if (error)
925 goto done;
927 inq->data = pwmd_strdup(p);
928 inq->fp = inquirefp;
929 error = pwmd_inquire(pwm, inquire, do_inquire, inq);
930 pwmd_free(inq);
931 goto done;
934 if (strcasecmp(p, "BYE") == 0)
935 goto done;
937 error = pwmd_command(pwm, &result, command);
938 memset(command, 0, sizeof(command));
940 if (error)
941 goto done;
943 if (result) {
944 fwrite(result, 1, strlen(result), outfp);
945 pwmd_free(result);
948 done:
949 memset(command, 0, sizeof(command));
950 pwmd_free(password);
951 password = NULL;
953 if (!error && save && filename) {
954 if (iter != -2) {
955 error = pwmd_command(pwm, &result, "SET ITERATIONS=%i", iter);
957 if (error)
958 goto done;
961 if (cipher) {
962 error = pwmd_command(pwm, NULL, "SET CIPHER=%s", cipher);
964 if (error)
965 goto done;
968 if (local_pin) {
969 char *p1;
970 again:
971 if (!force_save) {
972 error = pwmd_command(pwm, NULL, "ISCACHED %s", filename);
974 if (error && error != GPG_ERR_NOT_FOUND &&
975 error != GPG_ERR_ENOENT)
976 goto done;
977 else if (!error)
978 goto do_save;
981 error = pwmd_getpin(pwm, filename, &p1, PWMD_PINENTRY_SAVE);
983 if (error)
984 goto done;
986 error = pwmd_getpin(pwm, filename, &password,
987 PWMD_PINENTRY_SAVE_CONFIRM);
989 if (error) {
990 pwmd_free(p1);
991 goto done;
994 if ((p1 || password) && ((!p1 && password) || (!password && p1) ||
995 strcmp(p1, password))) {
996 pwmd_free(p1);
997 pwmd_free(password);
998 password = NULL;
999 goto again;
1002 if (p1)
1003 pwmd_free(p1);
1005 error = pwmd_setopt(pwm, PWMD_OPTION_PASSPHRASE, password);
1007 if (password)
1008 pwmd_free(password);
1010 if (error)
1011 goto done;
1014 if (force_save) {
1015 error = pwmd_command(pwm, NULL, "CLEARCACHE %s", filename);
1017 if (error)
1018 goto done;
1020 if (!local_pin) {
1021 error = pwmd_setopt(pwm, PWMD_OPTION_PASSPHRASE, NULL);
1023 if (error)
1024 goto done;
1028 do_save:
1029 #ifdef DEBUG
1030 switch (method) {
1031 case 0:
1032 error = pwmd_save(pwm);
1033 break;
1034 case 1:
1035 error = pwmd_save2(pwm);
1036 break;
1037 case 2:
1038 error = pwmd_save_async(pwm);
1039 break;
1040 case 3:
1041 error = pwmd_save_async2(pwm);
1042 break;
1045 if (!error && method >= 2)
1046 error = process_cmd(pwm, NULL, 0);
1048 #else
1049 error = pwmd_save(pwm);
1050 #endif
1053 if (!error && filename)
1054 error = pwmd_command(pwm, &result, "UNLOCK");
1056 if (error) {
1057 show_error(error);
1058 ret = EXIT_FAILURE;
1061 pwmd_close(pwm);
1063 if (socketpath)
1064 pwmd_free(socketpath);
1066 exit(ret);