pwmc: let --lock-timeout accept -1 as an argument.
[libpwmd.git] / src / pwmc.c
blob56a76c07d7ee2fcb49945179d073f2705c2074ac
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 " --lock-timeout <N>\n"
154 " time in tenths of a second to wait for a locked data file\n"
155 " --no-status\n"
156 " disable showing of status messages from the server\n"
157 " --name, -n <string>\n"
158 " set the client name\n"
159 " --no-passphrase\n"
160 " do not require a passphrase when saving a new file\n"
161 " --keygrip <string>\n"
162 " the hex string of the keygrip to save to\n"
163 " --sign-keygrip <string>\n"
164 " the hex string of the keygrip to sign with\n"
165 " --key-file <filename>\n"
166 " obtain the passphrase from the specified filename\n"
167 " --new-key-file <filename>\n"
168 " obtain the passphrase to save with from the specified filename\n"
169 " --s2k-count <N>\n"
170 " the number of times to hash the passphrase for a new file\n"
171 " --cipher-iterations <N>\n"
172 " the number of times to encrypt the XML data (N+1)\n"
173 " --timeout <seconds>\n"
174 " pinentry timeout\n"
175 " --tries <N>\n"
176 " number of pinentry tries before failing (3)\n"
177 " --no-pinentry\n"
178 " disable pinentry both remotely and locally\n"
179 " --pinentry <path>\n"
180 " the full path to the pinentry binary (server default)\n"
181 " --ttyname, -y <path>\n"
182 " tty that pinentry will use\n"
183 " --ttytype, -t <string>\n"
184 " pinentry terminal type (default is $TERM)\n"
185 " --display, -d\n"
186 " pinentry display (default is $DISPLAY)\n"
187 " --lc-ctype <string>\n"
188 " locale setting for pinentry\n"
189 " --lc-messages <string>\n"
190 " locale setting for pinentry\n"
191 " --local-pinentry\n"
192 " force using a local pinentry\n"
193 #ifdef HAVE_LIBREADLINE
194 " --interactive\n"
195 " use a shell like interface to pwmd (allows more than one command)\n"
196 #endif
197 " --output-fd <FD>\n"
198 " redirect command output to the specified file descriptor\n"
199 " --inquire <COMMAND>\n"
200 " the specified command (with any options) uses a server inquire while\n"
201 " command data is read via the inquire file descriptor (stdin)\n"
202 " --inquire-fd <FD>\n"
203 " read inquire data from the specified file descriptor (stdin)\n"
204 " --inquire-file <filename>\n"
205 " read inquire data from the specified filename\n"
206 " --inquire-line, -L <STRING>\n"
207 " the initial line to send (i.e., element path) before the inquire data\n"
208 " --cipher <string>\n"
209 " the cipher to use when saving (see pwmd(1))\n"
210 " --save, -S\n"
211 " send the SAVE command before exiting\n"
212 " --key-params <string>\n"
213 " the key parameters to use when saving a new file (pwmd default)\n"
214 " --force-save\n"
215 " like --save but always ask for a passphrase\n"
216 " --version\n"
217 " --help\n"));
218 fprintf(status == EXIT_FAILURE ? stderr : stdout, N_(
219 "\n"
220 "An optional url may be in the form of:\n"
221 " --url /path/to/socket\n"
222 " --url file://[path/to/socket]\n"
223 #ifdef WITH_SSH
224 " or\n"
225 " --url ssh[46]://[username@]hostname[:port]\n"
226 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
227 #endif
228 #ifdef WITH_GNUTLS
229 " or\n"
230 " --url tls[46]://hostname[:port]\n"
231 #endif
233 exit(status);
236 static gpg_error_t inquire_cb(void *user, const char *keyword, gpg_error_t rc,
237 char **data, size_t *size)
239 struct inquire_s *inq = user;
240 int is_password = 0;
241 int is_newpassword = 0;
243 *data = NULL;
244 *size = 0;
246 if (rc)
247 return rc;
249 if (!strcmp(keyword, "PASSPHRASE"))
250 is_password = 1;
251 else if (!strcmp(keyword, "NEW_PASSPHRASE"))
252 is_newpassword = 1;
253 #ifdef HAVE_LIBREADLINE
254 else if (!strcmp(keyword, "KEYPARAM") && !interactive) {
255 #else
256 else if (!strcmp(keyword, "KEYPARAM")) {
257 #endif
258 if (!keyparams || !*keyparams)
259 return gpg_error(GPG_ERR_INV_PARAMETER);
261 *data = keyparams;
262 *size = strlen(keyparams);
263 return gpg_error(GPG_ERR_EOF);
266 if ((is_newpassword && new_keyfile) || (is_password && keyfile)) {
267 int fd = open(is_password ? keyfile : new_keyfile, O_RDONLY);
269 if (fd == -1) {
270 fprintf(stderr, "%s: %s\n", is_newpassword ? new_keyfile : keyfile,
271 strerror(errno));
272 return gpg_error_from_syserror();
275 rc = set_inquire(fd, NULL, &inq);
276 if (rc) {
277 close(fd);
278 return rc;
281 fprintf(stderr, N_("Using keyfile '%s' as %s.\n"),
282 is_newpassword ? new_keyfile : keyfile, keyword);
284 if (!new_keyfile || is_newpassword) {
285 pwmd_socket_t t;
287 pwmd_socket_type(pwm, &t);
288 pwmd_setopt(pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
289 if (!no_pinentry && t == PWMD_SOCKET_LOCAL)
290 pwmd_setopt(pwm, PWMD_OPTION_NO_PINENTRY, 0);
293 else if (is_password && !keyfile) {
294 char *tmp;
296 rc = pwmd_password(pwm, keyword, &tmp, &inq->len);
297 if (rc && gpg_err_code(rc) != GPG_ERR_EOF)
298 return rc;
300 pwmd_free(inq->line);
301 inq->line = tmp;
302 *data = inq->line;
303 *size = inq->len;
304 return gpg_error(GPG_ERR_EOF);
306 #ifdef HAVE_LIBREADLINE
307 else if (!inq->header && interactive) {
308 fprintf(stderr, N_(
309 "Press CTRL-D to send the current line. Press twice to end. %s:\n"), keyword);
310 inq->header = 1;
312 #endif
314 /* The first part of the command data. */
315 if (inq->len) {
316 *data = inq->line;
317 *size = inq->len;
318 inq->len = 0;
319 return inq->fd == -1 ? gpg_error(GPG_ERR_EOF) : 0;
322 *size = read(inq->fd, inq->line, ASSUAN_LINELENGTH);
323 if (*size == -1) {
324 *size = 0;
325 return gpg_error(gpg_error_from_syserror());
327 else if (*size)
328 *data = inq->line;
330 if (((is_newpassword && new_keyfile) || (is_password && keyfile))
331 && *size == inq->size)
332 return gpg_error(GPG_ERR_EOF);
334 return *size ? 0 : gpg_error(GPG_ERR_EOF);
337 static int status_msg_cb(void *data, const char *line)
339 char *p = strchr(line, ' ');
341 if (!strcmp(line, "KEEPALIVE"))
342 return 0;
344 if (*line != '#' && p && strchr(p, ' ') && *++p) {
345 char *p1 = strchr(p, ' ');
346 int a = strtol(p, NULL, 10);
348 if (isdigit(*p) && p1) {
349 int b = strtol(p1, NULL, 10);
350 char l[64] = {0};
351 int t = a && b ? a*100/b : 0;
353 strncpy(l, line, strlen(line)-strlen(p)-1);
354 fprintf(stderr, "\r%s %i/%i %i%%%s", l, a, b, t, a == b ? "\n" : "");
355 fflush(stderr);
356 return 0;
360 fprintf(stderr, "%s\n", line);
361 fflush(stderr);
362 rl_on_new_line();
363 return 0;
366 static gpg_error_t process_cmd()
368 return pwmd_process(pwm);
371 #ifdef WITH_SSH
372 static gpg_error_t get_password(char **result, pwmd_pinentry_t w, int echo)
374 char buf[LINE_MAX] = {0}, *p;
375 struct termios told, tnew;
376 char *key = NULL;
378 *result = NULL;
380 if (!isatty(STDIN_FILENO)) {
381 fprintf(stderr, N_("Input is not from a terminal! Failing.\n"));
382 return GPG_ERR_ENOTTY;
385 if (!echo) {
386 if (tcgetattr(STDIN_FILENO, &told) == -1)
387 return gpg_error_from_syserror();
389 memcpy(&tnew, &told, sizeof(struct termios));
390 tnew.c_lflag &= ~(ECHO);
391 tnew.c_lflag |= ICANON|ECHONL;
393 if (tcsetattr(STDIN_FILENO, TCSANOW, &tnew) == -1) {
394 int n = errno;
396 tcsetattr(STDIN_FILENO, TCSANOW, &told);
397 return gpg_error_from_errno(n);
401 switch (w) {
402 case PWMD_PINENTRY_OPEN:
403 fprintf(stderr, N_("Password for %s: "), filename);
404 break;
405 case PWMD_PINENTRY_OPEN_FAILED:
406 fprintf(stderr, N_("Invalid password. Password for %s: "), filename);
407 break;
408 case PWMD_PINENTRY_SAVE:
409 fprintf(stderr, N_("New password for %s: "), filename);
410 break;
411 case PWMD_PINENTRY_SAVE_CONFIRM:
412 fprintf(stderr, N_("Confirm password: "));
413 break;
414 default:
415 break;
418 if ((p = fgets(buf, sizeof(buf), stdin)) == NULL) {
419 tcsetattr(STDIN_FILENO, TCSANOW, &told);
420 return 0;
423 if (!echo)
424 tcsetattr(STDIN_FILENO, TCSANOW, &told);
426 if (feof(stdin)) {
427 clearerr(stdin);
428 return GPG_ERR_CANCELED;
431 p[strlen(p) - 1] = 0;
433 if (buf[0]) {
434 key = pwmd_strdup_printf("%s", p);
435 memset(&buf, 0, sizeof(buf));
437 if (!key)
438 return GPG_ERR_ENOMEM;
441 *result = key;
442 return 0;
445 static gpg_error_t knownhost_cb(void *data, const char *host, const char *key,
446 size_t len)
448 gpg_error_t rc;
449 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);
451 if (no_pinentry && !isatty(STDIN_FILENO)) {
452 fprintf(stderr, N_("Input is not from a terminal! Failing.\n"));
453 pwmd_free(buf);
454 return GPG_ERR_ENOTTY;
456 else if (no_pinentry) {
457 for (char *p = buf, len = 0; *p; p++, len++) {
458 if (*p == '\n')
459 len = 0;
461 if (len == 78) {
462 char *t = p;
464 while (!isspace(*(--p)));
465 *p = '\n';
466 p = t;
467 len = 0;
471 fprintf(stderr, "%s\n\n", buf);
472 pwmd_free(buf);
474 do {
475 char *result;
477 fprintf(stderr, N_("Trust this connection [y/N]: "));
478 fflush(stderr);
479 rc = get_password(&result, PWMD_PINENTRY_CONFIRM, 1);
481 if (rc)
482 return rc;
484 if (!result || !*result || *result == 'n' || *result == 'N') {
485 if (result && *result)
486 pwmd_free(result);
488 return GPG_ERR_NOT_CONFIRMED;
491 if ((*result == 'y' || *result == 'Y') && *(result+1) == 0) {
492 pwmd_free(result);
493 return 0;
495 } while (1);
498 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_DESC, buf);
499 pwmd_free(buf);
501 if (rc)
502 return rc;
504 return pwmd_getpin(pwm, NULL, NULL, NULL, PWMD_PINENTRY_CONFIRM);
506 #endif
508 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
509 static pwmd_socket_t is_remote_url(const char *str)
511 if (!str)
512 return PWMD_SOCKET_LOCAL;
514 #ifdef WITH_SSH
515 if (strstr(str, "ssh://") || strstr(str, "ssh4://")
516 || strstr(str, "ssh6://"))
517 return PWMD_SOCKET_SSH;
518 #endif
520 #ifdef WITH_GNUTLS
521 if (strstr(str, "tls://") || strstr(str, "tls4://")
522 || strstr(str, "tls6://"))
523 return PWMD_SOCKET_TLS;
524 #endif
526 return PWMD_SOCKET_LOCAL;
528 #endif
530 static char *escape(const char *str)
532 const char *p;
533 char *buf = pwmd_malloc(ASSUAN_LINELENGTH+1), *b = buf;
534 size_t len = 0;
536 for (p = str; *p; p++, len++) {
537 if (len == ASSUAN_LINELENGTH)
538 break;
540 if (*p == '\\') {
541 switch (*++p) {
542 case 't':
543 *b++ = '\t';
544 break;
545 case 'n':
546 *b++ = '\n';
547 break;
548 case 'v':
549 *b++ = '\v';
550 break;
551 case 'b':
552 *b++ = '\b';
553 break;
554 case 'f':
555 *b++ = '\f';
556 break;
557 case 'r':
558 *b++ = '\r';
559 break;
560 default:
561 *b++ = *p;
562 break;
565 if (!*p)
566 break;
568 continue;
571 *b++ = *p;
574 *b = 0;
575 return buf;
578 static void free_inquire(struct inquire_s *inq)
580 if (!inq)
581 return;
583 pwmd_free(inq->line);
585 if (inq->fd != -1 && inq->fd != STDIN_FILENO)
586 close(inq->fd);
588 pwmd_free(inq);
591 /* When *result is not NULL it is updated to the new values and not
592 * reallocated. */
593 static gpg_error_t set_inquire(int fd, const char *line,
594 struct inquire_s **result)
596 struct inquire_s inq = {0};
597 struct stat st = {0};
598 gpg_error_t rc;
600 if (fd != -1) {
601 if (fstat(fd, &st) == -1)
602 return gpg_error_from_syserror();
604 inq.size = st.st_size;
607 inq.fd = fd;
608 inq.line = pwmd_calloc(1, ASSUAN_LINELENGTH);
609 if (!inq.line)
610 return GPG_ERR_ENOMEM;
612 if (line) {
613 char *s = escape(line);
615 if (strlen(s) >= ASSUAN_LINELENGTH) {
616 pwmd_free(inq.line);
617 return GPG_ERR_LINE_TOO_LONG;
620 strncpy(inq.line, s, ASSUAN_LINELENGTH-1);
621 inq.len = strlen(s);
622 pwmd_free(s);
625 rc = pwmd_setopt(pwm, PWMD_OPTION_INQUIRE_TOTAL,
626 st.st_size ? st.st_size+strlen(inq.line) : 0);
627 if (rc) {
628 pwmd_free(inq.line);
629 return rc;
632 if (*result == NULL)
633 *result = pwmd_malloc(sizeof(struct inquire_s));
634 else {
635 if ((*result)->fd != -1 && (*result)->fd != STDIN_FILENO)
636 close((*result)->fd);
638 pwmd_free((*result)->line);
639 (*result)->line = NULL;
640 (*result)->fd = -1;
641 (*result)->len = 0;
644 memcpy(*result, &inq, sizeof(struct inquire_s));
645 memset(&inq, 0, sizeof(struct inquire_s));
646 return rc;
649 #ifdef HAVE_LIBREADLINE
650 static int interactive_hook(void)
652 interactive_error = process_cmd();
654 if (interactive_error)
655 rl_event_hook = NULL;
657 return 0;
660 static void print_help()
662 fprintf(stderr, N_(
663 "------------------------------------------------------------------------------\n"
664 "Elements are TAB delimited. Press CTRL-V then TAB to insert from the prompt.\n"
665 "\n"
666 "Type HELP for protocol commands. Type .help for pwmc commands. Press CTRL-D\n"
667 "to quit.\n"
668 "------------------------------------------------------------------------------\n"
671 #endif
673 static char *parse_arg(const char *src, char *dst, size_t len)
675 char *p = dst;
676 const char *s = src;
677 size_t n = 0;
679 for (; s && *s && *s != ' ' && n < len; s++, n++)
680 *p++ = *s;
682 *p = 0;
683 p = dst;
684 return p;
687 static gpg_error_t read_command(const char *line, char **result, size_t *len)
689 const char *p = line;
690 int fd;
691 gpg_error_t rc = GPG_ERR_SYNTAX;
692 char filebuf[ASSUAN_LINELENGTH];
693 char *filename = NULL;
694 struct inquire_s *inq = NULL;
696 if (p && *p && *++p) {
697 filename = parse_arg(p, filebuf, sizeof(filebuf));
698 if (filename && *filename) {
699 p += strlen(filename)+1;
701 while (*p && isspace(*p))
702 p++;
704 if (*p)
705 rc = 0;
709 if (rc) {
710 fprintf(stderr, N_("Usage: .read <filename> <command> [args]\n"));
711 return rc;
714 fd = open(filename, O_RDONLY);
715 if (fd == -1)
716 return gpg_error_from_syserror();
718 rc = set_inquire(fd, NULL, &inq);
719 if (rc) {
720 close(fd);
721 return rc;
724 inq->header = 1;
725 rc = pwmd_command(pwm, result, len, inquire_cb, inq, p);
726 free_inquire(inq);
727 return rc;
730 static gpg_error_t redir_command(const char *line)
732 const char *p = line;
733 int fd;
734 gpg_error_t rc = GPG_ERR_SYNTAX;
735 char filebuf[ASSUAN_LINELENGTH];
736 char *filename = NULL;
737 struct inquire_s *inq = NULL;
738 char *result = NULL;
739 size_t len = 0;
741 if (p && *p && *++p) {
742 filename = parse_arg(p, filebuf, sizeof(filebuf));
743 if (filename && *filename) {
744 p += strlen(filename)+1;
746 while (*p && isspace(*p))
747 p++;
749 if (*p)
750 rc = 0;
754 if (rc) {
755 fprintf(stderr, N_("Usage: .redir <filename> <command> [args]\n"));
756 return rc;
759 fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0600);
760 if (fd == -1)
761 return gpg_error_from_syserror();
763 #ifdef HAVE_LIBREADLINE
764 rc = set_inquire(interactive ? STDIN_FILENO : inquirefd, NULL, &inq);
765 #else
766 rc = set_inquire(inquirefd, NULL, &inq);
767 #endif
768 if (rc) {
769 close(fd);
770 return rc;
773 rc = parse_dotcommand(p, &result, &len, inq);
774 if (!rc && result && len--) { // null byte which is always appended
775 if (write(fd, result, len) != len)
776 rc = GPG_ERR_TOO_SHORT;
777 pwmd_free(result);
780 free_inquire(inq);
781 close(fd);
782 return rc;
785 static gpg_error_t help_command(const char *line)
787 fprintf(stderr, N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
788 " .redir <filename> <command>\n"
789 " redirect the output of a command to the specified file\n"
790 "\n"
791 " .open <filename>\n"
792 " open the specified filename losing any changes to the current one\n"
793 "\n"
794 " .read <filename> <command> [args]\n"
795 " obtain data from the specified filename for an inquire command\n"
796 "\n"
797 " .set help | <name> [<value>]\n"
798 " set option <name> to <value>\n"
799 "\n"
800 " .help\n"
801 " this help text\n"));
802 return 0;
805 static gpg_error_t open_command(const char *line)
807 struct inquire_s *inq = NULL;
808 const char *filename = line;
809 gpg_error_t rc;
811 while (filename && isspace(*filename))
812 filename++;
814 if (!filename || !*filename) {
815 fprintf(stderr, N_("Usage: .open <filename>\n"));
816 return GPG_ERR_SYNTAX;
819 fprintf(stderr, N_("Opening data file \"%s\" ...\n"), filename);
820 #ifdef HAVE_LIBREADLINE
821 rc = set_inquire(interactive ? STDIN_FILENO : -1, NULL, &inq);
822 #else
823 rc = set_inquire(-1, NULL, &inq);
824 #endif
825 if (rc)
826 return rc;
828 if (keyfile)
829 pwmd_setopt(pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
831 #ifdef HAVE_LIBREADLINE
832 // For safety. This file may be a different one. Make the user set it
833 // again if needed.
834 if (interactive) {
835 pwmd_free(new_keyfile);
836 new_keyfile = NULL;
838 #endif
840 rc = pwmd_open(pwm, filename, inquire_cb, inq);
841 free_inquire(inq);
842 return rc;
845 static gpg_error_t set_command(const char *line)
847 gpg_error_t rc = 0;
848 char name[256] = {0};
849 char value[512] = {0};
850 char *namep;
851 char *valuep;
852 const char *p = line;
854 while (p && *p && isspace(*p))
855 p++;
857 namep = parse_arg(p, name, sizeof(name));
858 if (!namep || !*namep) {
859 fprintf(stderr, N_("Usage: .set help | <name> [<value>]\n"));
860 return GPG_ERR_SYNTAX;
863 p += strlen(namep);
864 while (p && *p && isspace(*p))
865 p++;
867 valuep = parse_arg(p, value, sizeof(value));
869 if (!strcmp(name, "keyfile") || !strcmp(name, "new-keyfile")) {
870 int is_newkeyfile = 1;
872 if (!strcmp(name, "keyfile"))
873 is_newkeyfile = 0;
875 if (is_newkeyfile) {
876 pwmd_free(new_keyfile);
877 new_keyfile = NULL;
879 else {
880 pwmd_free(keyfile);
881 keyfile = NULL;
884 if (*valuep) {
885 if (is_newkeyfile)
886 new_keyfile = pwmd_strdup(value);
887 else
888 keyfile = pwmd_strdup(value);
890 rc = pwmd_command(pwm, NULL, NULL, NULL, NULL, "AGENT option pinentry-mode=loopback");
891 if (!rc) {
892 rc = pwmd_setopt(pwm, PWMD_OPTION_NO_PINENTRY, 1);
893 rc = pwmd_setopt(pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
896 else if (!local_pin && !no_pinentry) {
897 pwmd_socket_t t;
899 pwmd_socket_type(pwm, &t);
900 if (t == PWMD_SOCKET_LOCAL) {
901 rc = pwmd_setopt(pwm, PWMD_OPTION_NO_PINENTRY, 0);
902 rc = pwmd_setopt(pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
906 else if (!strcmp(name, "help")) {
907 fprintf(stderr, N_(
908 "Set a libpwmd or pwmc option. The option name and optional value is space\n"
909 "delimited. When no value is specified the option is unset.\n\n"
910 "keyfile [<filename>]\n"
911 " set or unset the keyfile to be used when a passphrase is required\n"
912 "\n"
913 "new-keyfile [<filename>]\n"
914 " set or unset the keyfile to be used when a new passphrase is required\n"
917 else
918 rc = GPG_ERR_UNKNOWN_OPTION;
920 return rc;
923 static gpg_error_t parse_dotcommand(const char *line, char **result,
924 size_t *len, struct inquire_s *inq)
926 const char *p = line;
927 gpg_error_t rc = 0;
929 if (!strncmp(p, ".read", 5))
930 rc = read_command(p+5, result, len);
931 else if (!strncmp(p, ".redir", 6))
932 rc = redir_command(p+6);
933 else if (!strncmp(p, ".help", 5))
934 rc = help_command(p+5);
935 else if (!strncmp(p, ".open", 5))
936 rc = open_command(p+5);
937 else if (!strncmp(p, ".set", 4))
938 rc = set_command(p+4);
939 else
940 rc = pwmd_command(pwm, result, len, inquire_cb, inq, line);
942 return FINISH(rc);
945 #ifdef HAVE_LIBREADLINE
946 static gpg_error_t do_interactive()
948 gpg_error_t rc;
949 struct inquire_s *inq = NULL;
951 rl_initialize();
952 rc = process_cmd();
953 if (rc)
954 return rc;
956 rc = set_inquire(STDIN_FILENO, NULL, &inq);
957 if (rc)
958 return rc;
960 fprintf(stderr, N_("WARNING: interactive mode doesn't use secure memory!\n"));
961 print_help();
962 rl_event_hook = &interactive_hook;
963 rl_set_keyboard_input_timeout(100000);
965 for (;;) {
966 char *line;
967 char *result = NULL;
968 size_t len;
970 line = readline("pwm> ");
971 if (interactive_error) {
972 rc = interactive_error;
973 break;
976 if (!line) {
977 rc = finalize();
978 if (!rc)
979 break;
981 if (gpg_err_code(rc) != GPG_ERR_CANCELED &&
982 gpg_err_code(rc) != GPG_ERR_EOF)
983 fprintf(stderr, "ERR %i: %s\n", rc, gpg_strerror(rc));
985 continue;
987 else if (!*line) {
988 free(line);
989 continue;
992 #ifdef HAVE_LIBREADLINE
993 add_history(line);
994 #endif
995 inq->header = 0;
996 rc = parse_dotcommand(line, &result, &len, inq);
997 free(line);
998 if (rc)
999 fprintf(stderr, "ERR %i: %s\n", rc, gpg_strerror(rc));
1000 else if (result && len)
1001 printf("%s%s", result, result[len-1] != '\n' ? "\n" : "");
1003 pwmd_free(result);
1006 free_inquire(inq);
1007 return 0;
1009 #endif
1011 static char *itoa(long long int n)
1013 static char buf[64];
1015 snprintf(buf, sizeof(buf), "%llu", n);
1016 return buf;
1019 static gpg_error_t finalize()
1021 gpg_error_t rc = 0;
1022 #ifdef HAVE_LIBREADLINE
1023 int quit = 0;
1025 if (!force_save && interactive) {
1026 char *p, buf[16];
1027 int finished = 0;
1029 fprintf(stderr, "\n");
1031 do {
1032 fprintf(stderr, N_("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1033 p = fgets(buf, sizeof(buf), stdin);
1035 if (feof(stdin)) {
1036 clearerr(stdin);
1037 return GPG_ERR_EOF;
1040 switch (*p) {
1041 case 'h':
1042 print_help();
1043 break;
1044 case 'c':
1045 return GPG_ERR_CANCELED;
1046 case 'Q':
1047 return 0;
1048 case 'f':
1049 rc = pwmd_command(pwm, NULL, NULL, NULL, NULL,
1050 "CLEARCACHE %s", filename);
1051 if (rc)
1052 return rc;
1054 interactive_hook();
1055 break;
1056 case 'S':
1057 quit = 1;
1058 case 's':
1059 save = 1;
1060 finished = 1;
1061 break;
1062 default:
1063 break;
1065 } while (!finished);
1067 #endif
1069 if (save && !filename) {
1070 fprintf(stderr, N_("No filename was specified on the command line. Aborting.\n"));
1071 return GPG_ERR_CANCELED;
1074 if (save && filename) {
1075 char *args = pwmd_strdup_printf("%s%s %s%s %s %s%s %s%s --s2k-count=%lu",
1076 keygrip ? "--keygrip=" : "", keygrip ? keygrip : "",
1077 sign_keygrip ? "--sign-keygrip=" : "", sign_keygrip ? sign_keygrip : "",
1078 no_passphrase ? "--no-passphrase" : "",
1079 cipher ? "--cipher=" : "", cipher ? cipher : "",
1080 iterations_arg ? "--cipher-iterations=" : "", iterations_arg ? itoa(iterations) : "",
1081 s2k_count);
1083 fprintf(stderr, "\n");
1084 fprintf(stderr, N_("Saving changes ...\n"));
1085 rc = pwmd_save(pwm, args, inquire_cb, NULL);
1086 pwmd_free(args);
1088 if (!rc)
1089 no_passphrase = 0; // reset to avoid usage error on the next SAVE
1092 #ifdef HAVE_LIBREADLINE
1093 if (interactive)
1094 return rc ? rc : quit ? 0 : GPG_ERR_CANCELED;
1095 #endif
1097 return rc;
1100 int main(int argc, char *argv[])
1102 int connected = 0;
1103 gpg_error_t rc;
1104 int opt;
1105 char command[ASSUAN_LINELENGTH], *p = NULL;
1106 char *result = NULL;
1107 size_t len;
1108 char *pinentry_path = NULL;
1109 char *display = NULL, *tty = NULL, *ttytype = NULL, *lcctype = NULL,
1110 *lcmessages = NULL;
1111 int outfd = STDOUT_FILENO;
1112 FILE *outfp = stdout;
1113 FILE *inquirefp = stdin;
1114 int show_status = 1;
1115 char *clientname = "pwmc";
1116 char *inquire = NULL;
1117 char *inquire_line = NULL;
1118 int timeout = 0;
1119 #ifdef WITH_SSH
1120 int use_ssh_agent = 1;
1121 long ssh_timeout = 0;
1122 int ssh_keepalive = 0;
1123 char *knownhosts = NULL;
1124 char *identity = NULL;
1125 #endif
1126 #ifdef WITH_GNUTLS
1127 char *cacert = NULL;
1128 char *clientcert = NULL;
1129 char *clientkey = NULL;
1130 char *prio = NULL;
1131 int tls_verify = 0;
1132 #endif
1133 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1134 pwmd_socket_t socktype;
1135 #endif
1136 int lock_on_open = 1;
1137 long lock_timeout = 0;
1138 char *url = NULL;
1139 /* The order is important. */
1140 enum {
1141 #ifdef WITH_SSH
1142 OPT_USE_SSH_AGENT, OPT_IDENTITY, OPT_KNOWNHOSTS, OPT_SSH_TIMEOUT,
1143 OPT_SSH_KEEPALIVE,
1144 #endif
1145 #ifdef WITH_GNUTLS
1146 OPT_CACERT, OPT_CLIENTCERT, OPT_CLIENTKEY, OPT_PRIORITY, OPT_VERIFY,
1147 #endif
1148 OPT_URL, OPT_LOCAL, OPT_FORCE_SAVE, OPT_TTYNAME, OPT_TTYTYPE,
1149 OPT_DISPLAY, OPT_LC_CTYPE, OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES,
1150 OPT_PINENTRY, OPT_KEYFILE, OPT_NEW_KEYFILE, OPT_NOLOCK,
1151 OPT_LOCK_TIMEOUT, OPT_SAVE, OPT_OUTPUT_FD, OPT_INQUIRE,
1152 OPT_INQUIRE_FD, OPT_INQUIRE_FILE, OPT_INQUIRE_LINE, OPT_NO_STATUS,
1153 OPT_NAME, OPT_VERSION, OPT_HELP, OPT_KEYGRIP, OPT_SIGN_KEYGRIP,
1154 OPT_NOPASSPHRASE, OPT_CIPHER, OPT_KEYPARAMS, OPT_NO_PINENTRY,
1155 OPT_S2K_COUNT, OPT_ITERATIONS,
1156 #ifdef HAVE_LIBREADLINE
1157 OPT_INTERACTIVE,
1158 #endif
1160 const struct option long_opts[] = {
1161 #ifdef WITH_SSH
1162 { "no-ssh-agent", 0, 0, 0 },
1163 { "identity", 1, 0, 'i' },
1164 { "knownhosts", 1, 0, 'k' },
1165 { "ssh-timeout", 1, 0, 0 },
1166 { "ssh-keepalive", 1, 0, 0 },
1167 #endif
1168 #ifdef WITH_GNUTLS
1169 { "ca-cert", 1, 0, 0 },
1170 { "client-cert", 1, 0, 0 },
1171 { "client-key", 1, 0, 0 },
1172 { "tls-priority", 1, 0, 0 },
1173 { "tls-verify", 0, 0, 0 },
1174 #endif
1175 { "url", 1, 0, 0 },
1176 { "local-pinentry", 0, 0 },
1177 { "force-save", 0, 0 },
1178 { "ttyname", 1, 0, 'y' },
1179 { "ttytype", 1, 0, 't' },
1180 { "display", 1, 0, 'd' },
1181 { "lc-ctype", 1, 0, 0 },
1182 { "lc-messages", 1, 0, 0 },
1183 { "timeout", 1, 0, 0 },
1184 { "tries", 1, 0, 0 },
1185 { "pinentry", 1, 0, 0 },
1186 { "key-file", 1, 0, 0 },
1187 { "new-key-file", 1, 0, 0 },
1188 { "no-lock", 0, 0, 0 },
1189 { "lock-timeout", 1, 0, 0 },
1190 { "save", 0, 0, 'S' },
1191 { "output-fd", 1, 0, 0 },
1192 { "inquire", 1, 0, 0 },
1193 { "inquire-fd", 1, 0, 0 },
1194 { "inquire-file", 1, 0, 0 },
1195 { "inquire-line", 1, 0, 'L' },
1196 { "no-status", 0, 0, 0 },
1197 { "name", 1, 0, 'n' },
1198 { "version", 0, 0, 0 },
1199 { "help", 0, 0, 0 },
1200 { "keygrip", 1, 0, 0 },
1201 { "sign-keygrip", 1, 0, 0 },
1202 { "no-passphrase", 0, 0, 0 },
1203 { "cipher", 1, 0, 0 },
1204 { "key-params", 1, 0, 0 },
1205 { "no-pinentry", 0, 0, 0 },
1206 { "s2k-count", 1, 0, 0 },
1207 { "cipher-iterations", 1, 0, 0 },
1208 #ifdef HAVE_LIBREADLINE
1209 { "interactive", 0, 0 },
1210 #endif
1211 { 0, 0, 0, 0}
1213 #ifdef WITH_SSH
1214 const char *optstring = "L:y:t:d:P:I:Sn:i:k:";
1215 #else
1216 const char *optstring = "L:y:t:d:P:I:Sn:";
1217 #endif
1218 int opt_index = 0;
1220 #ifdef ENABLE_NLS
1221 setlocale(LC_ALL, "");
1222 bindtextdomain("libpwmd", LOCALEDIR);
1223 #endif
1225 #ifdef HAVE_LIBREADLINE
1226 if (!strcmp(basename(argv[0]), "pwmsh"))
1227 interactive = 1;
1228 #endif
1230 tries = DEFAULT_PIN_TRIES;
1231 inquirefd = STDIN_FILENO;
1233 while ((opt = getopt_long(argc, argv, optstring, long_opts, &opt_index)) != -1) {
1234 switch (opt) {
1235 /* Handle long options without a short option part. */
1236 case 0:
1237 switch (opt_index) {
1238 #ifdef WITH_SSH
1239 case OPT_USE_SSH_AGENT:
1240 use_ssh_agent = 0;
1241 break;
1242 case OPT_SSH_TIMEOUT:
1243 ssh_timeout = strtol(optarg, &p, 10);
1244 break;
1245 case OPT_SSH_KEEPALIVE:
1246 ssh_keepalive = strtol(optarg, &p, 10);
1247 break;
1248 #endif
1249 #ifdef WITH_GNUTLS
1250 case OPT_CACERT:
1251 cacert = optarg;
1252 break;
1253 case OPT_CLIENTCERT:
1254 clientcert = optarg;
1255 break;
1256 case OPT_CLIENTKEY:
1257 clientkey = optarg;
1258 break;
1259 case OPT_PRIORITY:
1260 prio = optarg;
1261 break;
1262 case OPT_VERIFY:
1263 tls_verify = 1;
1264 break;
1265 #endif
1266 case OPT_KEYPARAMS:
1267 keyparams = optarg;
1268 break;
1269 case OPT_KEYFILE:
1270 keyfile = pwmd_strdup(optarg);
1271 break;
1272 case OPT_NEW_KEYFILE:
1273 new_keyfile = pwmd_strdup(optarg);
1274 break;
1275 case OPT_NOLOCK:
1276 lock_on_open = 0;
1277 break;
1278 case OPT_LOCK_TIMEOUT:
1279 lock_timeout = strtol(optarg, &p, 10);
1280 break;
1281 case OPT_URL:
1282 url = optarg;
1283 break;
1284 case OPT_LOCAL:
1285 local_pin = 1;
1286 break;
1287 case OPT_FORCE_SAVE:
1288 save = force_save = 1;
1289 break;
1290 case OPT_LC_CTYPE:
1291 lcctype = pwmd_strdup(optarg);
1292 break;
1293 case OPT_LC_MESSAGES:
1294 lcmessages = pwmd_strdup(optarg);
1295 break;
1296 case OPT_TIMEOUT:
1297 timeout = strtol(optarg, &p, 10);
1298 break;
1299 case OPT_TRIES:
1300 tries = strtol(optarg, &p, 10);
1301 break;
1302 case OPT_INQUIRE:
1303 inquire = optarg;
1304 break;
1305 case OPT_INQUIRE_FD:
1306 inquirefd = strtol(optarg, &p, 10);
1307 if (!p) {
1308 inquirefp = fdopen(inquirefd, "r");
1309 if (!inquirefp) {
1310 pwmd_free(password);
1311 err(EXIT_FAILURE, "%i", inquirefd);
1314 break;
1315 case OPT_INQUIRE_FILE:
1316 inquirefd = open(optarg, O_RDONLY);
1317 if (!inquirefd == -1) {
1318 pwmd_free(password);
1319 err(EXIT_FAILURE, "%s", optarg);
1321 inquirefp = fdopen(inquirefd, "r");
1322 break;
1323 case OPT_OUTPUT_FD:
1324 outfd = strtol(optarg, &p, 10);
1325 if (!p) {
1326 outfp = fdopen(outfd, "w");
1327 if (!outfp) {
1328 pwmd_free(password);
1329 err(EXIT_FAILURE, "%i", outfd);
1332 break;
1333 case OPT_NO_STATUS:
1334 show_status = 0;
1335 break;
1336 case OPT_VERSION:
1337 pwmd_free(password);
1338 printf("%s (pwmc)\n\n"
1339 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012\n"
1340 "%s\n"
1341 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1342 "Compile-time features:\n"
1343 #ifdef WITH_SSH
1344 "+SSH "
1345 #else
1346 "-SSH "
1347 #endif
1348 #ifdef WITH_GNUTLS
1349 "+GNUTLS "
1350 #else
1351 "-GNUTLS "
1352 #endif
1353 #ifdef WITH_PINENTRY
1354 "+PINENTRY "
1355 #else
1356 "-PINENTRY "
1357 #endif
1358 #ifdef WITH_QUALITY
1359 "+CRACK "
1360 #else
1361 "-CRACK "
1362 #endif
1363 #ifdef MEM_DEBUG
1364 "+MEM_DEBUG "
1365 #else
1366 "-MEM_DEBUG "
1367 #endif
1368 #ifdef HAVE_LIBREADLINE
1369 "+INTERACTIVE "
1370 #else
1371 "-INTERACTIVE "
1372 #endif
1373 "\n"
1374 , PACKAGE_STRING, PACKAGE_BUGREPORT);
1375 exit(EXIT_SUCCESS);
1376 case OPT_PINENTRY:
1377 pinentry_path = optarg;
1378 break;
1379 case OPT_HELP:
1380 usage(argv[0], EXIT_SUCCESS);
1381 case OPT_KEYGRIP:
1382 keygrip = optarg;
1383 break;
1384 case OPT_SIGN_KEYGRIP:
1385 sign_keygrip = optarg;
1386 break;
1387 case OPT_S2K_COUNT:
1388 s2k_count = strtoul(optarg, &p, 10);
1389 break;
1390 case OPT_ITERATIONS:
1391 iterations = strtoull(optarg, &p, 10);
1392 iterations_arg = 1;
1393 break;
1394 case OPT_NOPASSPHRASE:
1395 no_passphrase = 1;
1396 break;
1397 case OPT_CIPHER:
1398 cipher = optarg;
1399 break;
1400 case OPT_NO_PINENTRY:
1401 no_pinentry = 1;
1402 break;
1403 #ifdef HAVE_LIBREADLINE
1404 case OPT_INTERACTIVE:
1405 interactive = 1;
1406 break;
1407 #endif
1408 default:
1409 usage(argv[0], EXIT_FAILURE);
1412 if (p && *p) {
1413 fprintf(stderr, N_("%s: invalid argument for option '--%s'\n"),
1414 argv[0], long_opts[opt_index].name);
1415 usage(argv[0], EXIT_FAILURE);
1418 break;
1419 #ifdef WITH_SSH
1420 case 'i':
1421 identity = optarg;
1422 break;
1423 case 'k':
1424 knownhosts = optarg;
1425 break;
1426 #endif
1427 case 'L':
1428 inquire_line = optarg;
1429 break;
1430 case 'y':
1431 tty = optarg;
1432 break;
1433 case 't':
1434 ttytype = optarg;
1435 break;
1436 case 'd':
1437 display = optarg;
1438 break;
1439 case 'S':
1440 save = 1;
1441 break;
1442 case 'n':
1443 clientname = optarg;
1444 break;
1445 default:
1446 pwmd_free(password);
1447 usage(argv[0], EXIT_FAILURE);
1451 #ifdef HAVE_LIBREADLINE
1452 if (interactive && !isatty(STDIN_FILENO)) {
1453 pwmd_free(password);
1454 usage(argv[0], EXIT_FAILURE);
1456 else if (isatty(STDIN_FILENO) && !inquire && !inquire_line)
1457 interactive = 1;
1458 #endif
1460 filename = argv[optind];
1461 #ifdef WITH_GNUTLS
1462 gnutls_global_set_mem_functions(pwmd_malloc, pwmd_malloc, NULL,
1463 pwmd_realloc, pwmd_free);
1464 #endif
1465 pwmd_init();
1466 rc = pwmd_new(clientname, &pwm);
1467 if (rc)
1468 goto done;
1470 pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
1471 fprintf(stderr, N_("Connecting ...\n"));
1473 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1474 socktype = is_remote_url(url);
1475 if (socktype != PWMD_SOCKET_LOCAL) {
1476 local_pin = 1;
1477 if (socktype == PWMD_SOCKET_SSH) {
1478 #ifdef WITH_SSH
1479 rc = pwmd_setopt(pwm, PWMD_OPTION_KNOWNHOST_CB, knownhost_cb);
1480 if (rc)
1481 goto done;
1483 rc = pwmd_setopt(pwm, PWMD_OPTION_KNOWNHOST_DATA, clientname);
1484 if (rc)
1485 goto done;
1487 if (!getenv("SSH_AUTH_SOCK") || identity)
1488 use_ssh_agent = 0;
1490 rc = pwmd_setopt(pwm, PWMD_OPTION_SSH_AGENT, use_ssh_agent);
1491 if (rc)
1492 goto done;
1494 rc = pwmd_setopt(pwm, PWMD_OPTION_SSH_TIMEOUT, ssh_timeout);
1495 if (rc)
1496 goto done;
1498 rc = pwmd_setopt(pwm, PWMD_OPTION_SSH_KEEPALIVE, ssh_keepalive);
1499 if (rc)
1500 goto done;
1502 rc = pwmd_connect(pwm, url, identity, knownhosts);
1503 #endif
1505 #ifdef WITH_GNUTLS
1506 else {
1507 rc = pwmd_setopt(pwm, PWMD_OPTION_TLS_VERIFY, tls_verify);
1508 if (rc)
1509 goto done;
1511 rc = pwmd_connect(pwm, url, clientcert, clientkey, cacert, prio);
1513 #endif
1515 else
1516 rc = pwmd_connect(pwm, url);
1517 #else
1518 rc = pwmd_connect(pwm, url);
1519 #endif
1520 if (rc)
1521 goto done;
1523 fprintf(stderr, N_("Connected.\n"));
1524 connected = 1;
1525 if (lock_timeout) {
1526 rc = pwmd_command(pwm, NULL, NULL, NULL, NULL,
1527 "OPTION LOCK-TIMEOUT=%li", lock_timeout);
1528 if (rc)
1529 goto done;
1532 if (lock_on_open) {
1533 rc = pwmd_setopt(pwm, PWMD_OPTION_LOCK_ON_OPEN, 1);
1534 if (rc)
1535 goto done;
1538 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_DESC, NULL);
1539 if (rc)
1540 goto done;
1542 if (timeout > 0) {
1543 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
1544 if (rc)
1545 goto done;
1548 rc = pwmd_setopt(pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1549 if (rc)
1550 goto done;
1552 rc = pwmd_setopt(pwm, PWMD_OPTION_LOCAL_PINENTRY,
1553 (local_pin || keyfile || new_keyfile));
1554 if (rc)
1555 goto done;
1557 if (pinentry_path) {
1558 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
1559 if (rc)
1560 goto done;
1563 if (display) {
1564 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
1565 if (rc)
1566 goto done;
1569 if (tty) {
1570 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TTY, tty);
1571 if (rc)
1572 goto done;
1575 if (ttytype) {
1576 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
1577 if (rc)
1578 goto done;
1581 if (lcctype) {
1582 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
1583 if (rc)
1584 goto done;
1587 if (lcmessages) {
1588 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES,
1589 lcmessages);
1590 if (rc)
1591 goto done;
1594 if (show_status) {
1595 rc = pwmd_setopt(pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
1596 if (rc)
1597 goto done;
1600 if (filename) {
1601 rc = open_command(filename);
1602 if (rc)
1603 goto done;
1606 #ifdef HAVE_LIBREADLINE
1607 if (interactive) {
1608 if (!force_save)
1609 save = 0;
1611 rc = do_interactive();
1612 goto do_exit;
1614 #endif
1616 if (inquire) {
1617 struct inquire_s *inq = NULL;
1619 rc = set_inquire(inquirefd, inquire_line, &inq);
1620 if (!rc)
1621 rc = pwmd_command(pwm, &result, &len, inquire_cb, inq, inquire);
1623 free_inquire(inq);
1624 goto done;
1627 fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
1628 ssize_t n;
1630 for (;;) {
1631 rc = process_cmd();
1633 if (rc)
1634 goto done;
1636 n = read(STDIN_FILENO, command, sizeof(command));
1637 if (n == -1) {
1638 if (errno == EAGAIN) {
1639 usleep(100000);
1640 continue;
1643 rc = gpg_error_from_errno(errno);
1644 goto done;
1646 else if (!n)
1647 goto done;
1649 p = command;
1650 command[n] = 0;
1651 break;
1654 if (!p || !*p || !strcasecmp(p, "BYE"))
1655 goto done;
1658 struct inquire_s *inq = NULL;
1659 rc = set_inquire(inquirefd, inquire_line, &inq);
1660 if (!rc) {
1661 rc = parse_dotcommand(command, &result, &len, inq);
1662 free_inquire(inq);
1665 if (rc)
1666 goto done;
1668 done:
1669 if (result) {
1670 fwrite(result, 1, result[len-1] == 0 ? len-1 : len, outfp);
1671 fflush(outfp);
1672 pwmd_free(result);
1675 pwmd_free(password);
1676 password = NULL;
1677 if (!rc)
1678 rc = finalize();
1680 #ifdef HAVE_LIBREADLINE
1681 do_exit:
1682 #endif
1683 memset(command, 0, sizeof(command));
1684 pwmd_close(pwm);
1685 pwmd_free(keyfile);
1686 pwmd_free(new_keyfile);
1687 pwmd_deinit();
1689 if (rc)
1690 show_error(rc);
1692 if (connected)
1693 fprintf(stderr, N_("Connection closed.\n"));
1695 exit(rc ? EXIT_FAILURE : EXIT_SUCCESS);