pwmc: Compile time fix when no DEBUG is defined.
[libpwmd.git] / src / pwmc.c
blob87423604eecde355cd1bbce0956a885bcc1e10a9
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>
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
36 #ifdef HAVE_LOCALE_H
37 #include <locale.h>
38 #endif
40 #ifdef HAVE_GETOPT_LONG
41 #ifdef HAVE_GETOPT_H
42 #include <getopt.h>
43 #endif
44 #else
45 #include "getopt_long.h"
46 #endif
48 #include "gettext.h"
49 #define N_(msgid) gettext(msgid)
51 #include "mem.h"
53 #define DEFAULT_PORT 22
54 pwm_t *pwm;
56 static void show_error(gpg_error_t error)
58 fprintf(stderr, "ERR %i %s\n", gpg_err_code(error), pwmd_strerror(error));
61 static void usage(const char *pn, int status)
63 fprintf(status == EXIT_FAILURE ? stderr : stdout, N_(
64 "Read a PWMD protocol command from standard input.\n\n"
65 "Usage: pwmc [options] [file]\n"
66 #ifdef DEBUG
67 " --debug <N>\n"
68 " pinentry method (0=pwmd, 1=libpwmd, 2=pwmd async, "
69 "3=libpwmd async)\n"
70 #endif
71 "\n"
72 #ifdef WITH_TCP
73 " --host, -h <hostname>\n"
74 " connect to the specified hostname\n"
75 "\n"
76 " --port\n"
77 " alterate port (22)\n"
78 "\n"
79 " --user\n"
80 " SSH username (default is the invoking user)\n"
81 "\n"
82 " --identity, -i <filename>\n"
83 " SSH identity file\n"
84 "\n"
85 " --known-hosts, -k <filename>\n"
86 " known host's file (for server validation)\n"
87 "\n"
88 " --get-hostkey, -g\n"
89 " retrieve the remote SSH host key and exit\n"
90 "\n"
91 " --ipv4, -4\n"
92 " try connecting via IPv4 only\n"
93 "\n"
94 " --ipv6, -6\n"
95 " try connecting via IPv6 only\n"
96 "\n"
97 #endif
98 " --url <string>\n"
99 " a url string to parse\n"
100 "\n"
101 " --no-status\n"
102 " disable showing of status messages from the server\n"
103 "\n"
104 " --name, -n <string>\n"
105 " set the client name\n"
106 "\n"
107 " --socket <filename>\n"
108 " local socket to connect to (~/.pwmd/socket)\n"
109 "\n"
110 " --passphrase, -P <string>\n"
111 " passphrase to use (disables pinentry use)\n"
112 "\n"
113 " --timeout <seconds>\n"
114 " pinentry timeout\n"
115 "\n"
116 " --tries <N>\n"
117 " number of pinentry tries before failing (3)\n"
118 "\n"
119 " --pinentry <path>\n"
120 " the full path to the pinentry binary (server default)\n"
121 "\n"
122 " --ttyname, -y <path>\n"
123 " tty that pinentry will use\n"
124 "\n"
125 " --ttytype, -t <string>\n"
126 " pinentry terminal type (default is TERM)\n"
127 "\n"
128 " --display, -d\n"
129 " pinentry display (default is DISPLAY)\n"
130 "\n"
131 " --lc-ctype <string>\n"
132 " locale setting for pinentry\n"
133 "\n"
134 " --lc-messages <string>\n"
135 " locale setting for pinentry\n"
136 "\n"
138 " --local-pinentry\n"
139 " force using a local pinentry\n"
140 "\n"
141 " --output-fd <FD>\n"
142 " redirect command output to the specified file descriptor\n"
143 "\n"
144 " --inquire-fd <FD>\n"
145 " read inquire data from the specified file descriptor\n"
146 "\n"
147 " --save, -S\n"
148 " send the SAVE command before exiting\n"
149 "\n"
150 " --force-save\n"
151 " like --save, but ask for a passphrase\n"
152 "\n"
153 " --iterations, -I <N>\n"
154 " encrypt with the specified number of iterations when saving\n"
155 "\n"
156 " --version\n"
157 " --help\n"));
158 fprintf(status == EXIT_FAILURE ? stderr : stdout, N_(
159 "\n"
160 "A url string (specified with --url) may be in the form of:\n"
161 " local://[path/to/socket]\n"
162 #ifdef WITH_TCP
163 " ssh[46]://[username@]hostname[:port],identity,known_hosts\n"
164 #endif
166 exit(status);
169 struct inquire_s {
170 FILE *fp;
171 char *data;
174 static gpg_error_t do_inquire(void *data, const char *keyword, gpg_error_t rc,
175 char **result, size_t *result_len)
177 int c;
178 static char buf[ASSUAN_LINELENGTH];
179 char *p;
180 size_t len = 0;
181 struct inquire_s *inq = (struct inquire_s *)data;
183 if (rc) {
184 memset(buf, 0, sizeof(buf));
185 return rc;
188 buf[0] = 0;
189 p = buf;
191 if (inq->data) {
192 snprintf(buf, sizeof(buf), "%s", inq->data);
193 pwmd_free(inq->data);
194 inq->data = NULL;
195 len = strlen(buf);
196 p = buf + len;
199 while ((c = fgetc(inq->fp)) != EOF) {
200 if (len == sizeof(buf)) {
201 ungetc(c, inq->fp);
202 break;
205 *p++ = c;
206 len++;
209 if (!buf[0]) {
210 memset(buf, 0, sizeof(buf));
211 return GPG_ERR_EOF;
214 *result = buf;
215 *result_len = len;
216 return 0;
219 static int status_msg_cb(void *data, const char *line)
221 fprintf(stderr, "%s\n", line);
222 return 0;
225 static gpg_error_t process_cmd(pwm_t *pwm, char **result, int input)
227 gpg_error_t rc;
228 pwmd_async_t s;
230 do {
231 int i, n;
232 fd_set rfds;
233 int nfds = 5;
234 pwmd_fd_t pfds[nfds];
236 FD_ZERO(&rfds);
237 rc = pwmd_get_fds(pwm, pfds, &nfds);
239 if (rc)
240 return rc;
242 if (!nfds)
243 return 0;
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 int main(int argc, char *argv[])
271 int opt;
272 char *password = NULL;
273 char *filename = NULL;
274 char *socketpath = NULL;
275 char command[ASSUAN_LINELENGTH], *p;
276 int ret = EXIT_SUCCESS;
277 gpg_error_t error;
278 char *result = NULL;
279 int save = 0;
280 char *pinentry_path = NULL;
281 char *display = NULL, *tty = NULL, *ttytype = NULL, *lcctype = NULL,
282 *lcmessages = NULL;
283 int outfd = STDOUT_FILENO;
284 FILE *outfp = stdout;
285 int inquirefd = STDIN_FILENO;
286 FILE *inquirefp = stdin;
287 int show_status = 1;
288 char *clientname = "pwmc";
289 char *inquire = NULL;
290 long iter = -2;
291 int have_iter = 0;
292 int timeout = 0;
293 int local_pin = 0;
294 int force_save = 0;
295 #ifdef WITH_TCP
296 char *host = NULL;
297 int port = DEFAULT_PORT;
298 char *username = NULL;
299 char *ident = NULL;
300 char *known_hosts = NULL;
301 int get = 0;
302 int prot = PWMD_IP_ANY;
303 #endif
304 int tries = 0;
305 int local_tries = 3;
306 int try = 0;
307 pwmd_socket_t s;
308 #ifdef DEBUG
309 int method = 0;
310 fd_set rfds;
311 #endif
312 char *url_string = NULL;
313 /* The order is important. */
314 enum {
315 #ifdef DEBUG
316 OPT_DEBUG,
317 #endif
318 #ifdef WITH_TCP
319 OPT_HOST, OPT_PORT, OPT_IDENTITY, OPT_KNOWN_HOSTS, OPT_USER,
320 OPT_GET_HOSTKEY, OPT_IPV4, OPT_IPV6,
321 #endif
322 OPT_URL, OPT_LOCAL, OPT_FORCE_SAVE, OPT_TTYNAME, OPT_TTYTYPE,
323 OPT_DISPLAY, OPT_LC_CTYPE, OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES,
324 OPT_PINENTRY, OPT_PASSPHRASE, OPT_SOCKET, OPT_SAVE, OPT_ITERATIONS,
325 OPT_OUTPUT_FD, OPT_INQUIRE_FD, OPT_NO_STATUS, OPT_NAME, OPT_VERSION,
326 OPT_HELP,
328 const struct option long_opts[] = {
329 #ifdef DEBUG
330 { "debug", 1, 0, 0 },
331 #endif
332 #ifdef WITH_TCP
333 { "host", 1, 0, 'h' },
334 { "port", 1, 0, 'p' },
335 { "identity", 1, 0, 'i' },
336 { "known-hosts", 1, 0, 'k' },
337 { "user", 1, 0, 'u' },
338 { "get-hostkey", 0, 0, 'g' },
339 { "ipv4", 0, 0, '4' },
340 { "ipv6", 0, 0, '6' },
341 #endif
342 { "url", 1, 0, 0 },
343 { "local-pinentry", 0, 0 },
344 { "force-save", 0, 0 },
345 { "ttyname", 1, 0, 'y' },
346 { "ttytype", 1, 0, 't' },
347 { "display", 1, 0, 'd' },
348 { "lc-ctype", 1, 0, 0 },
349 { "lc-messages", 1, 0, 0 },
350 { "timeout", 1, 0, 0 },
351 { "tries", 1, 0, 0 },
352 { "pinentry", 1, 0, 0 },
353 { "passphrase", 1, 0, 'P' },
354 { "socket", 1, 0, 0 },
355 { "save", 0, 0, 'S' },
356 { "iterations", 1, 0, 'I' },
357 { "output-fd", 1, 0, 0 },
358 { "inquire-fd", 1, 0, 0 },
359 { "no-status", 0, 0, 0 },
360 { "name", 1, 0, 'n' },
361 { "version", 0, 0, 0 },
362 { "help", 0, 0, 0 },
363 { 0, 0, 0, 0}
365 #ifdef WITH_TCP
366 const char *optstring = "46h:p:i:k:u:gy:t:d:P:I:Sn:";
367 #else
368 const char *optstring = "y:t:d:P:I:Sn:";
369 #endif
370 int opt_index = 0;
372 #ifdef ENABLE_NLS
373 setlocale(LC_ALL, "");
374 bindtextdomain("libpwmd", LOCALEDIR);
375 #endif
377 while ((opt = getopt_long(argc, argv, optstring, long_opts, &opt_index)) != -1) {
378 switch (opt) {
379 /* Handle long options without a short option part. */
380 case 0:
381 switch (opt_index) {
382 #ifdef DEBUG
383 case OPT_DEBUG:
384 method = atoi(optarg);
386 if (method > 3)
387 method = 3;
388 break;
389 #endif
390 case OPT_URL:
391 url_string = optarg;
392 break;
393 case OPT_LOCAL:
394 local_pin = 1;
395 break;
396 case OPT_FORCE_SAVE:
397 save = force_save = 1;
398 break;
399 case OPT_LC_CTYPE:
400 lcctype = pwmd_strdup(optarg);
401 break;
402 case OPT_LC_MESSAGES:
403 lcmessages = pwmd_strdup(optarg);
404 break;
405 case OPT_TIMEOUT:
406 timeout = atoi(optarg);
407 break;
408 case OPT_TRIES:
409 tries = atoi(optarg);
410 local_tries = tries;
411 break;
412 case OPT_SOCKET:
413 socketpath = pwmd_strdup(optarg);
414 break;
415 case OPT_INQUIRE_FD:
416 inquirefd = atoi(optarg);
417 inquirefp = fdopen(inquirefd, "r");
419 if (!inquirefp) {
420 pwmd_free(password);
421 err(EXIT_FAILURE, "%i", inquirefd);
423 break;
424 case OPT_OUTPUT_FD:
425 outfd = atoi(optarg);
426 outfp = fdopen(outfd, "w");
428 if (!outfp) {
429 pwmd_free(password);
430 err(EXIT_FAILURE, "%i", outfd);
432 break;
433 case OPT_NO_STATUS:
434 show_status = 0;
435 break;
436 case OPT_VERSION:
437 pwmd_free(password);
438 printf("%s (pwmc)\n%s\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
439 exit(EXIT_SUCCESS);
440 case OPT_PINENTRY:
441 pinentry_path = optarg;
442 break;
443 case OPT_HELP:
444 usage(argv[0], EXIT_SUCCESS);
445 default:
446 usage(argv[0], EXIT_FAILURE);
449 break;
450 #ifdef WITH_TCP
451 case '4':
452 prot = PWMD_IPV4;
453 break;
454 case '6':
455 prot = PWMD_IPV6;
456 break;
457 case 'h':
458 host = pwmd_strdup(optarg);
459 break;
460 case 'p':
461 port = atoi(optarg);
462 break;
463 case 'i':
464 ident = pwmd_strdup(optarg);
465 break;
466 case 'u':
467 username = pwmd_strdup(optarg);
468 break;
469 case 'k':
470 known_hosts = pwmd_strdup(optarg);
471 break;
472 case 'g':
473 get = 1;
474 break;
475 #endif
476 case 'y':
477 tty = optarg;
478 break;
479 case 't':
480 ttytype = optarg;
481 break;
482 case 'd':
483 display = optarg;
484 break;
485 case 'S':
486 save = 1;
487 break;
488 case 'I':
489 iter = strtol(optarg, NULL, 10);
490 have_iter = 1;
491 break;
492 case 'P':
493 password = pwmd_strdup(optarg);
494 memset(optarg, 0, strlen(optarg));
495 break;
496 case 'n':
497 clientname = optarg;
498 break;
499 default:
500 pwmd_free(password);
501 usage(argv[0], EXIT_FAILURE);
505 #ifdef DEBUG
506 if (!url_string) {
507 #endif
508 #ifdef WITH_TCP
509 if (host && !get && (!known_hosts || !ident)) {
510 pwmd_free(password);
511 usage(argv[0], EXIT_FAILURE);
514 if (get && !host) {
515 pwmd_free(password);
516 usage(argv[0], EXIT_FAILURE);
518 #endif
519 #ifdef DEBUG
521 #endif
523 filename = argv[optind];
524 pwmd_init();
525 pwm = pwmd_new(clientname);
526 #ifdef DEBUG
527 FD_ZERO(&rfds);
528 #endif
530 #ifdef WITH_TCP
531 if (host) {
532 if (prot != PWMD_IP_ANY) {
533 error = pwmd_setopt(pwm, PWMD_OPTION_IP_VERSION, prot);
535 if (error)
536 goto done;
539 #ifdef DEBUG
540 if (method >= 2) {
541 if (get) {
542 char *hostkey;
544 error = pwmd_get_hostkey_async(pwm, host, port);
546 if (error)
547 errx(EXIT_FAILURE, "%s: %s", host, pwmd_strerror(error));
549 error = process_cmd(pwm, &hostkey, 0);
551 if (error)
552 goto done;
554 printf("%s\n", hostkey);
555 pwmd_free(hostkey);
556 pwmd_free(password);
557 pwmd_close(pwm);
558 exit(EXIT_SUCCESS);
561 if (url_string)
562 error = pwmd_connect_url_async(pwm, url_string);
563 else
564 error = pwmd_ssh_connect_async(pwm, host, port, ident, username,
565 known_hosts);
567 if (error)
568 goto done;
570 error = process_cmd(pwm, NULL, 0);
572 if (error)
573 goto done;
575 else {
576 #endif
577 if (get) {
578 char *hostkey;
580 error = pwmd_get_hostkey(pwm, host, port, &hostkey);
582 if (error)
583 goto done;
585 printf("%s\n", hostkey);
586 pwmd_free(hostkey);
587 pwmd_free(password);
588 pwmd_close(pwm);
589 exit(EXIT_SUCCESS);
592 if (url_string)
593 error = pwmd_connect_url(pwm, url_string);
594 else
595 error = pwmd_ssh_connect(pwm, host, port, ident, username, known_hosts);
597 if (error)
598 goto done;
599 #ifdef DEBUG
601 #endif
603 else {
604 #endif
605 if (url_string)
606 error = pwmd_connect_url(pwm, url_string);
607 else
608 error = pwmd_connect(pwm, socketpath);
610 if (error)
611 goto done;
612 #ifdef WITH_TCP
614 #endif
616 error = pwmd_socket_type(pwm, &s);
618 if (error)
619 goto done;
621 if (s == PWMD_SOCKET_SSH && force_save && !local_pin) {
622 error = GPG_ERR_WRONG_KEY_USAGE;
623 goto done;
626 if (have_iter) {
627 error = pwmd_command(pwm, &result, "VERSION");
629 if (error)
630 goto done;
632 pwmd_free(result);
634 if (iter < 0) {
635 pwmd_free(password);
636 pwmd_close(pwm);
637 usage(argv[0], EXIT_FAILURE);
641 if (timeout > 0) {
642 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
644 if (error)
645 goto done;
648 if (local_pin && filename) {
649 error = pwmd_command(pwm, NULL, "ISCACHED %s", filename);
651 if (error == GPG_ERR_NOT_FOUND) {
652 local_password:
653 if (try++ == local_tries)
654 goto done;
656 if (password)
657 pwmd_free(password);
659 password = NULL;
661 if (try > 1)
662 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, 0);
664 error = pwmd_getpin(pwm, filename, &password,
665 try > 1 ? PWMD_PINENTRY_OPEN_FAILED : PWMD_PINENTRY_OPEN);
667 if (error)
668 goto done;
670 error = pwmd_setopt(pwm, PWMD_OPTION_PASSPHRASE, password);
672 if (error)
673 goto done;
675 if (try > 1)
676 goto do_open;
678 else if (error && error != GPG_ERR_ENOENT)
679 goto done;
682 if (password) {
683 error = pwmd_setopt(pwm, PWMD_OPTION_PASSPHRASE, password);
685 if (error)
686 goto done;
688 else {
689 if (pinentry_path) {
690 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
692 if (error)
693 goto done;
696 if (display) {
697 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
699 if (error)
700 goto done;
703 if (tty) {
704 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TTY, tty);
706 if (error)
707 goto done;
710 if (ttytype) {
711 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
713 if (error)
714 goto done;
717 if (lcctype) {
718 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
720 if (error)
721 goto done;
724 if (lcmessages) {
725 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES,
726 lcmessages);
728 if (error)
729 goto done;
732 if (tries > 0) {
733 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
735 if (error)
736 goto done;
740 if (show_status) {
741 error = pwmd_setopt(pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
743 if (error)
744 goto done;
747 do_open:
748 if (filename) {
749 #ifdef DEBUG
750 switch (method) {
751 case 0:
752 error = pwmd_open(pwm, filename);
753 break;
754 case 1:
755 error = pwmd_open2(pwm, filename);
756 break;
757 case 2:
758 error = pwmd_open_async(pwm, filename);
760 break;
761 case 3:
762 error = pwmd_open_async2(pwm, filename);
763 break;
766 if (error && local_pin && error == GPG_ERR_INV_PASSPHRASE)
767 goto local_password;
769 if (error)
770 goto done;
772 if (method >= 2)
773 error = process_cmd(pwm, &result, 0);
774 #else
775 error = pwmd_open(pwm, filename);
777 if (error && local_pin && error == GPG_ERR_INV_PASSPHRASE)
778 goto local_password;
779 #endif
781 if (error)
782 goto done;
785 if (filename) {
786 error = pwmd_command(pwm, &result, "LOCK");
788 if (error)
789 goto done;
792 fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
794 for (;;) {
795 ssize_t n;
797 error = process_cmd(pwm, NULL, 1);
799 if (error)
800 goto done;
802 n = read(STDIN_FILENO, command, sizeof(command));
804 if (n == -1) {
805 if (errno == EAGAIN)
806 continue;
808 error = gpg_error_from_errno(errno);
809 goto done;
811 else if (!n)
812 goto done;
814 command[n] = 0;
816 if (n && command[strlen(command)-1] == '\n')
817 command[strlen(command)-1] = 0;
819 p = command;
820 break;
823 if (!p || !*p)
824 goto done;
827 * This is a known INQUIRE command. We use pwmd_inquire() to send the
828 * data from the do_inquire() callback function.
830 if (strncasecmp(p, "STORE ", 6) == 0) {
831 p += 6;
832 inquire = (char *)"STORE";
834 else if (strncasecmp(p, "IMPORT ", 7) == 0) {
835 p += 7;
836 inquire = (char *)"IMPORT";
839 if (inquire) {
840 struct inquire_s *inq = (struct inquire_s *)pwmd_malloc(sizeof(struct inquire_s));
842 if (!inq) {
843 error = gpg_error_from_errno(ENOMEM);
844 goto done;
847 inq->data = pwmd_strdup(p);
848 inq->fp = inquirefp;
849 error = pwmd_inquire(pwm, inquire, do_inquire, inq);
850 pwmd_free(inq);
851 goto done;
854 if (strcasecmp(p, "BYE") == 0)
855 goto done;
857 error = pwmd_command(pwm, &result, command);
858 memset(command, 0, sizeof(command));
860 if (error)
861 goto done;
863 if (result) {
864 fwrite(result, 1, strlen(result), outfp);
865 pwmd_free(result);
868 done:
869 memset(command, 0, sizeof(command));
870 pwmd_free(password);
871 password = NULL;
873 if (!error && save && filename) {
874 if (iter != -2) {
875 error = pwmd_command(pwm, &result, "SET ITERATIONS=%i", iter);
877 if (error)
878 goto done;
881 if (local_pin) {
882 char *p1;
883 again:
884 if (!force_save) {
885 error = pwmd_command(pwm, NULL, "ISCACHED %s", filename);
887 if (error && error != GPG_ERR_NOT_FOUND &&
888 error != GPG_ERR_ENOENT)
889 goto done;
890 else if (!error)
891 goto do_save;
894 error = pwmd_getpin(pwm, filename, &p1, PWMD_PINENTRY_SAVE);
896 if (error)
897 goto done;
899 error = pwmd_getpin(pwm, filename, &password,
900 PWMD_PINENTRY_SAVE_CONFIRM);
902 if (error) {
903 pwmd_free(p1);
904 goto done;
907 if ((p1 || password) && ((!p1 && password) || (!password && p1) ||
908 strcmp(p1, password))) {
909 pwmd_free(p1);
910 pwmd_free(password);
911 password = NULL;
912 goto again;
915 if (p1)
916 pwmd_free(p1);
918 error = pwmd_setopt(pwm, PWMD_OPTION_PASSPHRASE, password);
920 if (password)
921 pwmd_free(password);
923 if (error)
924 goto done;
927 if (force_save) {
928 error = pwmd_command(pwm, NULL, "CLEARCACHE %s", filename);
930 if (error)
931 goto done;
933 if (!local_pin) {
934 error = pwmd_setopt(pwm, PWMD_OPTION_PASSPHRASE, NULL);
936 if (error)
937 goto done;
941 do_save:
942 #ifdef DEBUG
943 switch (method) {
944 case 0:
945 error = pwmd_save(pwm);
946 break;
947 case 1:
948 error = pwmd_save2(pwm);
949 break;
950 case 2:
951 error = pwmd_save_async(pwm);
952 break;
953 case 3:
954 error = pwmd_save_async2(pwm);
955 break;
958 if (!error && method >= 2)
959 error = process_cmd(pwm, NULL, 0);
961 #else
962 error = pwmd_save(pwm);
963 #endif
966 if (!error && filename)
967 error = pwmd_command(pwm, &result, "UNLOCK");
969 if (error) {
970 show_error(error);
971 ret = EXIT_FAILURE;
974 pwmd_close(pwm);
976 if (socketpath)
977 pwmd_free(socketpath);
979 exit(ret);