pwmc: fixed --key-file over an SSH connection.
[libpwmd.git] / src / pwmc.c
blob9a6b4abf6febaeaed56cc4f34474f3734c7909ee
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"
80 " alterate port (22)\n"
81 "\n"
82 " --user\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-fd <FD>\n"
154 " read inquire data from the specified file descriptor\n"
155 "\n"
156 " --cipher <string>\n"
157 " the cipher to use when saving\n"
158 "\n"
159 " --save, -S\n"
160 " send the SAVE command before exiting\n"
161 "\n"
162 " --force-save\n"
163 " like --save, but ask for a passphrase\n"
164 "\n"
165 " --iterations, -I <N>\n"
166 " encrypt with the specified number of iterations when saving\n"
167 "\n"
168 " --version\n"
169 " --help\n"));
170 fprintf(status == EXIT_FAILURE ? stderr : stdout, N_(
171 "\n"
172 "A url string (specified with --url) may be in the form of:\n"
173 " file://[path/to/socket]\n"
174 #ifdef WITH_TCP
175 " ssh[46]://[username@]hostname[:port],identity,known_hosts\n"
176 #endif
178 exit(status);
181 struct inquire_s {
182 int fd;
183 char *line;
184 size_t len;
187 static gpg_error_t inquire_cb(void *user, const char *cmd, gpg_error_t rc,
188 char **data, size_t *len)
190 struct inquire_s *inq = user;
192 *data = NULL;
193 *len = 0;
195 if (rc)
196 return rc;
198 /* The first part of the command data. */
199 if (inq->len) {
200 *data = inq->line;
201 *len = inq->len;
202 inq->len = 0;
203 return 0;
206 *len = read(inq->fd, inq->line, ASSUAN_LINELENGTH);
208 if (*len == -1)
209 return gpg_error_from_syserror();
211 if (*len)
212 *data = inq->line;
214 return *len ? 0 : GPG_ERR_EOF;
217 static int status_msg_cb(void *data, const char *line)
219 fprintf(stderr, "%s\n", line);
220 return 0;
223 static gpg_error_t process_cmd(pwm_t *pwm, char **result, int input)
225 gpg_error_t rc;
226 pwmd_async_t s;
228 do {
229 int i, n;
230 fd_set rfds;
231 int nfds = 5;
232 pwmd_fd_t pfds[nfds];
234 FD_ZERO(&rfds);
235 rc = pwmd_get_fds(pwm, pfds, &nfds);
237 if (rc)
238 return rc;
240 if (!nfds) {
241 s = pwmd_process(pwm, &rc, result);
242 break;
245 for (i = 0, n = 0; i < nfds; i++) {
246 FD_SET(pfds[i].fd, &rfds);
247 n = pfds[i].fd > n ? pfds[i].fd : n;
250 if (input)
251 FD_SET(STDIN_FILENO, &rfds);
253 nfds = select(n+1, &rfds, NULL, NULL, NULL);
255 if (nfds == -1) {
256 rc = gpg_error_from_errno(errno);
257 return rc;
260 if (input && FD_ISSET(STDIN_FILENO, &rfds))
261 return 0;
263 s = pwmd_process(pwm, &rc, result);
264 } while (s == ASYNC_PROCESS);
266 return rc;
269 static gpg_error_t knownhost_cb(void *data, const char *host, const char *key,
270 size_t len)
272 gpg_error_t rc;
273 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);
275 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TITLE, buf);
276 pwmd_free(buf);
278 if (rc)
279 return rc;
281 return pwmd_getpin(pwm, NULL, NULL, PWMD_PINENTRY_CONFIRM);
284 int main(int argc, char *argv[])
286 int opt;
287 char *password = NULL;
288 char *keyfile = NULL;
289 int base64 = 0;
290 char *filename = NULL;
291 char *socketpath = NULL;
292 char command[ASSUAN_LINELENGTH], *p;
293 int ret = EXIT_SUCCESS;
294 gpg_error_t error;
295 char *result = NULL;
296 int save = 0;
297 char *pinentry_path = NULL;
298 char *display = NULL, *tty = NULL, *ttytype = NULL, *lcctype = NULL,
299 *lcmessages = NULL;
300 int outfd = STDOUT_FILENO;
301 FILE *outfp = stdout;
302 int inquirefd = STDIN_FILENO;
303 FILE *inquirefp = stdin;
304 int show_status = 1;
305 char *clientname = "pwmc";
306 char *inquire = NULL;
307 long iter = -2;
308 int have_iter = 0;
309 int timeout = 0;
310 int local_pin = 0;
311 int force_save = 0;
312 char *cipher = NULL;
313 #ifdef WITH_TCP
314 char *host = NULL;
315 int port = DEFAULT_PORT;
316 char *username = NULL;
317 char *ident = NULL;
318 char *known_hosts = NULL;
319 int get = 0;
320 int prot = PWMD_IP_ANY;
321 #endif
322 int tries = 0;
323 int local_tries = 3;
324 int try = 0;
325 pwmd_socket_t s;
326 int lock_on_open = 1;
327 #ifdef DEBUG
328 int method = 0;
329 fd_set rfds;
330 #endif
331 char *url_string = NULL;
332 /* The order is important. */
333 enum {
334 #ifdef DEBUG
335 OPT_DEBUG,
336 #endif
337 #ifdef WITH_TCP
338 OPT_HOST, OPT_PORT, OPT_IDENTITY, OPT_KNOWN_HOSTS, OPT_USER,
339 OPT_GET_HOSTKEY, OPT_IPV4, OPT_IPV6,
340 #endif
341 OPT_URL, OPT_LOCAL, OPT_FORCE_SAVE, OPT_TTYNAME, OPT_TTYTYPE,
342 OPT_DISPLAY, OPT_LC_CTYPE, OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES,
343 OPT_PINENTRY, OPT_PASSPHRASE, OPT_KEYFILE, OPT_BASE64, OPT_SOCKET,
344 OPT_NOLOCK, OPT_SAVE, OPT_ITERATIONS, OPT_OUTPUT_FD, OPT_INQUIRE_FD,
345 OPT_NO_STATUS, OPT_NAME, OPT_VERSION, OPT_HELP, OPT_CIPHER,
347 const struct option long_opts[] = {
348 #ifdef DEBUG
349 { "debug", 1, 0, 0 },
350 #endif
351 #ifdef WITH_TCP
352 { "host", 1, 0, 'h' },
353 { "port", 1, 0, 'p' },
354 { "identity", 1, 0, 'i' },
355 { "known-hosts", 1, 0, 'k' },
356 { "user", 1, 0, 'u' },
357 { "get-hostkey", 0, 0, 'g' },
358 { "ipv4", 0, 0, '4' },
359 { "ipv6", 0, 0, '6' },
360 #endif
361 { "url", 1, 0, 0 },
362 { "local-pinentry", 0, 0 },
363 { "force-save", 0, 0 },
364 { "ttyname", 1, 0, 'y' },
365 { "ttytype", 1, 0, 't' },
366 { "display", 1, 0, 'd' },
367 { "lc-ctype", 1, 0, 0 },
368 { "lc-messages", 1, 0, 0 },
369 { "timeout", 1, 0, 0 },
370 { "tries", 1, 0, 0 },
371 { "pinentry", 1, 0, 0 },
372 { "passphrase", 1, 0, 'P' },
373 { "key-file", 1, 0, 0 },
374 { "base64", 0, 0, 0 },
375 { "socket", 1, 0, 0 },
376 { "no-lock", 0, 0, 0 },
377 { "save", 0, 0, 'S' },
378 { "iterations", 1, 0, 'I' },
379 { "output-fd", 1, 0, 0 },
380 { "inquire-fd", 1, 0, 0 },
381 { "no-status", 0, 0, 0 },
382 { "name", 1, 0, 'n' },
383 { "version", 0, 0, 0 },
384 { "help", 0, 0, 0 },
385 { "cipher", 1, 0, 0 },
386 { 0, 0, 0, 0}
388 #ifdef WITH_TCP
389 const char *optstring = "46h:p:i:k:u:gy:t:d:P:I:Sn:";
390 #else
391 const char *optstring = "y:t:d:P:I:Sn:";
392 #endif
393 int opt_index = 0;
395 #ifdef ENABLE_NLS
396 setlocale(LC_ALL, "");
397 bindtextdomain("libpwmd", LOCALEDIR);
398 #endif
400 while ((opt = getopt_long(argc, argv, optstring, long_opts, &opt_index)) != -1) {
401 switch (opt) {
402 /* Handle long options without a short option part. */
403 case 0:
404 switch (opt_index) {
405 #ifdef DEBUG
406 case OPT_DEBUG:
407 method = atoi(optarg);
409 if (method > 3)
410 method = 3;
411 break;
412 #endif
413 case OPT_KEYFILE:
414 keyfile = optarg;
415 break;
416 case OPT_BASE64:
417 base64 = 1;
418 break;
419 case OPT_NOLOCK:
420 lock_on_open = 0;
421 break;
422 case OPT_URL:
423 url_string = optarg;
424 break;
425 case OPT_LOCAL:
426 local_pin = 1;
427 break;
428 case OPT_FORCE_SAVE:
429 save = force_save = 1;
430 break;
431 case OPT_LC_CTYPE:
432 lcctype = pwmd_strdup(optarg);
433 break;
434 case OPT_LC_MESSAGES:
435 lcmessages = pwmd_strdup(optarg);
436 break;
437 case OPT_TIMEOUT:
438 timeout = atoi(optarg);
439 break;
440 case OPT_TRIES:
441 tries = atoi(optarg);
442 local_tries = tries;
443 break;
444 case OPT_SOCKET:
445 socketpath = pwmd_strdup(optarg);
446 break;
447 case OPT_INQUIRE_FD:
448 inquirefd = atoi(optarg);
449 inquirefp = fdopen(inquirefd, "r");
451 if (!inquirefp) {
452 pwmd_free(password);
453 err(EXIT_FAILURE, "%i", inquirefd);
455 break;
456 case OPT_OUTPUT_FD:
457 outfd = atoi(optarg);
458 outfp = fdopen(outfd, "w");
460 if (!outfp) {
461 pwmd_free(password);
462 err(EXIT_FAILURE, "%i", outfd);
464 break;
465 case OPT_NO_STATUS:
466 show_status = 0;
467 break;
468 case OPT_VERSION:
469 pwmd_free(password);
470 printf("%s (pwmc)\n%s\n\n"
471 "Compile-time features:\n"
472 #ifdef WITH_TCP
473 "+SSH "
474 #else
475 "-SSH "
476 #endif
477 #ifdef WITH_PINENTRY
478 "+PINENTRY "
479 #else
480 "-PINENTRY "
481 #endif
482 #ifdef WITH_QUALITY
483 "+QUALITY "
484 #else
485 "-QUALITY "
486 #endif
487 #ifdef MEM_DEBUG
488 "+MEM_DEBUG "
489 #else
490 "-MEM_DEBUG "
491 #endif
492 "\n"
493 , PACKAGE_STRING, PACKAGE_BUGREPORT);
494 exit(EXIT_SUCCESS);
495 case OPT_PINENTRY:
496 pinentry_path = optarg;
497 break;
498 case OPT_HELP:
499 usage(argv[0], EXIT_SUCCESS);
500 case OPT_CIPHER:
501 cipher = optarg;
502 break;
503 default:
504 usage(argv[0], EXIT_FAILURE);
507 break;
508 #ifdef WITH_TCP
509 case '4':
510 prot = PWMD_IPV4;
511 break;
512 case '6':
513 prot = PWMD_IPV6;
514 break;
515 case 'h':
516 host = pwmd_strdup(optarg);
517 break;
518 case 'p':
519 port = atoi(optarg);
520 break;
521 case 'i':
522 ident = pwmd_strdup(optarg);
523 break;
524 case 'u':
525 username = pwmd_strdup(optarg);
526 break;
527 case 'k':
528 known_hosts = pwmd_strdup(optarg);
529 break;
530 case 'g':
531 get = 1;
532 break;
533 #endif
534 case 'y':
535 tty = optarg;
536 break;
537 case 't':
538 ttytype = optarg;
539 break;
540 case 'd':
541 display = optarg;
542 break;
543 case 'S':
544 save = 1;
545 break;
546 case 'I':
547 iter = strtol(optarg, NULL, 10);
548 have_iter = 1;
549 break;
550 case 'P':
551 password = pwmd_strdup(optarg);
552 memset(optarg, 0, strlen(optarg));
553 break;
554 case 'n':
555 clientname = optarg;
556 break;
557 default:
558 pwmd_free(password);
559 usage(argv[0], EXIT_FAILURE);
563 #ifdef DEBUG
564 if (!url_string) {
565 #endif
566 #ifdef WITH_TCP
567 if (host && !get && !ident) {
568 pwmd_free(password);
569 usage(argv[0], EXIT_FAILURE);
572 if (get && !host) {
573 pwmd_free(password);
574 usage(argv[0], EXIT_FAILURE);
576 #endif
577 #ifdef DEBUG
579 #endif
581 filename = argv[optind];
582 pwmd_init();
583 pwm = pwmd_new(clientname);
584 #ifdef DEBUG
585 FD_ZERO(&rfds);
586 #endif
588 #ifdef WITH_TCP
589 if (host || url_string) {
590 local_pin = 1;
592 if (prot != PWMD_IP_ANY) {
593 error = pwmd_setopt(pwm, PWMD_OPTION_IP_VERSION, prot);
595 if (error)
596 goto done;
599 error = pwmd_setopt(pwm, PWMD_OPTION_KNOWNHOST_CB, knownhost_cb);
601 if (error)
602 goto done;
604 error = pwmd_setopt(pwm, PWMD_OPTION_KNOWNHOST_DATA, clientname);
606 if (error)
607 goto done;
609 #ifdef DEBUG
610 if (method >= 2) {
611 if (get) {
612 char *hostkey;
614 error = pwmd_get_hostkey_async(pwm, host, port);
616 if (error)
617 errx(EXIT_FAILURE, "%s: %s", host, pwmd_strerror(error));
619 error = process_cmd(pwm, &hostkey, 0);
621 if (error)
622 goto done;
624 printf("%s", hostkey);
625 pwmd_free(hostkey);
626 pwmd_free(password);
627 pwmd_close(pwm);
628 exit(EXIT_SUCCESS);
631 if (url_string)
632 error = pwmd_connect_url_async(pwm, url_string);
633 else
634 error = pwmd_ssh_connect_async(pwm, host, port, ident, username,
635 known_hosts);
637 if (error)
638 goto done;
640 error = process_cmd(pwm, NULL, 0);
642 if (error)
643 goto done;
645 else {
646 #endif
647 if (get) {
648 char *hostkey;
650 error = pwmd_get_hostkey(pwm, host, port, &hostkey);
652 if (error)
653 goto done;
655 printf("%s", hostkey);
656 pwmd_free(hostkey);
657 pwmd_free(password);
658 pwmd_close(pwm);
659 exit(EXIT_SUCCESS);
662 if (url_string)
663 error = pwmd_connect_url(pwm, url_string);
664 else
665 error = pwmd_ssh_connect(pwm, host, port, ident, username, known_hosts);
667 if (error)
668 goto done;
669 #ifdef DEBUG
671 #endif
673 else {
674 #endif
675 if (url_string)
676 error = pwmd_connect_url(pwm, url_string);
677 else
678 error = pwmd_connect(pwm, socketpath);
680 if (error)
681 goto done;
682 #ifdef WITH_TCP
684 #endif
686 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TITLE, NULL);
687 error = pwmd_socket_type(pwm, &s);
689 if (error)
690 goto done;
692 if (s == PWMD_SOCKET_SSH && force_save && !local_pin) {
693 error = GPG_ERR_WRONG_KEY_USAGE;
694 goto done;
697 if (have_iter) {
698 error = pwmd_command(pwm, &result, "VERSION");
700 if (error)
701 goto done;
703 pwmd_free(result);
705 if (iter < 0) {
706 pwmd_free(password);
707 pwmd_close(pwm);
708 usage(argv[0], EXIT_FAILURE);
712 if (filename && lock_on_open) {
713 error = pwmd_setopt(pwm, PWMD_OPTION_LOCK_ON_OPEN, 1);
715 if (error)
716 goto done;
719 if (base64) {
720 error = pwmd_setopt(pwm, PWMD_OPTION_BASE64, 1);
722 if (error)
723 goto done;
726 if (timeout > 0) {
727 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
729 if (error)
730 goto done;
733 if (local_pin && filename && !keyfile) {
734 error = pwmd_command(pwm, NULL, "ISCACHED %s", filename);
736 if (error == GPG_ERR_NOT_FOUND) {
737 local_password:
738 if (try++ == local_tries)
739 goto done;
741 if (password)
742 pwmd_free(password);
744 password = NULL;
746 if (try > 1)
747 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, 0);
749 error = pwmd_getpin(pwm, filename, &password,
750 try > 1 ? PWMD_PINENTRY_OPEN_FAILED : PWMD_PINENTRY_OPEN);
752 if (error)
753 goto done;
755 error = pwmd_setopt(pwm, PWMD_OPTION_PASSPHRASE, password);
757 if (error)
758 goto done;
760 if (try > 1)
761 goto do_open;
763 else if (error && error != GPG_ERR_ENOENT)
764 goto done;
767 if (password) {
768 error = pwmd_setopt(pwm, PWMD_OPTION_PASSPHRASE, password);
770 if (error)
771 goto done;
773 else {
774 if (pinentry_path) {
775 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
777 if (error)
778 goto done;
781 if (display) {
782 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
784 if (error)
785 goto done;
788 if (tty) {
789 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TTY, tty);
791 if (error)
792 goto done;
795 if (ttytype) {
796 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
798 if (error)
799 goto done;
802 if (lcctype) {
803 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
805 if (error)
806 goto done;
809 if (lcmessages) {
810 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES,
811 lcmessages);
813 if (error)
814 goto done;
817 if (tries > 0) {
818 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
820 if (error)
821 goto done;
825 if (show_status) {
826 error = pwmd_setopt(pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
828 if (error)
829 goto done;
832 do_open:
833 if (filename) {
834 if (keyfile && (!local_pin || host || url_string)) {
835 struct inquire_s inq;
837 memset(&inq, 0, sizeof(inq));
838 inq.fd = open(keyfile, O_RDONLY);
840 if (inq.fd == -1) {
841 error = gpg_error_from_syserror();
842 goto done;
845 inq.line = pwmd_calloc(1, ASSUAN_LINELENGTH);
847 if (!inq.line) {
848 error = GPG_ERR_ENOMEM;
849 goto done;
852 error = pwmd_open_inquire(pwm, filename, inquire_cb, &inq);
853 pwmd_free(inq.line);
854 close(inq.fd);
856 if (error)
857 goto done;
859 goto read_command;
861 #ifdef DEBUG
862 switch (method) {
863 case 0:
864 error = pwmd_open(pwm, filename);
865 break;
866 case 1:
867 error = pwmd_open2(pwm, filename);
868 break;
869 case 2:
870 error = pwmd_open_async(pwm, filename);
872 break;
873 case 3:
874 error = pwmd_open_async2(pwm, filename);
875 break;
878 if (error && local_pin && error == GPG_ERR_INV_PASSPHRASE)
879 goto local_password;
881 if (error)
882 goto done;
884 if (method >= 2)
885 error = process_cmd(pwm, &result, 0);
886 #else
887 #ifdef WITH_TCP
888 if (host)
889 error = pwmd_open2(pwm, filename);
890 else
891 #endif
892 error = pwmd_open(pwm, filename);
894 if (error && local_pin && error == GPG_ERR_INV_PASSPHRASE)
895 goto local_password;
896 #endif
898 if (error)
899 goto done;
902 read_command:
903 fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
904 ssize_t n;
906 for (;;) {
907 error = process_cmd(pwm, NULL, 1);
909 if (error)
910 goto done;
912 n = read(STDIN_FILENO, command, sizeof(command));
914 if (n == -1) {
915 if (errno == EAGAIN)
916 continue;
918 error = gpg_error_from_errno(errno);
919 goto done;
921 else if (!n)
922 goto done;
924 p = command;
925 command[n] = 0;
926 break;
929 if (!p || !*p)
930 goto done;
933 * This is a known INQUIRE command. We use pwmd_inquire() to send the
934 * data from inquire_cb().
936 if (n > 6 && (!memcmp(p, "STORE ", 6) || !memcmp(p, "store ", 6))) {
937 p += 6;
938 n -= 6;
939 inquire = (char *)"STORE";
941 else if (n > 7 && (!memcmp(p, "IMPORT ", 7) || !memcmp(p, "import ", 7))) {
942 p += 7;
943 n -= 7;
944 inquire = (char *)"IMPORT";
947 if (inquire) {
948 struct inquire_s inq;
949 struct stat st;
951 memset(&inq, 0, sizeof(inq));
952 inq.fd = fileno(inquirefp);
954 if (inq.fd == -1) {
955 error = gpg_error_from_syserror();
956 goto done;
959 if (fstat(inq.fd, &st) == -1) {
960 error = gpg_error_from_syserror();
961 goto done;
964 error = pwmd_setopt(pwm, PWMD_OPTION_INQUIRE_TOTAL,
965 st.st_size ? (size_t)st.st_size+strlen(p) : 0);
967 if (error)
968 goto done;
970 inq.line = pwmd_calloc(1, ASSUAN_LINELENGTH);
972 if (!inq.line) {
973 error = GPG_ERR_ENOMEM;
974 goto done;
977 memcpy(inq.line, p, n);
978 inq.len = n;
979 error = pwmd_inquire(pwm, inquire, inquire_cb, &inq);
980 pwmd_free(inq.line);
981 close(inq.fd);
982 goto done;
985 if (strcasecmp(p, "BYE") == 0)
986 goto done;
988 error = pwmd_command(pwm, &result, command);
989 memset(command, 0, sizeof(command));
991 if (error)
992 goto done;
994 if (result) {
995 fwrite(result, 1, strlen(result), outfp);
996 pwmd_free(result);
999 done:
1000 memset(command, 0, sizeof(command));
1002 if (password)
1003 pwmd_free(password);
1005 password = NULL;
1007 if (!error && save && filename) {
1008 if (iter != -2) {
1009 error = pwmd_setopt(pwm, PWMD_OPTION_ITERATIONS, iter);
1011 if (error)
1012 goto do_exit;
1015 if (cipher) {
1016 error = pwmd_setopt(pwm, PWMD_OPTION_CIPHER, cipher);
1018 if (error)
1019 goto do_exit;
1022 if (local_pin) {
1023 char *p1;
1024 again:
1025 if (!force_save) {
1026 error = pwmd_command(pwm, NULL, "ISCACHED %s", filename);
1028 if (error && error != GPG_ERR_NOT_FOUND &&
1029 error != GPG_ERR_ENOENT)
1030 goto do_exit;
1031 else if (!error)
1032 goto do_save;
1035 error = pwmd_getpin(pwm, filename, &p1, PWMD_PINENTRY_SAVE);
1037 if (error)
1038 goto do_exit;
1040 error = pwmd_getpin(pwm, filename, &password,
1041 PWMD_PINENTRY_SAVE_CONFIRM);
1043 if (error) {
1044 pwmd_free(p1);
1045 goto do_exit;
1048 if ((p1 || password) && ((!p1 && password) || (!password && p1) ||
1049 strcmp(p1, password))) {
1050 pwmd_free(p1);
1051 pwmd_free(password);
1052 password = NULL;
1053 goto again;
1056 if (p1)
1057 pwmd_free(p1);
1059 error = pwmd_setopt(pwm, PWMD_OPTION_PASSPHRASE, password);
1061 if (password)
1062 pwmd_free(password);
1064 if (error)
1065 goto do_exit;
1068 if (force_save) {
1069 error = pwmd_command(pwm, NULL, "CLEARCACHE %s", filename);
1071 if (error)
1072 goto do_exit;
1074 if (!local_pin) {
1075 error = pwmd_setopt(pwm, PWMD_OPTION_PASSPHRASE, NULL);
1077 if (error)
1078 goto do_exit;
1082 do_save:
1083 if (keyfile && !local_pin) {
1084 struct inquire_s inq;
1086 memset(&inq, 0, sizeof(inq));
1087 inq.fd = open(keyfile, O_RDONLY);
1089 if (inq.fd == -1) {
1090 error = gpg_error_from_syserror();
1091 goto do_exit;
1094 inq.line = pwmd_calloc(1, ASSUAN_LINELENGTH);
1096 if (!inq.line) {
1097 error = GPG_ERR_ENOMEM;
1098 goto do_exit;
1101 error = pwmd_save_inquire(pwm, inquire_cb, &inq);
1102 pwmd_free(inq.line);
1103 close(inq.fd);
1105 else {
1106 #ifdef DEBUG
1107 switch (method) {
1108 case 0:
1109 error = pwmd_save(pwm);
1110 break;
1111 case 1:
1112 error = pwmd_save2(pwm);
1113 break;
1114 case 2:
1115 error = pwmd_save_async(pwm);
1116 break;
1117 case 3:
1118 error = pwmd_save_async2(pwm);
1119 break;
1122 if (!error && method >= 2)
1123 error = process_cmd(pwm, NULL, 0);
1125 #else
1126 #ifdef WITH_TCP
1127 if (host)
1128 error = pwmd_save2(pwm);
1129 else
1130 #endif
1131 error = pwmd_save(pwm);
1132 #endif
1136 do_exit:
1137 if (error) {
1138 show_error(error);
1139 ret = EXIT_FAILURE;
1142 pwmd_close(pwm);
1144 if (socketpath)
1145 pwmd_free(socketpath);
1147 exit(ret);