Added ssh-agent support. Enable with PWMD_OPTION_SSH_AGENT.
[libpwmd.git] / src / pwmc.c
blob1876874349e9353b0a3c445d90dbfdae1c436ab5
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 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <err.h>
27 #include <errno.h>
28 #include <string.h>
29 #include <libpwmd.h>
30 #include <assuan.h>
31 #ifdef DEBUG
32 #include <sys/select.h>
33 #endif
34 #include <fcntl.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
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 #ifdef HAVE_LIBREADLINE
51 # if defined(HAVE_READLINE_READLINE_H)
52 # include <readline/readline.h>
53 # elif defined(HAVE_READLINE_H)
54 # include <readline.h>
55 # endif /* !defined(HAVE_READLINE_H) */
56 #endif /* HAVE_LIBREADLINE */
58 #ifdef HAVE_READLINE_HISTORY
59 # if defined(HAVE_READLINE_HISTORY_H)
60 # include <readline/history.h>
61 # elif defined(HAVE_HISTORY_H)
62 # include <history.h>
63 # endif
64 #endif /* HAVE_READLINE_HISTORY */
66 #include "gettext.h"
67 #define N_(msgid) gettext(msgid)
69 #include "mem.h"
71 #define DEFAULT_PORT 22
73 static pwm_t *pwm;
75 struct inquire_s {
76 int fd;
77 char *line;
78 size_t len;
81 static void show_error(gpg_error_t error)
83 fprintf(stderr, "ERR %i %s\n", gpg_err_code(error), pwmd_strerror(error));
86 static void usage(const char *pn, int status)
88 fprintf(status == EXIT_FAILURE ? stderr : stdout, N_(
89 "Read a PWMD protocol command from standard input.\n\n"
90 "Usage: pwmc [options] [file]\n"
91 #ifdef DEBUG
92 " --debug <N>\n"
93 " pinentry method (0=pwmd, 1=libpwmd, 2=pwmd async, "
94 "3=libpwmd async)\n"
95 #endif
96 "\n"
97 #ifdef WITH_TCP
98 " --host, -h <hostname>\n"
99 " connect to the specified hostname\n"
100 "\n"
101 " --port <N>\n"
102 " alterate port (22)\n"
103 "\n"
104 " --user <username>\n"
105 " SSH username (default is the invoking user)\n"
106 "\n"
107 " --use-agent\n"
108 " use the ssh agent for authentication\n"
109 "\n"
110 " --identity, -i <filename>\n"
111 " SSH identity file\n"
112 "\n"
113 " --known-hosts, -k <filename>\n"
114 " known host's file (for server validation)\n"
115 "\n"
116 " --get-hostkey, -g\n"
117 " retrieve the remote SSH host key and exit\n"
118 "\n"
119 " --ipv4, -4\n"
120 " try connecting via IPv4 only\n"
121 "\n"
122 " --ipv6, -6\n"
123 " try connecting via IPv6 only\n"
124 "\n"
125 #endif
126 " --url <string>\n"
127 " a url string to parse\n"
128 "\n"
129 " --no-status\n"
130 " disable showing of status messages from the server\n"
131 "\n"
132 " --name, -n <string>\n"
133 " set the client name\n"
134 "\n"
135 " --socket <filename>\n"
136 " local socket to connect to (~/.pwmd/socket)\n"
137 "\n"
138 " --passphrase, -P <string>\n"
139 " passphrase to use (disables pinentry use)\n"
140 "\n"
141 " --key-file <filename>\n"
142 " obtain the passphrase from the specified filename\n"
143 "\n"
144 " --base64\n"
145 " the passphrase is base64 encoded\n"
146 "\n"
147 " --timeout <seconds>\n"
148 " pinentry timeout\n"
149 "\n"
150 " --tries <N>\n"
151 " number of pinentry tries before failing (3)\n"
152 "\n"
153 " --pinentry <path>\n"
154 " the full path to the pinentry binary (server default)\n"
155 "\n"
156 " --ttyname, -y <path>\n"
157 " tty that pinentry will use\n"
158 "\n"
159 " --ttytype, -t <string>\n"
160 " pinentry terminal type (default is $TERM)\n"
161 "\n"
162 " --display, -d\n"
163 " pinentry display (default is $DISPLAY)\n"
164 "\n"
165 " --lc-ctype <string>\n"
166 " locale setting for pinentry\n"
167 "\n"
168 " --lc-messages <string>\n"
169 " locale setting for pinentry\n"
170 "\n"
172 " --local-pinentry\n"
173 " force using a local pinentry\n"
174 "\n"
175 " --interactive\n"
176 " use a shell like interface to pwmd (allows more than one command)\n"
177 "\n"
178 " --output-fd <FD>\n"
179 " redirect command output to the specified file descriptor\n"
180 "\n"
181 " --inquire <COMMAND>\n"
182 " the specified command (with any options) uses a server inquire while\n"
183 " command data is read via the inquire file descriptor (stdin)\n"
184 "\n"
185 " --inquire-fd <FD>\n"
186 " read inquire data from the specified file descriptor (stdin)\n"
187 "\n"
188 " --cipher <string>\n"
189 " the cipher to use when saving (see pwmd(1))\n"
190 "\n"
191 " --save, -S\n"
192 " send the SAVE command before exiting\n"
193 "\n"
194 " --force-save\n"
195 " like --save, but ask for a passphrase\n"
196 "\n"
197 " --iterations, -I <N>\n"
198 " encrypt with the specified number of iterations when saving\n"
199 "\n"
200 " --version\n"
201 " --help\n"));
202 fprintf(status == EXIT_FAILURE ? stderr : stdout, N_(
203 "\n"
204 "A url string (specified with --url) may be in the form of:\n"
205 " file://[path/to/socket]\n"
206 #ifdef WITH_TCP
207 " ssh[46]://[username@]hostname[:port][,identity,known_hosts]\n"
208 #endif
210 exit(status);
213 static gpg_error_t inquire_cb(void *user, const char *cmd, gpg_error_t rc,
214 char **data, size_t *len)
216 struct inquire_s *inq = user;
218 *data = NULL;
219 *len = 0;
221 if (rc)
222 return rc;
224 /* The first part of the command data. */
225 if (inq->len) {
226 *data = inq->line;
227 *len = inq->len;
228 inq->len = 0;
229 return 0;
232 *len = read(inq->fd, inq->line, ASSUAN_LINELENGTH);
234 if (*len == -1)
235 return gpg_error_from_syserror();
237 if (*len)
238 *data = inq->line;
240 return *len ? 0 : GPG_ERR_EOF;
243 static int status_msg_cb(void *data, const char *line)
245 fprintf(stderr, "%s\n", line);
246 return 0;
249 static gpg_error_t process_cmd(pwm_t *pwm, char **result, int input, int once)
251 gpg_error_t rc;
252 pwmd_async_t s;
254 do {
255 int i, n;
256 fd_set rfds;
257 int nfds = 5;
258 pwmd_fd_t pfds[nfds];
259 struct timeval tv = {0, 0};
261 FD_ZERO(&rfds);
262 rc = pwmd_get_fds(pwm, pfds, &nfds);
264 if (rc)
265 return rc;
267 if (!nfds) {
268 s = pwmd_process(pwm, &rc, result);
269 break;
272 for (i = 0, n = 0; i < nfds; i++) {
273 FD_SET(pfds[i].fd, &rfds);
274 n = pfds[i].fd > n ? pfds[i].fd : n;
277 if (input)
278 FD_SET(STDIN_FILENO, &rfds);
280 nfds = select(n+1, &rfds, NULL, NULL, once ? &tv : NULL);
282 if (nfds == -1) {
283 rc = gpg_error_from_errno(errno);
284 return rc;
287 if (input && FD_ISSET(STDIN_FILENO, &rfds))
288 return 0;
290 s = pwmd_process(pwm, &rc, result);
292 if (once)
293 break;
294 } while (s == ASYNC_PROCESS);
296 return rc;
299 #ifdef WITH_TCP
300 static gpg_error_t knownhost_cb(void *data, const char *host, const char *key,
301 size_t len)
303 gpg_error_t rc;
304 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);
306 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TITLE, buf);
307 pwmd_free(buf);
309 if (rc)
310 return rc;
312 return pwmd_getpin(pwm, NULL, NULL, PWMD_PINENTRY_CONFIRM);
315 static int is_remote_url(const char *str)
317 if (strstr(str, "file://") || strstr(str, "local://"))
318 return 0;
320 return 1;
322 #endif
324 static gpg_error_t send_inquire(int fd, const char *command)
326 struct inquire_s inq;
327 struct stat st;
328 gpg_error_t rc;
330 if (fstat(fd, &st) == -1)
331 return gpg_error_from_syserror();
333 rc = pwmd_setopt(pwm, PWMD_OPTION_INQUIRE_TOTAL, st.st_size);
335 if (rc)
336 return rc;
338 memset(&inq, 0, sizeof(inq));
339 inq.fd = fd;
340 inq.line = pwmd_calloc(1, ASSUAN_LINELENGTH);
342 if (!inq.line)
343 return GPG_ERR_ENOMEM;
345 inq.len = 0;
346 rc = pwmd_inquire(pwm, command, inquire_cb, &inq);
347 pwmd_free(inq.line);
348 return rc;
351 #ifdef HAVE_LIBREADLINE
352 static int interactive_hook(void)
354 process_cmd(pwm, NULL, 0, 1);
355 return 0;
358 static gpg_error_t do_interactive()
360 gpg_error_t rc = 0;
362 fprintf(stderr, "WARNING: interactive mode doesn't use secure memory!\n");
363 rl_initialize();
364 rl_event_hook = &interactive_hook;
366 for (;;) {
367 char *line;
368 char *result = NULL;
370 line = readline("pwm> ");
372 if (!line)
373 break;
374 else if (!*line) {
375 free(line);
376 continue;
379 #ifdef HAVE_READLINE_HISTORY
380 add_history(line);
381 #endif
383 /* INQUIRE <COMMAND [options ...]> */
384 if (!strncasecmp(line, "inquire ", 8)) {
385 fprintf(stderr, "Press CTRL-D to end.\n");
386 rc = send_inquire(STDIN_FILENO, line+8);
388 /* INQUIRE_FILE <FILENAME> <COMMAND [options ...]> */
389 else if (!strncasecmp(line, "inquire_file ", 13)) {
390 char *p = strchr(line+13, ' ');
391 char *f = p ? line+13 : NULL;
392 int fd;
394 if (!f || !*f || !*p) {
395 fprintf(stderr, "Invalid number of command arguments.\n");
396 free(line);
397 continue;
400 f[strlen(f) - strlen(p++)] = 0;
401 fd = open(f, O_RDONLY);
403 if (fd == -1) {
404 fprintf(stderr, "%s\n", strerror(errno));
405 free(line);
406 continue;
408 else {
409 rc = send_inquire(fd, p);
410 close(fd);
413 else
414 rc = pwmd_command(pwm, &result, line);
416 free(line);
418 if (rc)
419 fprintf(stderr, "ERR %i: %s\n", rc, pwmd_strerror(rc));
420 else if (result && *result)
421 printf("%s%s", result, result[strlen(result)-1] != '\n' ? "\n" : "");
423 if (result)
424 pwmd_free(result);
427 return 0;
429 #endif
431 int main(int argc, char *argv[])
433 int opt;
434 #ifdef HAVE_LIBREADLINE
435 int interactive = 0;
436 #endif
437 char *password = NULL;
438 char *keyfile = NULL;
439 int base64 = 0;
440 char *filename = NULL;
441 char *socketpath = NULL;
442 char command[ASSUAN_LINELENGTH], *p;
443 int ret = EXIT_SUCCESS;
444 gpg_error_t error;
445 char *result = NULL;
446 int save = 0;
447 char *pinentry_path = NULL;
448 char *display = NULL, *tty = NULL, *ttytype = NULL, *lcctype = NULL,
449 *lcmessages = NULL;
450 int outfd = STDOUT_FILENO;
451 FILE *outfp = stdout;
452 int inquirefd = STDIN_FILENO;
453 FILE *inquirefp = stdin;
454 int show_status = 1;
455 char *clientname = "pwmc";
456 char *inquire = NULL;
457 long iter = -2;
458 int have_iter = 0;
459 int timeout = 0;
460 int local_pin = 0;
461 int force_save = 0;
462 char *cipher = NULL;
463 #ifdef WITH_TCP
464 char *host = NULL;
465 int port = DEFAULT_PORT;
466 char *username = NULL;
467 char *ident = NULL;
468 char *known_hosts = NULL;
469 int get = 0;
470 int prot = PWMD_IP_ANY;
471 int use_agent = 0;
472 #endif
473 int tries = 0;
474 int local_tries = 3;
475 int try = 0;
476 pwmd_socket_t s;
477 int lock_on_open = 1;
478 #ifdef DEBUG
479 int method = 0;
480 fd_set rfds;
481 #endif
482 char *url_string = NULL;
483 /* The order is important. */
484 enum {
485 #ifdef DEBUG
486 OPT_DEBUG,
487 #endif
488 #ifdef WITH_TCP
489 OPT_HOST, OPT_PORT, OPT_IDENTITY, OPT_KNOWN_HOSTS, OPT_USER,
490 OPT_GET_HOSTKEY, OPT_IPV4, OPT_IPV6, OPT_USE_AGENT,
491 #endif
492 OPT_URL, OPT_LOCAL, OPT_FORCE_SAVE, OPT_TTYNAME, OPT_TTYTYPE,
493 OPT_DISPLAY, OPT_LC_CTYPE, OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES,
494 OPT_PINENTRY, OPT_PASSPHRASE, OPT_KEYFILE, OPT_BASE64, OPT_SOCKET,
495 OPT_NOLOCK, OPT_SAVE, OPT_ITERATIONS, OPT_OUTPUT_FD, OPT_INQUIRE,
496 OPT_INQUIRE_FD, OPT_NO_STATUS, OPT_NAME, OPT_VERSION, OPT_HELP,
497 OPT_CIPHER,
498 #ifdef HAVE_LIBREADLINE
499 OPT_INTERACTIVE,
500 #endif
502 const struct option long_opts[] = {
503 #ifdef DEBUG
504 { "debug", 1, 0, 0 },
505 #endif
506 #ifdef WITH_TCP
507 { "host", 1, 0, 'h' },
508 { "port", 1, 0, 'p' },
509 { "identity", 1, 0, 'i' },
510 { "known-hosts", 1, 0, 'k' },
511 { "user", 1, 0, 'u' },
512 { "get-hostkey", 0, 0, 'g' },
513 { "ipv4", 0, 0, '4' },
514 { "ipv6", 0, 0, '6' },
515 { "use-agent", 0, 0, 0 },
516 #endif
517 { "url", 1, 0, 0 },
518 { "local-pinentry", 0, 0 },
519 { "force-save", 0, 0 },
520 { "ttyname", 1, 0, 'y' },
521 { "ttytype", 1, 0, 't' },
522 { "display", 1, 0, 'd' },
523 { "lc-ctype", 1, 0, 0 },
524 { "lc-messages", 1, 0, 0 },
525 { "timeout", 1, 0, 0 },
526 { "tries", 1, 0, 0 },
527 { "pinentry", 1, 0, 0 },
528 { "passphrase", 1, 0, 'P' },
529 { "key-file", 1, 0, 0 },
530 { "base64", 0, 0, 0 },
531 { "socket", 1, 0, 0 },
532 { "no-lock", 0, 0, 0 },
533 { "save", 0, 0, 'S' },
534 { "iterations", 1, 0, 'I' },
535 { "output-fd", 1, 0, 0 },
536 { "inquire", 1, 0, 0 },
537 { "inquire-fd", 1, 0, 0 },
538 { "no-status", 0, 0, 0 },
539 { "name", 1, 0, 'n' },
540 { "version", 0, 0, 0 },
541 { "help", 0, 0, 0 },
542 { "cipher", 1, 0, 0 },
543 #ifdef HAVE_LIBREADLINE
544 { "interactive", 0, 0 },
545 #endif
546 { 0, 0, 0, 0}
548 #ifdef WITH_TCP
549 const char *optstring = "46h:p:i:k:u:gy:t:d:P:I:Sn:";
550 #else
551 const char *optstring = "y:t:d:P:I:Sn:";
552 #endif
553 int opt_index = 0;
555 #ifdef ENABLE_NLS
556 setlocale(LC_ALL, "");
557 bindtextdomain("libpwmd", LOCALEDIR);
558 #endif
560 if (!strcmp(basename(argv[0]), "pwmsh"))
561 interactive = 1;
563 while ((opt = getopt_long(argc, argv, optstring, long_opts, &opt_index)) != -1) {
564 switch (opt) {
565 /* Handle long options without a short option part. */
566 case 0:
567 switch (opt_index) {
568 #ifdef DEBUG
569 case OPT_DEBUG:
570 method = atoi(optarg);
572 if (method > 3)
573 method = 3;
574 break;
575 #endif
576 #ifdef WITH_TCP
577 case OPT_USE_AGENT:
578 use_agent = 1;
579 break;
580 #endif
581 case OPT_KEYFILE:
582 keyfile = optarg;
583 break;
584 case OPT_BASE64:
585 base64 = 1;
586 break;
587 case OPT_NOLOCK:
588 lock_on_open = 0;
589 break;
590 case OPT_URL:
591 url_string = optarg;
592 break;
593 case OPT_LOCAL:
594 local_pin = 1;
595 break;
596 case OPT_FORCE_SAVE:
597 save = force_save = 1;
598 break;
599 case OPT_LC_CTYPE:
600 lcctype = pwmd_strdup(optarg);
601 break;
602 case OPT_LC_MESSAGES:
603 lcmessages = pwmd_strdup(optarg);
604 break;
605 case OPT_TIMEOUT:
606 timeout = atoi(optarg);
607 break;
608 case OPT_TRIES:
609 tries = atoi(optarg);
610 local_tries = tries;
611 break;
612 case OPT_SOCKET:
613 socketpath = pwmd_strdup(optarg);
614 break;
615 case OPT_INQUIRE:
616 inquire = optarg;
617 break;
618 case OPT_INQUIRE_FD:
619 inquirefd = atoi(optarg);
620 inquirefp = fdopen(inquirefd, "r");
622 if (!inquirefp) {
623 pwmd_free(password);
624 err(EXIT_FAILURE, "%i", inquirefd);
626 break;
627 case OPT_OUTPUT_FD:
628 outfd = atoi(optarg);
629 outfp = fdopen(outfd, "w");
631 if (!outfp) {
632 pwmd_free(password);
633 err(EXIT_FAILURE, "%i", outfd);
635 break;
636 case OPT_NO_STATUS:
637 show_status = 0;
638 break;
639 case OPT_VERSION:
640 pwmd_free(password);
641 printf("%s (pwmc)\n%s\n\n"
642 "Compile-time features:\n"
643 #ifdef WITH_TCP
644 "+SSH "
645 #else
646 "-SSH "
647 #endif
648 #ifdef WITH_PINENTRY
649 "+PINENTRY "
650 #else
651 "-PINENTRY "
652 #endif
653 #ifdef WITH_QUALITY
654 "+CRACK "
655 #else
656 "-CRACK "
657 #endif
658 #ifdef MEM_DEBUG
659 "+MEM_DEBUG "
660 #else
661 "-MEM_DEBUG "
662 #endif
663 #ifdef HAVE_LIBREADLINE
664 "+INTERACTIVE "
665 #else
666 "-INTERACTIVE "
667 #endif
668 "\n"
669 , PACKAGE_STRING, PACKAGE_BUGREPORT);
670 exit(EXIT_SUCCESS);
671 case OPT_PINENTRY:
672 pinentry_path = optarg;
673 break;
674 case OPT_HELP:
675 usage(argv[0], EXIT_SUCCESS);
676 case OPT_CIPHER:
677 cipher = optarg;
678 break;
679 #ifdef HAVE_LIBREADLINE
680 case OPT_INTERACTIVE:
681 interactive = 1;
682 break;
683 #endif
684 default:
685 usage(argv[0], EXIT_FAILURE);
688 break;
689 #ifdef WITH_TCP
690 case '4':
691 prot = PWMD_IPV4;
692 break;
693 case '6':
694 prot = PWMD_IPV6;
695 break;
696 case 'h':
697 host = pwmd_strdup(optarg);
698 break;
699 case 'p':
700 port = atoi(optarg);
701 break;
702 case 'i':
703 ident = pwmd_strdup(optarg);
704 break;
705 case 'u':
706 username = pwmd_strdup(optarg);
707 break;
708 case 'k':
709 known_hosts = pwmd_strdup(optarg);
710 break;
711 case 'g':
712 get = 1;
713 break;
714 #endif
715 case 'y':
716 tty = optarg;
717 break;
718 case 't':
719 ttytype = optarg;
720 break;
721 case 'd':
722 display = optarg;
723 break;
724 case 'S':
725 save = 1;
726 break;
727 case 'I':
728 iter = strtol(optarg, NULL, 10);
729 have_iter = 1;
730 break;
731 case 'P':
732 password = pwmd_strdup(optarg);
733 memset(optarg, 0, strlen(optarg));
734 break;
735 case 'n':
736 clientname = optarg;
737 break;
738 default:
739 pwmd_free(password);
740 usage(argv[0], EXIT_FAILURE);
744 #ifdef DEBUG
745 if (!url_string) {
746 #endif
747 #ifdef WITH_TCP
748 if (host && !get && !ident) {
749 pwmd_free(password);
750 usage(argv[0], EXIT_FAILURE);
753 if (get && !host) {
754 pwmd_free(password);
755 usage(argv[0], EXIT_FAILURE);
757 #endif
758 #ifdef DEBUG
760 #endif
762 filename = argv[optind];
763 pwmd_init();
764 pwm = pwmd_new(clientname);
765 #ifdef DEBUG
766 FD_ZERO(&rfds);
767 #endif
769 #ifdef WITH_TCP
770 if (host || url_string) {
771 local_pin = 1;
773 if (prot != PWMD_IP_ANY) {
774 error = pwmd_setopt(pwm, PWMD_OPTION_IP_VERSION, prot);
776 if (error)
777 goto done;
780 error = pwmd_setopt(pwm, PWMD_OPTION_KNOWNHOST_CB, knownhost_cb);
782 if (error)
783 goto done;
785 error = pwmd_setopt(pwm, PWMD_OPTION_KNOWNHOST_DATA, clientname);
787 if (error)
788 goto done;
790 error = pwmd_setopt(pwm, PWMD_OPTION_SSH_AGENT, use_agent);
792 if (error)
793 goto done;
795 #ifdef DEBUG
796 if (method >= 2) {
797 if (get) {
798 char *hostkey;
800 error = pwmd_get_hostkey_async(pwm, host, port);
802 if (error)
803 errx(EXIT_FAILURE, "%s: %s", host, pwmd_strerror(error));
805 error = process_cmd(pwm, &hostkey, 0, 0);
807 if (error)
808 goto done;
810 printf("%s", hostkey);
811 pwmd_free(hostkey);
812 pwmd_free(password);
813 pwmd_close(pwm);
814 exit(EXIT_SUCCESS);
817 if (url_string)
818 error = pwmd_connect_url_async(pwm, url_string);
819 else
820 error = pwmd_ssh_connect_async(pwm, host, port, ident, username,
821 known_hosts);
823 if (error)
824 goto done;
826 error = process_cmd(pwm, NULL, 0, 0);
828 if (error)
829 goto done;
831 else {
832 #endif
833 if (get) {
834 char *hostkey;
836 error = pwmd_get_hostkey(pwm, host, port, &hostkey);
838 if (error)
839 goto done;
841 printf("%s", hostkey);
842 pwmd_free(hostkey);
843 pwmd_free(password);
844 pwmd_close(pwm);
845 exit(EXIT_SUCCESS);
848 if (url_string)
849 error = pwmd_connect_url(pwm, url_string);
850 else
851 error = pwmd_ssh_connect(pwm, host, port, ident, username, known_hosts);
853 if (error)
854 goto done;
855 #ifdef DEBUG
857 #endif
859 else {
860 #endif
861 if (url_string)
862 error = pwmd_connect_url(pwm, url_string);
863 else
864 error = pwmd_connect(pwm, socketpath);
866 if (error)
867 goto done;
868 #ifdef WITH_TCP
870 #endif
872 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TITLE, NULL);
873 error = pwmd_socket_type(pwm, &s);
875 if (error)
876 goto done;
878 if (s == PWMD_SOCKET_SSH && force_save && !local_pin) {
879 error = GPG_ERR_WRONG_KEY_USAGE;
880 goto done;
883 if (have_iter) {
884 error = pwmd_command(pwm, &result, "VERSION");
886 if (error)
887 goto done;
889 pwmd_free(result);
891 if (iter < 0) {
892 pwmd_free(password);
893 pwmd_close(pwm);
894 usage(argv[0], EXIT_FAILURE);
898 if (filename && lock_on_open) {
899 error = pwmd_setopt(pwm, PWMD_OPTION_LOCK_ON_OPEN, 1);
901 if (error)
902 goto done;
905 if (base64) {
906 error = pwmd_setopt(pwm, PWMD_OPTION_BASE64, 1);
908 if (error)
909 goto done;
912 if (timeout > 0) {
913 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
915 if (error)
916 goto done;
919 if (local_pin && filename && !keyfile) {
920 error = pwmd_command(pwm, NULL, "ISCACHED %s", filename);
922 if (error == GPG_ERR_NOT_FOUND) {
923 local_password:
924 if (try++ == local_tries)
925 goto done;
927 if (password)
928 pwmd_free(password);
930 password = NULL;
932 if (try > 1)
933 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, 0);
935 error = pwmd_getpin(pwm, filename, &password,
936 try > 1 ? PWMD_PINENTRY_OPEN_FAILED : PWMD_PINENTRY_OPEN);
938 if (error)
939 goto done;
941 error = pwmd_setopt(pwm, PWMD_OPTION_PASSPHRASE, password);
943 if (error)
944 goto done;
946 if (try > 1)
947 goto do_open;
949 else if (error && error != GPG_ERR_ENOENT)
950 goto done;
953 if (password) {
954 error = pwmd_setopt(pwm, PWMD_OPTION_PASSPHRASE, password);
956 if (error)
957 goto done;
959 else {
960 if (pinentry_path) {
961 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
963 if (error)
964 goto done;
967 if (display) {
968 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
970 if (error)
971 goto done;
974 if (tty) {
975 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TTY, tty);
977 if (error)
978 goto done;
981 if (ttytype) {
982 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
984 if (error)
985 goto done;
988 if (lcctype) {
989 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
991 if (error)
992 goto done;
995 if (lcmessages) {
996 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES,
997 lcmessages);
999 if (error)
1000 goto done;
1003 if (tries > 0) {
1004 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
1006 if (error)
1007 goto done;
1011 if (show_status) {
1012 error = pwmd_setopt(pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
1014 if (error)
1015 goto done;
1018 do_open:
1019 if (filename) {
1020 #ifdef WITH_TCP
1021 if (keyfile && (!local_pin || host || is_remote_url(url_string))) {
1022 struct inquire_s inq;
1024 memset(&inq, 0, sizeof(inq));
1025 inq.fd = open(keyfile, O_RDONLY);
1027 if (inq.fd == -1) {
1028 error = gpg_error_from_syserror();
1029 goto done;
1032 inq.line = pwmd_calloc(1, ASSUAN_LINELENGTH);
1034 if (!inq.line) {
1035 error = GPG_ERR_ENOMEM;
1036 goto done;
1039 error = pwmd_open_inquire(pwm, filename, inquire_cb, &inq);
1040 pwmd_free(inq.line);
1041 close(inq.fd);
1043 if (error)
1044 goto done;
1046 goto read_command;
1048 #endif
1049 #ifdef DEBUG
1050 switch (method) {
1051 case 0:
1052 error = pwmd_open(pwm, filename);
1053 break;
1054 case 1:
1055 error = pwmd_open2(pwm, filename);
1056 break;
1057 case 2:
1058 error = pwmd_open_async(pwm, filename);
1060 break;
1061 case 3:
1062 error = pwmd_open_async2(pwm, filename);
1063 break;
1066 if (error && local_pin && error == GPG_ERR_INV_PASSPHRASE)
1067 goto local_password;
1069 if (error)
1070 goto done;
1072 if (method >= 2)
1073 error = process_cmd(pwm, &result, 0, 0);
1074 #else
1075 #ifdef WITH_TCP
1076 if (host)
1077 error = pwmd_open2(pwm, filename);
1078 else
1079 #endif
1080 error = pwmd_open(pwm, filename);
1082 if (error && local_pin && error == GPG_ERR_INV_PASSPHRASE)
1083 goto local_password;
1084 #endif
1086 if (error)
1087 goto done;
1090 #ifdef WITH_TCP
1091 read_command:
1092 #endif
1093 #ifdef HAVE_LIBREADLINE
1094 if (interactive) {
1095 error = do_interactive();
1097 if (error)
1098 goto do_exit;
1100 goto done;
1102 #endif
1104 if (inquire) {
1105 int fd = fileno(inquirefp);
1107 if (fd == -1) {
1108 error = gpg_error_from_syserror();
1109 goto done;
1112 error = send_inquire(fd, inquire);
1113 close(fd);
1114 goto done;
1117 fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
1118 ssize_t n;
1120 for (;;) {
1121 error = process_cmd(pwm, NULL, 1, 0);
1123 if (error)
1124 goto done;
1126 n = read(STDIN_FILENO, command, sizeof(command));
1128 if (n == -1) {
1129 if (errno == EAGAIN)
1130 continue;
1132 error = gpg_error_from_errno(errno);
1133 goto done;
1135 else if (!n)
1136 goto done;
1138 p = command;
1139 command[n] = 0;
1140 break;
1143 if (!p || !*p)
1144 goto done;
1146 if (strcasecmp(p, "BYE") == 0)
1147 goto done;
1149 error = pwmd_command(pwm, &result, command);
1151 if (error)
1152 goto done;
1154 if (result) {
1155 fwrite(result, 1, strlen(result), outfp);
1156 pwmd_free(result);
1159 done:
1160 if (password)
1161 pwmd_free(password);
1163 password = NULL;
1165 if (!error && save && filename) {
1166 if (iter != -2) {
1167 error = pwmd_setopt(pwm, PWMD_OPTION_ITERATIONS, iter);
1169 if (error)
1170 goto do_exit;
1173 if (cipher) {
1174 error = pwmd_setopt(pwm, PWMD_OPTION_CIPHER, cipher);
1176 if (error)
1177 goto do_exit;
1180 if (local_pin) {
1181 char *p1;
1182 again:
1183 if (!force_save) {
1184 error = pwmd_command(pwm, NULL, "ISCACHED %s", filename);
1186 if (error && error != GPG_ERR_NOT_FOUND &&
1187 error != GPG_ERR_ENOENT)
1188 goto do_exit;
1189 else if (!error)
1190 goto do_save;
1193 error = pwmd_getpin(pwm, filename, &p1, PWMD_PINENTRY_SAVE);
1195 if (error)
1196 goto do_exit;
1198 error = pwmd_getpin(pwm, filename, &password,
1199 PWMD_PINENTRY_SAVE_CONFIRM);
1201 if (error) {
1202 pwmd_free(p1);
1203 goto do_exit;
1206 if ((p1 || password) && ((!p1 && password) || (!password && p1) ||
1207 strcmp(p1, password))) {
1208 pwmd_free(p1);
1209 pwmd_free(password);
1210 password = NULL;
1211 goto again;
1214 if (p1)
1215 pwmd_free(p1);
1217 error = pwmd_setopt(pwm, PWMD_OPTION_PASSPHRASE, password);
1219 if (password)
1220 pwmd_free(password);
1222 if (error)
1223 goto do_exit;
1226 if (force_save) {
1227 error = pwmd_command(pwm, NULL, "CLEARCACHE %s", filename);
1229 if (error)
1230 goto do_exit;
1232 if (!local_pin) {
1233 error = pwmd_setopt(pwm, PWMD_OPTION_PASSPHRASE, NULL);
1235 if (error)
1236 goto do_exit;
1240 do_save:
1241 if (keyfile && !local_pin) {
1242 struct inquire_s inq;
1244 memset(&inq, 0, sizeof(inq));
1245 inq.fd = open(keyfile, O_RDONLY);
1247 if (inq.fd == -1) {
1248 error = gpg_error_from_syserror();
1249 goto do_exit;
1252 inq.line = pwmd_calloc(1, ASSUAN_LINELENGTH);
1254 if (!inq.line) {
1255 error = GPG_ERR_ENOMEM;
1256 goto do_exit;
1259 error = pwmd_save_inquire(pwm, inquire_cb, &inq);
1260 pwmd_free(inq.line);
1261 close(inq.fd);
1263 else {
1264 #ifdef DEBUG
1265 switch (method) {
1266 case 0:
1267 error = pwmd_save(pwm);
1268 break;
1269 case 1:
1270 error = pwmd_save2(pwm);
1271 break;
1272 case 2:
1273 error = pwmd_save_async(pwm);
1274 break;
1275 case 3:
1276 error = pwmd_save_async2(pwm);
1277 break;
1280 if (!error && method >= 2)
1281 error = process_cmd(pwm, NULL, 0, 0);
1283 #else
1284 #ifdef WITH_TCP
1285 if (host)
1286 error = pwmd_save2(pwm);
1287 else
1288 #endif
1289 error = pwmd_save(pwm);
1290 #endif
1294 do_exit:
1295 memset(command, 0, sizeof(command));
1297 if (error) {
1298 show_error(error);
1299 ret = EXIT_FAILURE;
1302 pwmd_close(pwm);
1304 if (socketpath)
1305 pwmd_free(socketpath);
1307 exit(ret);