pwmc: fix showing duplicate status messages.
[libpwmd.git] / src / pwmc.c
blob35d9c5179af66c1142a659591eb92c85d08b9b14
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012
4 Ben Kibbey <bjk@luxsci.net>
6 This file is part of libpwmd.
8 Libpwmd is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
13 Libpwmd is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Libpwmd. If not, see <http://www.gnu.org/licenses/>.
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <stdint.h>
29 #include <err.h>
30 #include <errno.h>
31 #include <string.h>
32 #include <libpwmd.h>
33 #include <assuan.h>
34 #include <sys/select.h>
35 #include <fcntl.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <libgen.h>
39 #include <termios.h>
40 #include <limits.h>
41 #include <ctype.h>
43 #ifdef HAVE_LOCALE_H
44 #include <locale.h>
45 #endif
47 #ifdef HAVE_GETOPT_LONG
48 #ifdef HAVE_GETOPT_H
49 #include <getopt.h>
50 #endif
51 #else
52 #include "getopt_long.h"
53 #endif
55 #ifdef HAVE_LIBREADLINE
56 #include <readline/readline.h>
57 #include <readline/history.h>
59 static int interactive_error;
60 static int interactive;
61 #endif
63 #ifndef LINE_MAX
64 #define LINE_MAX 2048
65 #endif
67 #include "gettext.h"
68 #define N_(msgid) gettext(msgid)
70 #include "mem.h"
72 #define DEFAULT_PORT 22
73 #define DEFAULT_PIN_TRIES 3
74 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
75 ? gpg_error(rc) : rc
77 static int no_pinentry;
78 static pwm_t *pwm;
79 static char *filename;
80 static int save;
81 static int force_save;
82 static int no_passphrase;
83 static char *cipher;
84 static char *keygrip;
85 static char *sign_keygrip;
86 static char *keyparams;
87 static char *password;
88 static char *keyfile;
89 static char *new_keyfile;
90 static unsigned long s2k_count;
91 static uint64_t iterations;
92 static int iterations_arg;
93 static int tries;
94 static int local_pin;
95 static int inquirefd;
97 struct inquire_s {
98 int fd;
99 char *line;
100 size_t len;
101 size_t size; // from stat(2).
102 int header;
105 static gpg_error_t finalize();
106 static gpg_error_t set_inquire(int fd, const char *line,
107 struct inquire_s **result);
108 static gpg_error_t parse_dotcommand(const char *line, char **result,
109 size_t *len, struct inquire_s *inq);
110 static gpg_error_t open_command(const char *line);
111 #ifdef WITH_SSH
112 static gpg_error_t get_password(char **result, pwmd_pinentry_t w, int echo);
113 #endif
115 static void show_error(gpg_error_t error)
117 fprintf(stderr, "ERR %i %s\n", error, gpg_strerror(error));
120 static void usage(const char *pn, int status)
122 fprintf(status == EXIT_FAILURE ? stderr : stdout, N_(
123 "Read a PWMD protocol command from standard input.\n\n"
124 "Usage: pwmc [options] [file]\n"
125 " --url <string>\n"
126 " a url string to connect to (see below)\n"
127 #ifdef WITH_SSH
128 " --no-ssh-agent\n"
129 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
130 " --identity, -i <filename>\n"
131 " the ssh identity file to use for authentication\n"
132 " --knownhosts, -k <filename>\n"
133 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
134 " --ssh-timeout <seconds>\n"
135 " timeout before a remote command fails (0=disabled, default)\n"
136 " --ssh-keepalive <seconds>\n"
137 " interval to send a keepalive to the remote server (0=disabled, default)\n"
138 #endif
139 #ifdef WITH_GNUTLS
140 " --ca-cert <filename>\n"
141 " certificate authority (CA) used to sign the server cert\n"
142 " --client-cert <filename>\n"
143 " client certificate to use for authentication\n"
144 " --client-key <filename>\n"
145 " key file used to protect the client certificate\n"
146 " --tls-priority <string>\n"
147 " compression, cipher and hash algorithm string (SECURE256)\n"
148 " --tls-verify\n"
149 " verify the hostname against the server certificate\n"
150 #endif
151 " --no-lock\n"
152 " do not lock the data file upon opening it\n"
153 " --no-status\n"
154 " disable showing of status messages from the server\n"
155 " --name, -n <string>\n"
156 " set the client name\n"
157 " --no-passphrase\n"
158 " do not require a passphrase when saving a new file\n"
159 " --keygrip <string>\n"
160 " the hex string of the keygrip to save to\n"
161 " --sign-keygrip <string>\n"
162 " the hex string of the keygrip to sign with\n"
163 " --key-file <filename>\n"
164 " obtain the passphrase from the specified filename\n"
165 " --new-key-file <filename>\n"
166 " obtain the passphrase to save with from the specified filename\n"
167 " --s2k-count <N>\n"
168 " the number of times to hash the passphrase for a new file\n"
169 " --cipher-iterations <N>\n"
170 " the number of times to encrypt the XML data (N+1)\n"
171 " --timeout <seconds>\n"
172 " pinentry timeout\n"
173 " --tries <N>\n"
174 " number of pinentry tries before failing (3)\n"
175 " --no-pinentry\n"
176 " disable pinentry both remotely and locally\n"
177 " --pinentry <path>\n"
178 " the full path to the pinentry binary (server default)\n"
179 " --ttyname, -y <path>\n"
180 " tty that pinentry will use\n"
181 " --ttytype, -t <string>\n"
182 " pinentry terminal type (default is $TERM)\n"
183 " --display, -d\n"
184 " pinentry display (default is $DISPLAY)\n"
185 " --lc-ctype <string>\n"
186 " locale setting for pinentry\n"
187 " --lc-messages <string>\n"
188 " locale setting for pinentry\n"
189 " --local-pinentry\n"
190 " force using a local pinentry\n"
191 #ifdef HAVE_LIBREADLINE
192 " --interactive\n"
193 " use a shell like interface to pwmd (allows more than one command)\n"
194 #endif
195 " --output-fd <FD>\n"
196 " redirect command output to the specified file descriptor\n"
197 " --inquire <COMMAND>\n"
198 " the specified command (with any options) uses a server inquire while\n"
199 " command data is read via the inquire file descriptor (stdin)\n"
200 " --inquire-fd <FD>\n"
201 " read inquire data from the specified file descriptor (stdin)\n"
202 " --inquire-file <filename>\n"
203 " read inquire data from the specified filename\n"
204 " --inquire-line, -L <STRING>\n"
205 " the initial line to send (i.e., element path) before the inquire data\n"
206 " --cipher <string>\n"
207 " the cipher to use when saving (see pwmd(1))\n"
208 " --save, -S\n"
209 " send the SAVE command before exiting\n"
210 " --key-params <string>\n"
211 " the key parameters to use when saving a new file (pwmd default)\n"
212 " --force-save\n"
213 " like --save but always ask for a passphrase\n"
214 " --version\n"
215 " --help\n"));
216 fprintf(status == EXIT_FAILURE ? stderr : stdout, N_(
217 "\n"
218 "An optional url may be in the form of:\n"
219 " --url /path/to/socket\n"
220 " --url file://[path/to/socket]\n"
221 #ifdef WITH_SSH
222 " or\n"
223 " --url ssh[46]://[username@]hostname[:port]\n"
224 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
225 #endif
226 #ifdef WITH_GNUTLS
227 " or\n"
228 " --url tls[46]://hostname[:port]\n"
229 #endif
231 exit(status);
234 static gpg_error_t inquire_cb(void *user, const char *keyword, gpg_error_t rc,
235 char **data, size_t *size)
237 struct inquire_s *inq = user;
238 int is_password = 0;
239 int is_newpassword = 0;
241 *data = NULL;
242 *size = 0;
244 if (rc)
245 return rc;
247 if (!strcmp(keyword, "PASSPHRASE"))
248 is_password = 1;
249 else if (!strcmp(keyword, "NEW_PASSPHRASE"))
250 is_newpassword = 1;
251 #ifdef HAVE_LIBREADLINE
252 else if (!strcmp(keyword, "KEYPARAM") && !interactive) {
253 #else
254 else if (!strcmp(keyword, "KEYPARAM")) {
255 #endif
256 if (!keyparams || !*keyparams)
257 return gpg_error(GPG_ERR_INV_PARAMETER);
259 *data = keyparams;
260 *size = strlen(keyparams);
261 return gpg_error(GPG_ERR_EOF);
264 if ((is_newpassword && new_keyfile) || (is_password && keyfile)) {
265 int fd = open(is_password ? keyfile : new_keyfile, O_RDONLY);
267 if (fd == -1) {
268 fprintf(stderr, "%s: %s\n", is_newpassword ? new_keyfile : keyfile,
269 strerror(errno));
270 return gpg_error_from_syserror();
273 rc = set_inquire(fd, NULL, &inq);
274 if (rc) {
275 close(fd);
276 return rc;
279 fprintf(stderr, N_("Using keyfile '%s' as %s.\n"),
280 is_newpassword ? new_keyfile : keyfile, keyword);
282 if (!new_keyfile || is_newpassword) {
283 pwmd_socket_t t;
285 pwmd_socket_type(pwm, &t);
286 pwmd_setopt(pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
287 if (!no_pinentry && t == PWMD_SOCKET_LOCAL)
288 pwmd_setopt(pwm, PWMD_OPTION_NO_PINENTRY, 0);
291 else if (is_password && !keyfile) {
292 char *tmp;
294 rc = pwmd_password(pwm, keyword, &tmp, &inq->len);
295 if (rc && gpg_err_code(rc) != GPG_ERR_EOF)
296 return rc;
298 pwmd_free(inq->line);
299 inq->line = tmp;
300 *data = inq->line;
301 *size = inq->len;
302 return gpg_error(GPG_ERR_EOF);
304 #ifdef HAVE_LIBREADLINE
305 else if (!inq->header && interactive) {
306 fprintf(stderr, N_(
307 "Press CTRL-D to send the current line. Press twice to end. %s:\n"), keyword);
308 inq->header = 1;
310 #endif
312 /* The first part of the command data. */
313 if (inq->len) {
314 *data = inq->line;
315 *size = inq->len;
316 inq->len = 0;
317 return inq->fd == -1 ? gpg_error(GPG_ERR_EOF) : 0;
320 *size = read(inq->fd, inq->line, ASSUAN_LINELENGTH);
321 if (*size == -1) {
322 *size = 0;
323 return gpg_error(gpg_error_from_syserror());
325 else if (*size)
326 *data = inq->line;
328 if (((is_newpassword && new_keyfile) || (is_password && keyfile))
329 && *size == inq->size)
330 return gpg_error(GPG_ERR_EOF);
332 return *size ? 0 : gpg_error(GPG_ERR_EOF);
335 static int status_msg_cb(void *data, const char *line)
337 char *p = strchr(line, ' ');
339 if (!strcmp(line, "KEEPALIVE"))
340 return 0;
342 if (*line != '#' && p && strchr(p, ' ') && *++p) {
343 char *p1 = strchr(p, ' ');
344 int a = strtol(p, NULL, 10);
346 if (isdigit(*p) && p1) {
347 int b = strtol(p1, NULL, 10);
348 char l[64] = {0};
349 int t = a && b ? a*100/b : 0;
351 strncpy(l, line, strlen(line)-strlen(p)-1);
352 fprintf(stderr, "\r%s %i/%i %i%%%s", l, a, b, t, a == b ? "\n" : "");
353 fflush(stderr);
354 return 0;
358 fprintf(stderr, "%s\n", line);
359 fflush(stderr);
360 return 0;
363 static gpg_error_t process_cmd()
365 return pwmd_process(pwm);
368 #ifdef WITH_SSH
369 static gpg_error_t get_password(char **result, pwmd_pinentry_t w, int echo)
371 char buf[LINE_MAX] = {0}, *p;
372 struct termios told, tnew;
373 char *key = NULL;
375 *result = NULL;
377 if (!isatty(STDIN_FILENO)) {
378 fprintf(stderr, N_("Input is not from a terminal! Failing.\n"));
379 return GPG_ERR_ENOTTY;
382 if (!echo) {
383 if (tcgetattr(STDIN_FILENO, &told) == -1)
384 return gpg_error_from_syserror();
386 memcpy(&tnew, &told, sizeof(struct termios));
387 tnew.c_lflag &= ~(ECHO);
388 tnew.c_lflag |= ICANON|ECHONL;
390 if (tcsetattr(STDIN_FILENO, TCSANOW, &tnew) == -1) {
391 int n = errno;
393 tcsetattr(STDIN_FILENO, TCSANOW, &told);
394 return gpg_error_from_errno(n);
398 switch (w) {
399 case PWMD_PINENTRY_OPEN:
400 fprintf(stderr, N_("Password for %s: "), filename);
401 break;
402 case PWMD_PINENTRY_OPEN_FAILED:
403 fprintf(stderr, N_("Invalid password. Password for %s: "), filename);
404 break;
405 case PWMD_PINENTRY_SAVE:
406 fprintf(stderr, N_("New password for %s: "), filename);
407 break;
408 case PWMD_PINENTRY_SAVE_CONFIRM:
409 fprintf(stderr, N_("Confirm password: "));
410 break;
411 default:
412 break;
415 if ((p = fgets(buf, sizeof(buf), stdin)) == NULL) {
416 tcsetattr(STDIN_FILENO, TCSANOW, &told);
417 return 0;
420 if (!echo)
421 tcsetattr(STDIN_FILENO, TCSANOW, &told);
423 if (feof(stdin)) {
424 clearerr(stdin);
425 return GPG_ERR_CANCELED;
428 p[strlen(p) - 1] = 0;
430 if (buf[0]) {
431 key = pwmd_strdup_printf("%s", p);
432 memset(&buf, 0, sizeof(buf));
434 if (!key)
435 return GPG_ERR_ENOMEM;
438 *result = key;
439 return 0;
442 static gpg_error_t knownhost_cb(void *data, const char *host, const char *key,
443 size_t len)
445 gpg_error_t rc;
446 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);
448 if (no_pinentry && !isatty(STDIN_FILENO)) {
449 fprintf(stderr, N_("Input is not from a terminal! Failing.\n"));
450 pwmd_free(buf);
451 return GPG_ERR_ENOTTY;
453 else if (no_pinentry) {
454 for (char *p = buf, len = 0; *p; p++, len++) {
455 if (*p == '\n')
456 len = 0;
458 if (len == 78) {
459 char *t = p;
461 while (!isspace(*(--p)));
462 *p = '\n';
463 p = t;
464 len = 0;
468 fprintf(stderr, "%s\n\n", buf);
469 pwmd_free(buf);
471 do {
472 char *result;
474 fprintf(stderr, N_("Trust this connection [y/N]: "));
475 fflush(stderr);
476 rc = get_password(&result, PWMD_PINENTRY_CONFIRM, 1);
478 if (rc)
479 return rc;
481 if (!result || !*result || *result == 'n' || *result == 'N') {
482 if (result && *result)
483 pwmd_free(result);
485 return GPG_ERR_NOT_CONFIRMED;
488 if ((*result == 'y' || *result == 'Y') && *(result+1) == 0) {
489 pwmd_free(result);
490 return 0;
492 } while (1);
495 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_DESC, buf);
496 pwmd_free(buf);
498 if (rc)
499 return rc;
501 return pwmd_getpin(pwm, NULL, NULL, NULL, PWMD_PINENTRY_CONFIRM);
503 #endif
505 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
506 static pwmd_socket_t is_remote_url(const char *str)
508 if (!str)
509 return PWMD_SOCKET_LOCAL;
511 #ifdef WITH_SSH
512 if (strstr(str, "ssh://") || strstr(str, "ssh4://")
513 || strstr(str, "ssh6://"))
514 return PWMD_SOCKET_SSH;
515 #endif
517 #ifdef WITH_GNUTLS
518 if (strstr(str, "tls://") || strstr(str, "tls4://")
519 || strstr(str, "tls6://"))
520 return PWMD_SOCKET_TLS;
521 #endif
523 return PWMD_SOCKET_LOCAL;
525 #endif
527 static char *escape(const char *str)
529 const char *p;
530 char *buf = pwmd_malloc(ASSUAN_LINELENGTH+1), *b = buf;
531 size_t len = 0;
533 for (p = str; *p; p++, len++) {
534 if (len == ASSUAN_LINELENGTH)
535 break;
537 if (*p == '\\') {
538 switch (*++p) {
539 case 't':
540 *b++ = '\t';
541 break;
542 case 'n':
543 *b++ = '\n';
544 break;
545 case 'v':
546 *b++ = '\v';
547 break;
548 case 'b':
549 *b++ = '\b';
550 break;
551 case 'f':
552 *b++ = '\f';
553 break;
554 case 'r':
555 *b++ = '\r';
556 break;
557 default:
558 *b++ = *p;
559 break;
562 if (!*p)
563 break;
565 continue;
568 *b++ = *p;
571 *b = 0;
572 return buf;
575 static void free_inquire(struct inquire_s *inq)
577 if (!inq)
578 return;
580 pwmd_free(inq->line);
582 if (inq->fd != -1 && inq->fd != STDIN_FILENO)
583 close(inq->fd);
585 pwmd_free(inq);
588 /* When *result is not NULL it is updated to the new values and not
589 * reallocated. */
590 static gpg_error_t set_inquire(int fd, const char *line,
591 struct inquire_s **result)
593 struct inquire_s inq = {0};
594 struct stat st = {0};
595 gpg_error_t rc;
597 if (fd != -1) {
598 if (fstat(fd, &st) == -1)
599 return gpg_error_from_syserror();
601 inq.size = st.st_size;
604 inq.fd = fd;
605 inq.line = pwmd_calloc(1, ASSUAN_LINELENGTH);
606 if (!inq.line)
607 return GPG_ERR_ENOMEM;
609 if (line) {
610 char *s = escape(line);
612 if (strlen(s) >= ASSUAN_LINELENGTH) {
613 pwmd_free(inq.line);
614 return GPG_ERR_LINE_TOO_LONG;
617 strncpy(inq.line, s, ASSUAN_LINELENGTH-1);
618 inq.len = strlen(s);
619 pwmd_free(s);
622 rc = pwmd_setopt(pwm, PWMD_OPTION_INQUIRE_TOTAL,
623 st.st_size ? st.st_size+strlen(inq.line) : 0);
624 if (rc) {
625 pwmd_free(inq.line);
626 return rc;
629 if (*result == NULL)
630 *result = pwmd_malloc(sizeof(struct inquire_s));
631 else {
632 if ((*result)->fd != -1 && (*result)->fd != STDIN_FILENO)
633 close((*result)->fd);
635 pwmd_free((*result)->line);
636 (*result)->line = NULL;
637 (*result)->fd = -1;
638 (*result)->len = 0;
641 memcpy(*result, &inq, sizeof(struct inquire_s));
642 memset(&inq, 0, sizeof(struct inquire_s));
643 return rc;
646 #ifdef HAVE_LIBREADLINE
647 static int interactive_hook(void)
649 interactive_error = process_cmd();
651 if (interactive_error)
652 rl_event_hook = NULL;
654 return 0;
657 static void print_help()
659 fprintf(stderr, N_(
660 "------------------------------------------------------------------------------\n"
661 "Elements are TAB delimited. Press CTRL-V then TAB to insert from the prompt.\n"
662 "\n"
663 "Type HELP for protocol commands. Type .help for pwmc commands. Press CTRL-D\n"
664 "to quit.\n"
665 "------------------------------------------------------------------------------\n"
668 #endif
670 static char *parse_arg(const char *src, char *dst, size_t len)
672 char *p = dst;
673 const char *s = src;
674 size_t n = 0;
676 for (; s && *s && *s != ' ' && n < len; s++, n++)
677 *p++ = *s;
679 *p = 0;
680 p = dst;
681 return p;
684 static gpg_error_t read_command(const char *line, char **result, size_t *len)
686 const char *p = line;
687 int fd;
688 gpg_error_t rc = GPG_ERR_SYNTAX;
689 char filebuf[ASSUAN_LINELENGTH];
690 char *filename = NULL;
691 struct inquire_s *inq = NULL;
693 if (p && *p && *++p) {
694 filename = parse_arg(p, filebuf, sizeof(filebuf));
695 if (filename && *filename) {
696 p += strlen(filename)+1;
698 while (*p && isspace(*p))
699 p++;
701 if (*p)
702 rc = 0;
706 if (rc) {
707 fprintf(stderr, N_("Usage: .read <filename> <command> [args]\n"));
708 return rc;
711 fd = open(filename, O_RDONLY);
712 if (fd == -1)
713 return gpg_error_from_syserror();
715 rc = set_inquire(fd, NULL, &inq);
716 if (rc) {
717 close(fd);
718 return rc;
721 inq->header = 1;
722 rc = pwmd_command(pwm, result, len, inquire_cb, inq, p);
723 free_inquire(inq);
724 return rc;
727 static gpg_error_t redir_command(const char *line)
729 const char *p = line;
730 int fd;
731 gpg_error_t rc = GPG_ERR_SYNTAX;
732 char filebuf[ASSUAN_LINELENGTH];
733 char *filename = NULL;
734 struct inquire_s *inq = NULL;
735 char *result = NULL;
736 size_t len = 0;
738 if (p && *p && *++p) {
739 filename = parse_arg(p, filebuf, sizeof(filebuf));
740 if (filename && *filename) {
741 p += strlen(filename)+1;
743 while (*p && isspace(*p))
744 p++;
746 if (*p)
747 rc = 0;
751 if (rc) {
752 fprintf(stderr, N_("Usage: .redir <filename> <command> [args]\n"));
753 return rc;
756 fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0600);
757 if (fd == -1)
758 return gpg_error_from_syserror();
760 #ifdef HAVE_LIBREADLINE
761 rc = set_inquire(interactive ? STDIN_FILENO : inquirefd, NULL, &inq);
762 #else
763 rc = set_inquire(inquirefd, NULL, &inq);
764 #endif
765 if (rc) {
766 close(fd);
767 return rc;
770 rc = parse_dotcommand(p, &result, &len, inq);
771 if (!rc && result && len--) { // null byte which is always appended
772 if (write(fd, result, len) != len)
773 rc = GPG_ERR_TOO_SHORT;
774 pwmd_free(result);
777 free_inquire(inq);
778 close(fd);
779 return rc;
782 static gpg_error_t help_command(const char *line)
784 fprintf(stderr, N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
785 " .redir <filename> <command>\n"
786 " redirect the output of a command to the specified file\n"
787 "\n"
788 " .open <filename>\n"
789 " open the specified filename losing any changes to the current one\n"
790 "\n"
791 " .read <filename> <command> [args]\n"
792 " obtain data from the specified filename for an inquire command\n"
793 "\n"
794 " .set help | <name> [<value>]\n"
795 " set option <name> to <value>\n"
796 "\n"
797 " .help\n"
798 " this help text\n"));
799 return 0;
802 static gpg_error_t open_command(const char *line)
804 struct inquire_s *inq = NULL;
805 const char *filename = line;
806 gpg_error_t rc;
808 while (filename && isspace(*filename))
809 filename++;
811 if (!filename || !*filename) {
812 fprintf(stderr, N_("Usage: .open <filename>\n"));
813 return GPG_ERR_SYNTAX;
816 fprintf(stderr, N_("Opening data file \"%s\" ...\n"), filename);
817 #ifdef HAVE_LIBREADLINE
818 rc = set_inquire(interactive ? STDIN_FILENO : -1, NULL, &inq);
819 #else
820 rc = set_inquire(-1, NULL, &inq);
821 #endif
822 if (rc)
823 return rc;
825 if (keyfile)
826 pwmd_setopt(pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
828 #ifdef HAVE_LIBREADLINE
829 // For safety. This file may be a different one. Make the user set it
830 // again if needed.
831 if (interactive) {
832 pwmd_free(new_keyfile);
833 new_keyfile = NULL;
835 #endif
837 rc = pwmd_open(pwm, filename, inquire_cb, inq);
838 free_inquire(inq);
839 return rc;
842 static gpg_error_t set_command(const char *line)
844 gpg_error_t rc = 0;
845 char name[256] = {0};
846 char value[512] = {0};
847 char *namep;
848 char *valuep;
849 const char *p = line;
851 while (p && *p && isspace(*p))
852 p++;
854 namep = parse_arg(p, name, sizeof(name));
855 if (!namep || !*namep) {
856 fprintf(stderr, N_("Usage: .set help | <name> [<value>]\n"));
857 return GPG_ERR_SYNTAX;
860 p += strlen(namep);
861 while (p && *p && isspace(*p))
862 p++;
864 valuep = parse_arg(p, value, sizeof(value));
866 if (!strcmp(name, "keyfile") || !strcmp(name, "new-keyfile")) {
867 int is_newkeyfile = 1;
869 if (!strcmp(name, "keyfile"))
870 is_newkeyfile = 0;
872 if (is_newkeyfile) {
873 pwmd_free(new_keyfile);
874 new_keyfile = NULL;
876 else {
877 pwmd_free(keyfile);
878 keyfile = NULL;
881 if (*valuep) {
882 if (is_newkeyfile)
883 new_keyfile = pwmd_strdup(value);
884 else
885 keyfile = pwmd_strdup(value);
887 rc = pwmd_command(pwm, NULL, NULL, NULL, NULL, "AGENT option pinentry-mode=loopback");
888 if (!rc) {
889 rc = pwmd_setopt(pwm, PWMD_OPTION_NO_PINENTRY, 1);
890 rc = pwmd_setopt(pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
893 else if (!local_pin && !no_pinentry) {
894 pwmd_socket_t t;
896 pwmd_socket_type(pwm, &t);
897 if (t == PWMD_SOCKET_LOCAL) {
898 rc = pwmd_setopt(pwm, PWMD_OPTION_NO_PINENTRY, 0);
899 rc = pwmd_setopt(pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
903 else if (!strcmp(name, "help")) {
904 fprintf(stderr, N_(
905 "Set a libpwmd or pwmc option. The option name and optional value is space\n"
906 "delimited. When no value is specified the option is unset.\n\n"
907 "keyfile [<filename>]\n"
908 " set or unset the keyfile to be used when a passphrase is required\n"
909 "\n"
910 "new-keyfile [<filename>]\n"
911 " set or unset the keyfile to be used when a new passphrase is required\n"
914 else
915 rc = GPG_ERR_UNKNOWN_OPTION;
917 return rc;
920 static gpg_error_t parse_dotcommand(const char *line, char **result,
921 size_t *len, struct inquire_s *inq)
923 const char *p = line;
924 gpg_error_t rc = 0;
926 if (!strncmp(p, ".read", 5))
927 rc = read_command(p+5, result, len);
928 else if (!strncmp(p, ".redir", 6))
929 rc = redir_command(p+6);
930 else if (!strncmp(p, ".help", 5))
931 rc = help_command(p+5);
932 else if (!strncmp(p, ".open", 5))
933 rc = open_command(p+5);
934 else if (!strncmp(p, ".set", 4))
935 rc = set_command(p+4);
936 else
937 rc = pwmd_command(pwm, result, len, inquire_cb, inq, line);
939 return FINISH(rc);
942 #ifdef HAVE_LIBREADLINE
943 static gpg_error_t do_interactive()
945 gpg_error_t rc = process_cmd();
946 struct inquire_s *inq = NULL;
948 if (rc)
949 return rc;
951 rc = set_inquire(STDIN_FILENO, NULL, &inq);
952 if (rc)
953 return rc;
955 fprintf(stderr, N_("WARNING: interactive mode doesn't use secure memory!\n"));
956 print_help();
957 rl_initialize();
958 rl_event_hook = &interactive_hook;
959 rl_set_keyboard_input_timeout(100000);
961 for (;;) {
962 char *line;
963 char *result = NULL;
964 size_t len;
966 line = readline("pwm> ");
967 if (interactive_error) {
968 rc = interactive_error;
969 break;
972 if (!line) {
973 rc = finalize();
974 if (!rc)
975 break;
977 if (gpg_err_code(rc) != GPG_ERR_CANCELED &&
978 gpg_err_code(rc) != GPG_ERR_EOF)
979 fprintf(stderr, "ERR %i: %s\n", rc, gpg_strerror(rc));
981 continue;
983 else if (!*line) {
984 free(line);
985 continue;
988 #ifdef HAVE_LIBREADLINE
989 add_history(line);
990 #endif
991 inq->header = 0;
992 rc = parse_dotcommand(line, &result, &len, inq);
993 free(line);
994 if (rc)
995 fprintf(stderr, "ERR %i: %s\n", rc, gpg_strerror(rc));
996 else if (result && len)
997 printf("%s%s", result, result[len-1] != '\n' ? "\n" : "");
999 pwmd_free(result);
1002 free_inquire(inq);
1003 return 0;
1005 #endif
1007 static char *itoa(long long int n)
1009 static char buf[64];
1011 snprintf(buf, sizeof(buf), "%llu", n);
1012 return buf;
1015 static gpg_error_t finalize()
1017 gpg_error_t rc = 0;
1018 #ifdef HAVE_LIBREADLINE
1019 int quit = 0;
1021 if (!force_save && interactive) {
1022 char *p, buf[16];
1023 int finished = 0;
1025 fprintf(stderr, "\n");
1027 do {
1028 fprintf(stderr, N_("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1029 p = fgets(buf, sizeof(buf), stdin);
1031 if (feof(stdin)) {
1032 clearerr(stdin);
1033 return GPG_ERR_EOF;
1036 switch (*p) {
1037 case 'h':
1038 print_help();
1039 break;
1040 case 'c':
1041 return GPG_ERR_CANCELED;
1042 case 'Q':
1043 return 0;
1044 case 'f':
1045 rc = pwmd_command(pwm, NULL, NULL, NULL, NULL,
1046 "CLEARCACHE %s", filename);
1047 if (rc)
1048 return rc;
1050 interactive_hook();
1051 break;
1052 case 'S':
1053 quit = 1;
1054 case 's':
1055 save = 1;
1056 finished = 1;
1057 break;
1058 default:
1059 break;
1061 } while (!finished);
1063 #endif
1065 if (save && !filename) {
1066 fprintf(stderr, N_("No filename was specified on the command line. Aborting.\n"));
1067 return GPG_ERR_CANCELED;
1070 if (save && filename) {
1071 char *args = pwmd_strdup_printf("%s%s %s%s %s %s%s %s%s --s2k-count=%lu",
1072 keygrip ? "--keygrip=" : "", keygrip ? keygrip : "",
1073 sign_keygrip ? "--sign-keygrip=" : "", sign_keygrip ? sign_keygrip : "",
1074 no_passphrase ? "--no-passphrase" : "",
1075 cipher ? "--cipher=" : "", cipher ? cipher : "",
1076 iterations_arg ? "--cipher-iterations=" : "", iterations_arg ? itoa(iterations) : "",
1077 s2k_count);
1079 fprintf(stderr, "\n");
1080 fprintf(stderr, N_("Saving changes ...\n"));
1081 rc = pwmd_save(pwm, args, inquire_cb, NULL);
1082 pwmd_free(args);
1084 if (!rc)
1085 no_passphrase = 0; // reset to avoid usage error on the next SAVE
1088 #ifdef HAVE_LIBREADLINE
1089 if (interactive)
1090 return rc ? rc : quit ? 0 : GPG_ERR_CANCELED;
1091 #endif
1093 return rc;
1096 int main(int argc, char *argv[])
1098 int connected = 0;
1099 gpg_error_t rc;
1100 int opt;
1101 char command[ASSUAN_LINELENGTH], *p = NULL;
1102 char *result = NULL;
1103 size_t len;
1104 char *pinentry_path = NULL;
1105 char *display = NULL, *tty = NULL, *ttytype = NULL, *lcctype = NULL,
1106 *lcmessages = NULL;
1107 int outfd = STDOUT_FILENO;
1108 FILE *outfp = stdout;
1109 FILE *inquirefp = stdin;
1110 int show_status = 1;
1111 char *clientname = "pwmc";
1112 char *inquire = NULL;
1113 char *inquire_line = NULL;
1114 int timeout = 0;
1115 #ifdef WITH_SSH
1116 int use_ssh_agent = 1;
1117 long ssh_timeout = 0;
1118 int ssh_keepalive = 0;
1119 char *knownhosts = NULL;
1120 char *identity = NULL;
1121 #endif
1122 #ifdef WITH_GNUTLS
1123 char *cacert = NULL;
1124 char *clientcert = NULL;
1125 char *clientkey = NULL;
1126 char *prio = NULL;
1127 int tls_verify = 0;
1128 #endif
1129 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1130 pwmd_socket_t socktype;
1131 #endif
1132 int lock_on_open = 1;
1133 char *url = NULL;
1134 /* The order is important. */
1135 enum {
1136 #ifdef WITH_SSH
1137 OPT_USE_SSH_AGENT, OPT_IDENTITY, OPT_KNOWNHOSTS, OPT_SSH_TIMEOUT,
1138 OPT_SSH_KEEPALIVE,
1139 #endif
1140 #ifdef WITH_GNUTLS
1141 OPT_CACERT, OPT_CLIENTCERT, OPT_CLIENTKEY, OPT_PRIORITY, OPT_VERIFY,
1142 #endif
1143 OPT_URL, OPT_LOCAL, OPT_FORCE_SAVE, OPT_TTYNAME, OPT_TTYTYPE,
1144 OPT_DISPLAY, OPT_LC_CTYPE, OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES,
1145 OPT_PINENTRY, OPT_KEYFILE, OPT_NEW_KEYFILE, OPT_NOLOCK, OPT_SAVE,
1146 OPT_OUTPUT_FD, OPT_INQUIRE, OPT_INQUIRE_FD, OPT_INQUIRE_FILE,
1147 OPT_INQUIRE_LINE, OPT_NO_STATUS, OPT_NAME, OPT_VERSION, OPT_HELP,
1148 OPT_KEYGRIP, OPT_SIGN_KEYGRIP, OPT_NOPASSPHRASE, OPT_CIPHER,
1149 OPT_KEYPARAMS, OPT_NO_PINENTRY, OPT_S2K_COUNT, OPT_ITERATIONS,
1150 #ifdef HAVE_LIBREADLINE
1151 OPT_INTERACTIVE,
1152 #endif
1154 const struct option long_opts[] = {
1155 #ifdef WITH_SSH
1156 { "no-ssh-agent", 0, 0, 0 },
1157 { "identity", 1, 0, 'i' },
1158 { "knownhosts", 1, 0, 'k' },
1159 { "ssh-timeout", 1, 0, 0 },
1160 { "ssh-keepalive", 1, 0, 0 },
1161 #endif
1162 #ifdef WITH_GNUTLS
1163 { "ca-cert", 1, 0, 0 },
1164 { "client-cert", 1, 0, 0 },
1165 { "client-key", 1, 0, 0 },
1166 { "tls-priority", 1, 0, 0 },
1167 { "tls-verify", 0, 0, 0 },
1168 #endif
1169 { "url", 1, 0, 0 },
1170 { "local-pinentry", 0, 0 },
1171 { "force-save", 0, 0 },
1172 { "ttyname", 1, 0, 'y' },
1173 { "ttytype", 1, 0, 't' },
1174 { "display", 1, 0, 'd' },
1175 { "lc-ctype", 1, 0, 0 },
1176 { "lc-messages", 1, 0, 0 },
1177 { "timeout", 1, 0, 0 },
1178 { "tries", 1, 0, 0 },
1179 { "pinentry", 1, 0, 0 },
1180 { "key-file", 1, 0, 0 },
1181 { "new-key-file", 1, 0, 0 },
1182 { "no-lock", 0, 0, 0 },
1183 { "save", 0, 0, 'S' },
1184 { "output-fd", 1, 0, 0 },
1185 { "inquire", 1, 0, 0 },
1186 { "inquire-fd", 1, 0, 0 },
1187 { "inquire-file", 1, 0, 0 },
1188 { "inquire-line", 1, 0, 'L' },
1189 { "no-status", 0, 0, 0 },
1190 { "name", 1, 0, 'n' },
1191 { "version", 0, 0, 0 },
1192 { "help", 0, 0, 0 },
1193 { "keygrip", 1, 0, 0 },
1194 { "sign-keygrip", 1, 0, 0 },
1195 { "no-passphrase", 0, 0, 0 },
1196 { "cipher", 1, 0, 0 },
1197 { "key-params", 1, 0, 0 },
1198 { "no-pinentry", 0, 0, 0 },
1199 { "s2k-count", 1, 0, 0 },
1200 { "cipher-iterations", 1, 0, 0 },
1201 #ifdef HAVE_LIBREADLINE
1202 { "interactive", 0, 0 },
1203 #endif
1204 { 0, 0, 0, 0}
1206 #ifdef WITH_SSH
1207 const char *optstring = "L:y:t:d:P:I:Sn:i:k:";
1208 #else
1209 const char *optstring = "L:y:t:d:P:I:Sn:";
1210 #endif
1211 int opt_index = 0;
1213 #ifdef ENABLE_NLS
1214 setlocale(LC_ALL, "");
1215 bindtextdomain("libpwmd", LOCALEDIR);
1216 #endif
1218 #ifdef HAVE_LIBREADLINE
1219 if (!strcmp(basename(argv[0]), "pwmsh"))
1220 interactive = 1;
1221 #endif
1223 tries = DEFAULT_PIN_TRIES;
1224 inquirefd = STDIN_FILENO;
1226 while ((opt = getopt_long(argc, argv, optstring, long_opts, &opt_index)) != -1) {
1227 switch (opt) {
1228 /* Handle long options without a short option part. */
1229 case 0:
1230 switch (opt_index) {
1231 #ifdef WITH_SSH
1232 case OPT_USE_SSH_AGENT:
1233 use_ssh_agent = 0;
1234 break;
1235 case OPT_SSH_TIMEOUT:
1236 ssh_timeout = strtol(optarg, &p, 10);
1237 break;
1238 case OPT_SSH_KEEPALIVE:
1239 ssh_keepalive = strtol(optarg, &p, 10);
1240 break;
1241 #endif
1242 #ifdef WITH_GNUTLS
1243 case OPT_CACERT:
1244 cacert = optarg;
1245 break;
1246 case OPT_CLIENTCERT:
1247 clientcert = optarg;
1248 break;
1249 case OPT_CLIENTKEY:
1250 clientkey = optarg;
1251 break;
1252 case OPT_PRIORITY:
1253 prio = optarg;
1254 break;
1255 case OPT_VERIFY:
1256 tls_verify = 1;
1257 break;
1258 #endif
1259 case OPT_KEYPARAMS:
1260 keyparams = optarg;
1261 break;
1262 case OPT_KEYFILE:
1263 keyfile = pwmd_strdup(optarg);
1264 break;
1265 case OPT_NEW_KEYFILE:
1266 new_keyfile = pwmd_strdup(optarg);
1267 break;
1268 case OPT_NOLOCK:
1269 lock_on_open = 0;
1270 break;
1271 case OPT_URL:
1272 url = optarg;
1273 break;
1274 case OPT_LOCAL:
1275 local_pin = 1;
1276 break;
1277 case OPT_FORCE_SAVE:
1278 save = force_save = 1;
1279 break;
1280 case OPT_LC_CTYPE:
1281 lcctype = pwmd_strdup(optarg);
1282 break;
1283 case OPT_LC_MESSAGES:
1284 lcmessages = pwmd_strdup(optarg);
1285 break;
1286 case OPT_TIMEOUT:
1287 timeout = strtol(optarg, &p, 10);
1288 break;
1289 case OPT_TRIES:
1290 tries = strtol(optarg, &p, 10);
1291 break;
1292 case OPT_INQUIRE:
1293 inquire = optarg;
1294 break;
1295 case OPT_INQUIRE_FD:
1296 inquirefd = strtol(optarg, &p, 10);
1297 if (!p) {
1298 inquirefp = fdopen(inquirefd, "r");
1299 if (!inquirefp) {
1300 pwmd_free(password);
1301 err(EXIT_FAILURE, "%i", inquirefd);
1304 break;
1305 case OPT_INQUIRE_FILE:
1306 inquirefd = open(optarg, O_RDONLY);
1307 if (!inquirefd == -1) {
1308 pwmd_free(password);
1309 err(EXIT_FAILURE, "%s", optarg);
1311 inquirefp = fdopen(inquirefd, "r");
1312 break;
1313 case OPT_OUTPUT_FD:
1314 outfd = strtol(optarg, &p, 10);
1315 if (!p) {
1316 outfp = fdopen(outfd, "w");
1317 if (!outfp) {
1318 pwmd_free(password);
1319 err(EXIT_FAILURE, "%i", outfd);
1322 break;
1323 case OPT_NO_STATUS:
1324 show_status = 0;
1325 break;
1326 case OPT_VERSION:
1327 pwmd_free(password);
1328 printf("%s (pwmc)\n\n"
1329 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012\n"
1330 "%s\n"
1331 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1332 "Compile-time features:\n"
1333 #ifdef WITH_SSH
1334 "+SSH "
1335 #else
1336 "-SSH "
1337 #endif
1338 #ifdef WITH_GNUTLS
1339 "+GNUTLS "
1340 #else
1341 "-GNUTLS "
1342 #endif
1343 #ifdef WITH_PINENTRY
1344 "+PINENTRY "
1345 #else
1346 "-PINENTRY "
1347 #endif
1348 #ifdef WITH_QUALITY
1349 "+CRACK "
1350 #else
1351 "-CRACK "
1352 #endif
1353 #ifdef MEM_DEBUG
1354 "+MEM_DEBUG "
1355 #else
1356 "-MEM_DEBUG "
1357 #endif
1358 #ifdef HAVE_LIBREADLINE
1359 "+INTERACTIVE "
1360 #else
1361 "-INTERACTIVE "
1362 #endif
1363 "\n"
1364 , PACKAGE_STRING, PACKAGE_BUGREPORT);
1365 exit(EXIT_SUCCESS);
1366 case OPT_PINENTRY:
1367 pinentry_path = optarg;
1368 break;
1369 case OPT_HELP:
1370 usage(argv[0], EXIT_SUCCESS);
1371 case OPT_KEYGRIP:
1372 keygrip = optarg;
1373 break;
1374 case OPT_SIGN_KEYGRIP:
1375 sign_keygrip = optarg;
1376 break;
1377 case OPT_S2K_COUNT:
1378 s2k_count = strtoul(optarg, &p, 10);
1379 break;
1380 case OPT_ITERATIONS:
1381 iterations = strtoull(optarg, &p, 10);
1382 iterations_arg = 1;
1383 break;
1384 case OPT_NOPASSPHRASE:
1385 no_passphrase = 1;
1386 break;
1387 case OPT_CIPHER:
1388 cipher = optarg;
1389 break;
1390 case OPT_NO_PINENTRY:
1391 no_pinentry = 1;
1392 break;
1393 #ifdef HAVE_LIBREADLINE
1394 case OPT_INTERACTIVE:
1395 interactive = 1;
1396 break;
1397 #endif
1398 default:
1399 usage(argv[0], EXIT_FAILURE);
1402 if (p && *p) {
1403 fprintf(stderr, N_("%s: invalid argument for option '--%s'\n"),
1404 argv[0], long_opts[opt_index].name);
1405 usage(argv[0], EXIT_FAILURE);
1408 break;
1409 #ifdef WITH_SSH
1410 case 'i':
1411 identity = optarg;
1412 break;
1413 case 'k':
1414 knownhosts = optarg;
1415 break;
1416 #endif
1417 case 'L':
1418 inquire_line = optarg;
1419 break;
1420 case 'y':
1421 tty = optarg;
1422 break;
1423 case 't':
1424 ttytype = optarg;
1425 break;
1426 case 'd':
1427 display = optarg;
1428 break;
1429 case 'S':
1430 save = 1;
1431 break;
1432 case 'n':
1433 clientname = optarg;
1434 break;
1435 default:
1436 pwmd_free(password);
1437 usage(argv[0], EXIT_FAILURE);
1441 #ifdef HAVE_LIBREADLINE
1442 if (interactive && !isatty(STDIN_FILENO)) {
1443 pwmd_free(password);
1444 usage(argv[0], EXIT_FAILURE);
1446 else if (isatty(STDIN_FILENO) && !inquire && !inquire_line)
1447 interactive = 1;
1448 #endif
1450 filename = argv[optind];
1451 #ifdef WITH_GNUTLS
1452 gnutls_global_set_mem_functions(pwmd_malloc, pwmd_malloc, NULL,
1453 pwmd_realloc, pwmd_free);
1454 #endif
1455 pwmd_init();
1456 rc = pwmd_new(clientname, &pwm);
1457 if (rc)
1458 goto done;
1460 pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
1461 fprintf(stderr, N_("Connecting ...\n"));
1463 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1464 socktype = is_remote_url(url);
1465 if (socktype != PWMD_SOCKET_LOCAL) {
1466 local_pin = 1;
1467 if (socktype == PWMD_SOCKET_SSH) {
1468 #ifdef WITH_SSH
1469 rc = pwmd_setopt(pwm, PWMD_OPTION_KNOWNHOST_CB, knownhost_cb);
1470 if (rc)
1471 goto done;
1473 rc = pwmd_setopt(pwm, PWMD_OPTION_KNOWNHOST_DATA, clientname);
1474 if (rc)
1475 goto done;
1477 if (!getenv("SSH_AUTH_SOCK") || identity)
1478 use_ssh_agent = 0;
1480 rc = pwmd_setopt(pwm, PWMD_OPTION_SSH_AGENT, use_ssh_agent);
1481 if (rc)
1482 goto done;
1484 rc = pwmd_setopt(pwm, PWMD_OPTION_SSH_TIMEOUT, ssh_timeout);
1485 if (rc)
1486 goto done;
1488 rc = pwmd_setopt(pwm, PWMD_OPTION_SSH_KEEPALIVE, ssh_keepalive);
1489 if (rc)
1490 goto done;
1492 rc = pwmd_connect(pwm, url, identity, knownhosts);
1493 #endif
1495 #ifdef WITH_GNUTLS
1496 else {
1497 rc = pwmd_setopt(pwm, PWMD_OPTION_TLS_VERIFY, tls_verify);
1498 if (rc)
1499 goto done;
1501 rc = pwmd_connect(pwm, url, clientcert, clientkey, cacert, prio);
1503 #endif
1505 else
1506 rc = pwmd_connect(pwm, url);
1507 #else
1508 rc = pwmd_connect(pwm, url);
1509 #endif
1510 if (rc)
1511 goto done;
1513 fprintf(stderr, N_("Connected.\n"));
1514 connected = 1;
1515 if (lock_on_open) {
1516 rc = pwmd_setopt(pwm, PWMD_OPTION_LOCK_ON_OPEN, 1);
1517 if (rc)
1518 goto done;
1521 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_DESC, NULL);
1522 if (rc)
1523 goto done;
1525 if (timeout > 0) {
1526 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
1527 if (rc)
1528 goto done;
1531 rc = pwmd_setopt(pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1532 if (rc)
1533 goto done;
1535 rc = pwmd_setopt(pwm, PWMD_OPTION_LOCAL_PINENTRY,
1536 (local_pin || keyfile || new_keyfile));
1537 if (rc)
1538 goto done;
1540 if (pinentry_path) {
1541 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
1542 if (rc)
1543 goto done;
1546 if (display) {
1547 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
1548 if (rc)
1549 goto done;
1552 if (tty) {
1553 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TTY, tty);
1554 if (rc)
1555 goto done;
1558 if (ttytype) {
1559 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
1560 if (rc)
1561 goto done;
1564 if (lcctype) {
1565 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
1566 if (rc)
1567 goto done;
1570 if (lcmessages) {
1571 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES,
1572 lcmessages);
1573 if (rc)
1574 goto done;
1577 if (show_status) {
1578 rc = pwmd_setopt(pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
1579 if (rc)
1580 goto done;
1583 if (filename) {
1584 rc = open_command(filename);
1585 if (rc)
1586 goto done;
1589 #ifdef HAVE_LIBREADLINE
1590 if (interactive) {
1591 if (!force_save)
1592 save = 0;
1594 rc = do_interactive();
1595 goto do_exit;
1597 #endif
1599 if (inquire) {
1600 struct inquire_s *inq = NULL;
1602 rc = set_inquire(inquirefd, inquire_line, &inq);
1603 if (!rc)
1604 rc = pwmd_command(pwm, &result, &len, inquire_cb, inq, inquire);
1606 free_inquire(inq);
1607 goto done;
1610 fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
1611 ssize_t n;
1613 for (;;) {
1614 rc = process_cmd();
1616 if (rc)
1617 goto done;
1619 n = read(STDIN_FILENO, command, sizeof(command));
1620 if (n == -1) {
1621 if (errno == EAGAIN) {
1622 usleep(100000);
1623 continue;
1626 rc = gpg_error_from_errno(errno);
1627 goto done;
1629 else if (!n)
1630 goto done;
1632 p = command;
1633 command[n] = 0;
1634 break;
1637 if (!p || !*p || !strcasecmp(p, "BYE"))
1638 goto done;
1641 struct inquire_s *inq = NULL;
1642 rc = set_inquire(inquirefd, inquire_line, &inq);
1643 if (!rc) {
1644 rc = parse_dotcommand(command, &result, &len, inq);
1645 free_inquire(inq);
1648 if (rc)
1649 goto done;
1651 done:
1652 if (result) {
1653 fwrite(result, 1, result[len-1] == 0 ? len-1 : len, outfp);
1654 fflush(outfp);
1655 pwmd_free(result);
1658 pwmd_free(password);
1659 password = NULL;
1660 if (!rc)
1661 rc = finalize();
1663 #ifdef HAVE_LIBREADLINE
1664 do_exit:
1665 #endif
1666 memset(command, 0, sizeof(command));
1667 pwmd_close(pwm);
1668 pwmd_free(keyfile);
1669 pwmd_free(new_keyfile);
1670 pwmd_deinit();
1672 if (rc)
1673 show_error(rc);
1675 if (connected)
1676 fprintf(stderr, N_("Connection closed.\n"));
1678 exit(rc ? EXIT_FAILURE : EXIT_SUCCESS);