Revert "Include m4 readline checking macro in the dist."
[libpwmd.git] / src / pwmc.c
blobbbe964d21807a0c9fcdff251cb05b45253b68274
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 # if defined(HAVE_READLINE_READLINE_H)
57 # include <readline/readline.h>
58 # elif defined(HAVE_READLINE_H)
59 # include <readline.h>
60 # endif /* !defined(HAVE_READLINE_H) */
61 static int interactive_error;
62 static int interactive;
63 #endif /* HAVE_LIBREADLINE */
65 #ifdef HAVE_READLINE_HISTORY
66 # if defined(HAVE_READLINE_HISTORY_H)
67 # include <readline/history.h>
68 # elif defined(HAVE_HISTORY_H)
69 # include <history.h>
70 # endif
71 #endif /* HAVE_READLINE_HISTORY */
73 #ifndef LINE_MAX
74 #define LINE_MAX 2048
75 #endif
77 #include "gettext.h"
78 #define N_(msgid) gettext(msgid)
80 #include "mem.h"
82 #define DEFAULT_PORT 22
83 #define DEFAULT_PIN_TRIES 3
84 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
85 ? gpg_error(rc) : rc
87 static int no_pinentry;
88 static pwm_t *pwm;
89 static char *filename;
90 static int save;
91 static int force_save;
92 static int no_passphrase;
93 static char *cipher;
94 static char *keygrip;
95 static char *sign_keygrip;
96 static char *keyparams;
97 static char *password;
98 static char *keyfile;
99 static char *new_keyfile;
100 static unsigned long s2k_count;
101 static uint64_t iterations;
102 static int iterations_arg;
103 static int tries;
104 static int local_pin;
105 static int inquirefd;
107 struct inquire_s {
108 int fd;
109 char *line;
110 size_t len;
111 size_t size; // from stat(2).
112 int header;
115 static gpg_error_t finalize();
116 static gpg_error_t set_inquire(int fd, const char *line,
117 struct inquire_s **result);
118 static gpg_error_t parse_dotcommand(const char *line, char **result,
119 size_t *len, struct inquire_s *inq);
120 static gpg_error_t open_command(const char *line);
121 #ifdef WITH_SSH
122 static gpg_error_t get_password(char **result, pwmd_pinentry_t w, int echo);
123 #endif
125 static void show_error(gpg_error_t error)
127 fprintf(stderr, "ERR %i %s\n", error, gpg_strerror(error));
130 static void usage(const char *pn, int status)
132 fprintf(status == EXIT_FAILURE ? stderr : stdout, N_(
133 "Read a PWMD protocol command from standard input.\n\n"
134 "Usage: pwmc [options] [file]\n"
135 " --url <string>\n"
136 " a url string to connect to (see below)\n"
137 #ifdef WITH_SSH
138 " --no-ssh-agent\n"
139 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
140 " --identity, -i <filename>\n"
141 " the ssh identity file to use for authentication\n"
142 " --knownhosts, -k <filename>\n"
143 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
144 " --ssh-timeout <seconds>\n"
145 " timeout before a remote command fails (0=disabled, default)\n"
146 " --ssh-keepalive <seconds>\n"
147 " interval to send a keepalive to the remote server (0=disabled, default)\n"
148 #endif
149 #ifdef WITH_GNUTLS
150 " --ca-cert <filename>\n"
151 " certificate authority (CA) used to sign the server cert\n"
152 " --client-cert <filename>\n"
153 " client certificate to use for authentication\n"
154 " --client-key <filename>\n"
155 " key file used to protect the client certificate\n"
156 " --tls-priority <string>\n"
157 " compression, cipher and hash algorithm string (SECURE256)\n"
158 " --tls-verify\n"
159 " verify the hostname against the server certificate\n"
160 #endif
161 " --no-lock\n"
162 " do not lock the data file upon opening it\n"
163 " --lock-timeout <N>\n"
164 " time in tenths of a second to wait for a locked data file\n"
165 " --no-status\n"
166 " disable showing of status messages from the server\n"
167 " --name, -n <string>\n"
168 " set the client name\n"
169 " --no-passphrase\n"
170 " do not require a passphrase when saving a new file\n"
171 " --keygrip <string>\n"
172 " the hex string of the keygrip to save to\n"
173 " --sign-keygrip <string>\n"
174 " the hex string of the keygrip to sign with\n"
175 " --key-file <filename>\n"
176 " obtain the passphrase from the specified filename\n"
177 " --new-key-file <filename>\n"
178 " obtain the passphrase to save with from the specified filename\n"
179 " --s2k-count <N>\n"
180 " the number of times to hash the passphrase for a new file\n"
181 " --cipher-iterations <N>\n"
182 " the number of times to encrypt the XML data (N+1)\n"
183 " --timeout <seconds>\n"
184 " pinentry timeout\n"
185 " --tries <N>\n"
186 " number of pinentry tries before failing (3)\n"
187 " --no-pinentry\n"
188 " disable pinentry both remotely and locally\n"
189 " --pinentry <path>\n"
190 " the full path to the pinentry binary (server default)\n"
191 " --ttyname, -y <path>\n"
192 " tty that pinentry will use\n"
193 " --ttytype, -t <string>\n"
194 " pinentry terminal type (default is $TERM)\n"
195 " --display, -d\n"
196 " pinentry display (default is $DISPLAY)\n"
197 " --lc-ctype <string>\n"
198 " locale setting for pinentry\n"
199 " --lc-messages <string>\n"
200 " locale setting for pinentry\n"
201 " --local-pinentry\n"
202 " force using a local pinentry\n"
203 #ifdef HAVE_LIBREADLINE
204 " --interactive\n"
205 " use a shell like interface to pwmd (allows more than one command)\n"
206 #endif
207 " --output-fd <FD>\n"
208 " redirect command output to the specified file descriptor\n"
209 " --inquire <COMMAND>\n"
210 " the specified command (with any options) uses a server inquire while\n"
211 " command data is read via the inquire file descriptor (stdin)\n"
212 " --inquire-fd <FD>\n"
213 " read inquire data from the specified file descriptor (stdin)\n"
214 " --inquire-file <filename>\n"
215 " read inquire data from the specified filename\n"
216 " --inquire-line, -L <STRING>\n"
217 " the initial line to send (i.e., element path) before the inquire data\n"
218 " --cipher <string>\n"
219 " the cipher to use when saving (see pwmd(1))\n"
220 " --save, -S\n"
221 " send the SAVE command before exiting\n"
222 " --key-params <string>\n"
223 " the key parameters to use when saving a new file (pwmd default)\n"
224 " --force-save\n"
225 " like --save but always ask for a passphrase\n"
226 " --version\n"
227 " --help\n"));
228 fprintf(status == EXIT_FAILURE ? stderr : stdout, N_(
229 "\n"
230 "An optional url may be in the form of:\n"
231 " --url /path/to/socket\n"
232 " --url file://[path/to/socket]\n"
233 #ifdef WITH_SSH
234 " or\n"
235 " --url ssh[46]://[username@]hostname[:port]\n"
236 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
237 #endif
238 #ifdef WITH_GNUTLS
239 " or\n"
240 " --url tls[46]://hostname[:port]\n"
241 #endif
243 exit(status);
246 static gpg_error_t inquire_cb(void *user, const char *keyword, gpg_error_t rc,
247 char **data, size_t *size)
249 struct inquire_s *inq = user;
250 int is_password = 0;
251 int is_newpassword = 0;
253 *data = NULL;
254 *size = 0;
256 if (rc)
257 return rc;
259 if (!strcmp(keyword, "PASSPHRASE"))
260 is_password = 1;
261 else if (!strcmp(keyword, "NEW_PASSPHRASE"))
262 is_newpassword = 1;
263 #ifdef HAVE_LIBREADLINE
264 else if (!strcmp(keyword, "KEYPARAM") && !interactive) {
265 #else
266 else if (!strcmp(keyword, "KEYPARAM")) {
267 #endif
268 if (!keyparams || !*keyparams)
269 return gpg_error(GPG_ERR_INV_PARAMETER);
271 *data = keyparams;
272 *size = strlen(keyparams);
273 return gpg_error(GPG_ERR_EOF);
276 if ((is_newpassword && new_keyfile) || (is_password && keyfile)) {
277 int fd = open(is_password ? keyfile : new_keyfile, O_RDONLY);
279 if (fd == -1) {
280 fprintf(stderr, "%s: %s\n", is_newpassword ? new_keyfile : keyfile,
281 strerror(errno));
282 return gpg_error_from_syserror();
285 rc = set_inquire(fd, NULL, &inq);
286 if (rc) {
287 close(fd);
288 return rc;
291 fprintf(stderr, N_("Using keyfile '%s' as %s.\n"),
292 is_newpassword ? new_keyfile : keyfile, keyword);
294 if (!new_keyfile || is_newpassword) {
295 pwmd_socket_t t;
297 pwmd_socket_type(pwm, &t);
298 pwmd_setopt(pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
299 if (!no_pinentry && t == PWMD_SOCKET_LOCAL)
300 pwmd_setopt(pwm, PWMD_OPTION_NO_PINENTRY, 0);
303 else if (is_password && !keyfile) {
304 char *tmp;
306 rc = pwmd_password(pwm, keyword, &tmp, &inq->len);
307 if (rc && gpg_err_code(rc) != GPG_ERR_EOF)
308 return rc;
310 pwmd_free(inq->line);
311 inq->line = tmp;
312 *data = inq->line;
313 *size = inq->len;
314 return gpg_error(GPG_ERR_EOF);
316 #ifdef HAVE_LIBREADLINE
317 else if (!inq->header && interactive) {
318 fprintf(stderr, N_(
319 "Press CTRL-D to send the current line. Press twice to end. %s:\n"), keyword);
320 inq->header = 1;
322 #endif
324 /* The first part of the command data. */
325 if (inq->len) {
326 *data = inq->line;
327 *size = inq->len;
328 inq->len = 0;
329 return inq->fd == -1 ? gpg_error(GPG_ERR_EOF) : 0;
332 *size = read(inq->fd, inq->line, ASSUAN_LINELENGTH);
333 if (*size == -1) {
334 *size = 0;
335 return gpg_error(gpg_error_from_syserror());
337 else if (*size)
338 *data = inq->line;
340 if (((is_newpassword && new_keyfile) || (is_password && keyfile))
341 && *size == inq->size)
342 return gpg_error(GPG_ERR_EOF);
344 return *size ? 0 : gpg_error(GPG_ERR_EOF);
347 static int status_msg_cb(void *data, const char *line)
349 char *p = strchr(line, ' ');
351 if (!strcmp(line, "KEEPALIVE"))
352 return 0;
354 if (*line != '#' && p && strchr(p, ' ') && *++p) {
355 char *p1 = strchr(p, ' ');
356 int a = strtol(p, NULL, 10);
358 if (isdigit(*p) && p1) {
359 int b = strtol(p1, NULL, 10);
360 char l[64] = {0};
361 int t = a && b ? a*100/b : 0;
363 strncpy(l, line, strlen(line)-strlen(p)-1);
364 fprintf(stderr, "\r%s %i/%i %i%%%s", l, a, b, t, a == b ? "\n" : "");
365 fflush(stderr);
366 return 0;
370 fprintf(stderr, "%s\n", line);
371 fflush(stderr);
372 rl_on_new_line();
373 return 0;
376 static gpg_error_t process_cmd()
378 return pwmd_process(pwm);
381 #ifdef WITH_SSH
382 static gpg_error_t get_password(char **result, pwmd_pinentry_t w, int echo)
384 char buf[LINE_MAX] = {0}, *p;
385 struct termios told, tnew;
386 char *key = NULL;
388 *result = NULL;
390 if (!isatty(STDIN_FILENO)) {
391 fprintf(stderr, N_("Input is not from a terminal! Failing.\n"));
392 return GPG_ERR_ENOTTY;
395 if (!echo) {
396 if (tcgetattr(STDIN_FILENO, &told) == -1)
397 return gpg_error_from_syserror();
399 memcpy(&tnew, &told, sizeof(struct termios));
400 tnew.c_lflag &= ~(ECHO);
401 tnew.c_lflag |= ICANON|ECHONL;
403 if (tcsetattr(STDIN_FILENO, TCSANOW, &tnew) == -1) {
404 int n = errno;
406 tcsetattr(STDIN_FILENO, TCSANOW, &told);
407 return gpg_error_from_errno(n);
411 switch (w) {
412 case PWMD_PINENTRY_OPEN:
413 fprintf(stderr, N_("Password for %s: "), filename);
414 break;
415 case PWMD_PINENTRY_OPEN_FAILED:
416 fprintf(stderr, N_("Invalid password. Password for %s: "), filename);
417 break;
418 case PWMD_PINENTRY_SAVE:
419 fprintf(stderr, N_("New password for %s: "), filename);
420 break;
421 case PWMD_PINENTRY_SAVE_CONFIRM:
422 fprintf(stderr, N_("Confirm password: "));
423 break;
424 default:
425 break;
428 if ((p = fgets(buf, sizeof(buf), stdin)) == NULL) {
429 tcsetattr(STDIN_FILENO, TCSANOW, &told);
430 return 0;
433 if (!echo)
434 tcsetattr(STDIN_FILENO, TCSANOW, &told);
436 if (feof(stdin)) {
437 clearerr(stdin);
438 return GPG_ERR_CANCELED;
441 p[strlen(p) - 1] = 0;
443 if (buf[0]) {
444 key = pwmd_strdup_printf("%s", p);
445 memset(&buf, 0, sizeof(buf));
447 if (!key)
448 return GPG_ERR_ENOMEM;
451 *result = key;
452 return 0;
455 static gpg_error_t knownhost_cb(void *data, const char *host, const char *key,
456 size_t len)
458 gpg_error_t rc;
459 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);
461 if (no_pinentry && !isatty(STDIN_FILENO)) {
462 fprintf(stderr, N_("Input is not from a terminal! Failing.\n"));
463 pwmd_free(buf);
464 return GPG_ERR_ENOTTY;
466 else if (no_pinentry) {
467 for (char *p = buf, len = 0; *p; p++, len++) {
468 if (*p == '\n')
469 len = 0;
471 if (len == 78) {
472 char *t = p;
474 while (!isspace(*(--p)));
475 *p = '\n';
476 p = t;
477 len = 0;
481 fprintf(stderr, "%s\n\n", buf);
482 pwmd_free(buf);
484 do {
485 char *result;
487 fprintf(stderr, N_("Trust this connection [y/N]: "));
488 fflush(stderr);
489 rc = get_password(&result, PWMD_PINENTRY_CONFIRM, 1);
491 if (rc)
492 return rc;
494 if (!result || !*result || *result == 'n' || *result == 'N') {
495 if (result && *result)
496 pwmd_free(result);
498 return GPG_ERR_NOT_CONFIRMED;
501 if ((*result == 'y' || *result == 'Y') && *(result+1) == 0) {
502 pwmd_free(result);
503 return 0;
505 } while (1);
508 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_DESC, buf);
509 pwmd_free(buf);
511 if (rc)
512 return rc;
514 return pwmd_getpin(pwm, NULL, NULL, NULL, PWMD_PINENTRY_CONFIRM);
516 #endif
518 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
519 static pwmd_socket_t is_remote_url(const char *str)
521 if (!str)
522 return PWMD_SOCKET_LOCAL;
524 #ifdef WITH_SSH
525 if (strstr(str, "ssh://") || strstr(str, "ssh4://")
526 || strstr(str, "ssh6://"))
527 return PWMD_SOCKET_SSH;
528 #endif
530 #ifdef WITH_GNUTLS
531 if (strstr(str, "tls://") || strstr(str, "tls4://")
532 || strstr(str, "tls6://"))
533 return PWMD_SOCKET_TLS;
534 #endif
536 return PWMD_SOCKET_LOCAL;
538 #endif
540 static char *escape(const char *str)
542 const char *p;
543 char *buf = pwmd_malloc(ASSUAN_LINELENGTH+1), *b = buf;
544 size_t len = 0;
546 for (p = str; *p; p++, len++) {
547 if (len == ASSUAN_LINELENGTH)
548 break;
550 if (*p == '\\') {
551 switch (*++p) {
552 case 't':
553 *b++ = '\t';
554 break;
555 case 'n':
556 *b++ = '\n';
557 break;
558 case 'v':
559 *b++ = '\v';
560 break;
561 case 'b':
562 *b++ = '\b';
563 break;
564 case 'f':
565 *b++ = '\f';
566 break;
567 case 'r':
568 *b++ = '\r';
569 break;
570 default:
571 *b++ = *p;
572 break;
575 if (!*p)
576 break;
578 continue;
581 *b++ = *p;
584 *b = 0;
585 return buf;
588 static void free_inquire(struct inquire_s *inq)
590 if (!inq)
591 return;
593 pwmd_free(inq->line);
595 if (inq->fd != -1 && inq->fd != STDIN_FILENO)
596 close(inq->fd);
598 pwmd_free(inq);
601 /* When *result is not NULL it is updated to the new values and not
602 * reallocated. */
603 static gpg_error_t set_inquire(int fd, const char *line,
604 struct inquire_s **result)
606 struct inquire_s inq = {0};
607 struct stat st = {0};
608 gpg_error_t rc;
610 if (fd != -1) {
611 if (fstat(fd, &st) == -1)
612 return gpg_error_from_syserror();
614 inq.size = st.st_size;
617 inq.fd = fd;
618 inq.line = pwmd_calloc(1, ASSUAN_LINELENGTH);
619 if (!inq.line)
620 return GPG_ERR_ENOMEM;
622 if (line) {
623 char *s = escape(line);
625 if (strlen(s) >= ASSUAN_LINELENGTH) {
626 pwmd_free(inq.line);
627 return GPG_ERR_LINE_TOO_LONG;
630 strncpy(inq.line, s, ASSUAN_LINELENGTH-1);
631 inq.len = strlen(s);
632 pwmd_free(s);
635 rc = pwmd_setopt(pwm, PWMD_OPTION_INQUIRE_TOTAL,
636 st.st_size ? st.st_size+strlen(inq.line) : 0);
637 if (rc) {
638 pwmd_free(inq.line);
639 return rc;
642 if (*result == NULL)
643 *result = pwmd_malloc(sizeof(struct inquire_s));
644 else {
645 if ((*result)->fd != -1 && (*result)->fd != STDIN_FILENO)
646 close((*result)->fd);
648 pwmd_free((*result)->line);
649 (*result)->line = NULL;
650 (*result)->fd = -1;
651 (*result)->len = 0;
654 memcpy(*result, &inq, sizeof(struct inquire_s));
655 memset(&inq, 0, sizeof(struct inquire_s));
656 return rc;
659 #ifdef HAVE_LIBREADLINE
660 static int interactive_hook(void)
662 interactive_error = process_cmd();
664 if (interactive_error)
665 rl_event_hook = NULL;
667 return 0;
670 static void print_help()
672 fprintf(stderr, N_(
673 "------------------------------------------------------------------------------\n"
674 "Elements are TAB delimited. Press CTRL-V then TAB to insert from the prompt.\n"
675 "\n"
676 "Type HELP for protocol commands. Type .help for pwmc commands. Press CTRL-D\n"
677 "to quit.\n"
678 "------------------------------------------------------------------------------\n"
681 #endif
683 static char *parse_arg(const char *src, char *dst, size_t len)
685 char *p = dst;
686 const char *s = src;
687 size_t n = 0;
689 for (; s && *s && *s != ' ' && n < len; s++, n++)
690 *p++ = *s;
692 *p = 0;
693 p = dst;
694 return p;
697 static gpg_error_t read_command(const char *line, char **result, size_t *len)
699 const char *p = line;
700 int fd;
701 gpg_error_t rc = GPG_ERR_SYNTAX;
702 char filebuf[ASSUAN_LINELENGTH];
703 char *filename = NULL;
704 struct inquire_s *inq = NULL;
706 if (p && *p && *++p) {
707 filename = parse_arg(p, filebuf, sizeof(filebuf));
708 if (filename && *filename) {
709 p += strlen(filename)+1;
711 while (*p && isspace(*p))
712 p++;
714 if (*p)
715 rc = 0;
719 if (rc) {
720 fprintf(stderr, N_("Usage: .read <filename> <command> [args]\n"));
721 return rc;
724 fd = open(filename, O_RDONLY);
725 if (fd == -1)
726 return gpg_error_from_syserror();
728 rc = set_inquire(fd, NULL, &inq);
729 if (rc) {
730 close(fd);
731 return rc;
734 inq->header = 1;
735 rc = pwmd_command(pwm, result, len, inquire_cb, inq, p);
736 free_inquire(inq);
737 return rc;
740 static gpg_error_t redir_command(const char *line)
742 const char *p = line;
743 int fd;
744 gpg_error_t rc = GPG_ERR_SYNTAX;
745 char filebuf[ASSUAN_LINELENGTH];
746 char *filename = NULL;
747 struct inquire_s *inq = NULL;
748 char *result = NULL;
749 size_t len = 0;
751 if (p && *p && *++p) {
752 filename = parse_arg(p, filebuf, sizeof(filebuf));
753 if (filename && *filename) {
754 p += strlen(filename)+1;
756 while (*p && isspace(*p))
757 p++;
759 if (*p)
760 rc = 0;
764 if (rc) {
765 fprintf(stderr, N_("Usage: .redir <filename> <command> [args]\n"));
766 return rc;
769 fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0600);
770 if (fd == -1)
771 return gpg_error_from_syserror();
773 #ifdef HAVE_LIBREADLINE
774 rc = set_inquire(interactive ? STDIN_FILENO : inquirefd, NULL, &inq);
775 #else
776 rc = set_inquire(inquirefd, NULL, &inq);
777 #endif
778 if (rc) {
779 close(fd);
780 return rc;
783 rc = parse_dotcommand(p, &result, &len, inq);
784 if (!rc && result && len--) { // null byte which is always appended
785 if (write(fd, result, len) != len)
786 rc = GPG_ERR_TOO_SHORT;
787 pwmd_free(result);
790 free_inquire(inq);
791 close(fd);
792 return rc;
795 static gpg_error_t help_command(const char *line)
797 fprintf(stderr, N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
798 " .redir <filename> <command>\n"
799 " redirect the output of a command to the specified file\n"
800 "\n"
801 " .open <filename>\n"
802 " open the specified filename losing any changes to the current one\n"
803 "\n"
804 " .read <filename> <command> [args]\n"
805 " obtain data from the specified filename for an inquire command\n"
806 "\n"
807 " .set help | <name> [<value>]\n"
808 " set option <name> to <value>\n"
809 "\n"
810 " .help\n"
811 " this help text\n"));
812 return 0;
815 static gpg_error_t open_command(const char *line)
817 struct inquire_s *inq = NULL;
818 const char *filename = line;
819 gpg_error_t rc;
821 while (filename && isspace(*filename))
822 filename++;
824 if (!filename || !*filename) {
825 fprintf(stderr, N_("Usage: .open <filename>\n"));
826 return GPG_ERR_SYNTAX;
829 fprintf(stderr, N_("Opening data file \"%s\" ...\n"), filename);
830 #ifdef HAVE_LIBREADLINE
831 rc = set_inquire(interactive ? STDIN_FILENO : -1, NULL, &inq);
832 #else
833 rc = set_inquire(-1, NULL, &inq);
834 #endif
835 if (rc)
836 return rc;
838 if (keyfile)
839 pwmd_setopt(pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
841 #ifdef HAVE_LIBREADLINE
842 // For safety. This file may be a different one. Make the user set it
843 // again if needed.
844 if (interactive) {
845 pwmd_free(new_keyfile);
846 new_keyfile = NULL;
848 #endif
850 rc = pwmd_open(pwm, filename, inquire_cb, inq);
851 free_inquire(inq);
852 return rc;
855 static gpg_error_t set_command(const char *line)
857 gpg_error_t rc = 0;
858 char name[256] = {0};
859 char value[512] = {0};
860 char *namep;
861 char *valuep;
862 const char *p = line;
864 while (p && *p && isspace(*p))
865 p++;
867 namep = parse_arg(p, name, sizeof(name));
868 if (!namep || !*namep) {
869 fprintf(stderr, N_("Usage: .set help | <name> [<value>]\n"));
870 return GPG_ERR_SYNTAX;
873 p += strlen(namep);
874 while (p && *p && isspace(*p))
875 p++;
877 valuep = parse_arg(p, value, sizeof(value));
879 if (!strcmp(name, "keyfile") || !strcmp(name, "new-keyfile")) {
880 int is_newkeyfile = 1;
882 if (!strcmp(name, "keyfile"))
883 is_newkeyfile = 0;
885 if (is_newkeyfile) {
886 pwmd_free(new_keyfile);
887 new_keyfile = NULL;
889 else {
890 pwmd_free(keyfile);
891 keyfile = NULL;
894 if (*valuep) {
895 if (is_newkeyfile)
896 new_keyfile = pwmd_strdup(value);
897 else
898 keyfile = pwmd_strdup(value);
900 rc = pwmd_command(pwm, NULL, NULL, NULL, NULL, "AGENT option pinentry-mode=loopback");
901 if (!rc) {
902 rc = pwmd_setopt(pwm, PWMD_OPTION_NO_PINENTRY, 1);
903 rc = pwmd_setopt(pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
906 else if (!local_pin && !no_pinentry) {
907 pwmd_socket_t t;
909 pwmd_socket_type(pwm, &t);
910 if (t == PWMD_SOCKET_LOCAL) {
911 rc = pwmd_setopt(pwm, PWMD_OPTION_NO_PINENTRY, 0);
912 rc = pwmd_setopt(pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
916 else if (!strcmp(name, "help")) {
917 fprintf(stderr, N_(
918 "Set a libpwmd or pwmc option. The option name and optional value is space\n"
919 "delimited. When no value is specified the option is unset.\n\n"
920 "keyfile [<filename>]\n"
921 " set or unset the keyfile to be used when a passphrase is required\n"
922 "\n"
923 "new-keyfile [<filename>]\n"
924 " set or unset the keyfile to be used when a new passphrase is required\n"
927 else
928 rc = GPG_ERR_UNKNOWN_OPTION;
930 return rc;
933 static gpg_error_t parse_dotcommand(const char *line, char **result,
934 size_t *len, struct inquire_s *inq)
936 const char *p = line;
937 gpg_error_t rc = 0;
939 if (!strncmp(p, ".read", 5))
940 rc = read_command(p+5, result, len);
941 else if (!strncmp(p, ".redir", 6))
942 rc = redir_command(p+6);
943 else if (!strncmp(p, ".help", 5))
944 rc = help_command(p+5);
945 else if (!strncmp(p, ".open", 5))
946 rc = open_command(p+5);
947 else if (!strncmp(p, ".set", 4))
948 rc = set_command(p+4);
949 else
950 rc = pwmd_command(pwm, result, len, inquire_cb, inq, line);
952 return FINISH(rc);
955 #ifdef HAVE_LIBREADLINE
956 static gpg_error_t do_interactive()
958 gpg_error_t rc;
959 struct inquire_s *inq = NULL;
961 rl_initialize();
962 rc = process_cmd();
963 if (rc)
964 return rc;
966 rc = set_inquire(STDIN_FILENO, NULL, &inq);
967 if (rc)
968 return rc;
970 fprintf(stderr, N_("WARNING: interactive mode doesn't use secure memory!\n"));
971 print_help();
972 rl_event_hook = &interactive_hook;
973 rl_set_keyboard_input_timeout(100000);
975 for (;;) {
976 char *line;
977 char *result = NULL;
978 size_t len;
980 line = readline("pwm> ");
981 if (interactive_error) {
982 rc = interactive_error;
983 break;
986 if (!line) {
987 rc = finalize();
988 if (!rc)
989 break;
991 if (gpg_err_code(rc) != GPG_ERR_CANCELED &&
992 gpg_err_code(rc) != GPG_ERR_EOF)
993 fprintf(stderr, "ERR %i: %s\n", rc, gpg_strerror(rc));
995 continue;
997 else if (!*line) {
998 free(line);
999 continue;
1002 #ifdef HAVE_LIBREADLINE
1003 add_history(line);
1004 #endif
1005 inq->header = 0;
1006 rc = parse_dotcommand(line, &result, &len, inq);
1007 free(line);
1008 if (rc)
1009 fprintf(stderr, "ERR %i: %s\n", rc, gpg_strerror(rc));
1010 else if (result && len)
1011 printf("%s%s", result, result[len-1] != '\n' ? "\n" : "");
1013 pwmd_free(result);
1016 free_inquire(inq);
1017 return 0;
1019 #endif
1021 static char *itoa(long long int n)
1023 static char buf[64];
1025 snprintf(buf, sizeof(buf), "%llu", n);
1026 return buf;
1029 static gpg_error_t finalize()
1031 gpg_error_t rc = 0;
1032 #ifdef HAVE_LIBREADLINE
1033 int quit = 0;
1035 if (!force_save && interactive) {
1036 char *p, buf[16];
1037 int finished = 0;
1039 fprintf(stderr, "\n");
1041 do {
1042 fprintf(stderr, N_("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1043 p = fgets(buf, sizeof(buf), stdin);
1045 if (feof(stdin)) {
1046 clearerr(stdin);
1047 return GPG_ERR_EOF;
1050 switch (*p) {
1051 case 'h':
1052 print_help();
1053 break;
1054 case 'c':
1055 return GPG_ERR_CANCELED;
1056 case 'Q':
1057 return 0;
1058 case 'f':
1059 rc = pwmd_command(pwm, NULL, NULL, NULL, NULL,
1060 "CLEARCACHE %s", filename);
1061 if (rc)
1062 return rc;
1064 interactive_hook();
1065 break;
1066 case 'S':
1067 quit = 1;
1068 case 's':
1069 save = 1;
1070 finished = 1;
1071 break;
1072 default:
1073 break;
1075 } while (!finished);
1077 #endif
1079 if (save && !filename) {
1080 fprintf(stderr, N_("No filename was specified on the command line. Aborting.\n"));
1081 return GPG_ERR_CANCELED;
1084 if (save && filename) {
1085 char *args = pwmd_strdup_printf("%s%s %s%s %s %s%s %s%s --s2k-count=%lu",
1086 keygrip ? "--keygrip=" : "", keygrip ? keygrip : "",
1087 sign_keygrip ? "--sign-keygrip=" : "", sign_keygrip ? sign_keygrip : "",
1088 no_passphrase ? "--no-passphrase" : "",
1089 cipher ? "--cipher=" : "", cipher ? cipher : "",
1090 iterations_arg ? "--cipher-iterations=" : "", iterations_arg ? itoa(iterations) : "",
1091 s2k_count);
1093 fprintf(stderr, "\n");
1094 fprintf(stderr, N_("Saving changes ...\n"));
1095 rc = pwmd_save(pwm, args, inquire_cb, NULL);
1096 pwmd_free(args);
1098 if (!rc)
1099 no_passphrase = 0; // reset to avoid usage error on the next SAVE
1102 #ifdef HAVE_LIBREADLINE
1103 if (interactive)
1104 return rc ? rc : quit ? 0 : GPG_ERR_CANCELED;
1105 #endif
1107 return rc;
1110 int main(int argc, char *argv[])
1112 int connected = 0;
1113 gpg_error_t rc;
1114 int opt;
1115 char command[ASSUAN_LINELENGTH], *p = NULL;
1116 char *result = NULL;
1117 size_t len;
1118 char *pinentry_path = NULL;
1119 char *display = NULL, *tty = NULL, *ttytype = NULL, *lcctype = NULL,
1120 *lcmessages = NULL;
1121 int outfd = STDOUT_FILENO;
1122 FILE *outfp = stdout;
1123 FILE *inquirefp = stdin;
1124 int show_status = 1;
1125 char *clientname = "pwmc";
1126 char *inquire = NULL;
1127 char *inquire_line = NULL;
1128 int timeout = 0;
1129 #ifdef WITH_SSH
1130 int use_ssh_agent = 1;
1131 long ssh_timeout = 0;
1132 int ssh_keepalive = 0;
1133 char *knownhosts = NULL;
1134 char *identity = NULL;
1135 #endif
1136 #ifdef WITH_GNUTLS
1137 char *cacert = NULL;
1138 char *clientcert = NULL;
1139 char *clientkey = NULL;
1140 char *prio = NULL;
1141 int tls_verify = 0;
1142 #endif
1143 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1144 pwmd_socket_t socktype;
1145 #endif
1146 int lock_on_open = 1;
1147 long lock_timeout = 0;
1148 char *url = NULL;
1149 /* The order is important. */
1150 enum {
1151 #ifdef WITH_SSH
1152 OPT_USE_SSH_AGENT, OPT_IDENTITY, OPT_KNOWNHOSTS, OPT_SSH_TIMEOUT,
1153 OPT_SSH_KEEPALIVE,
1154 #endif
1155 #ifdef WITH_GNUTLS
1156 OPT_CACERT, OPT_CLIENTCERT, OPT_CLIENTKEY, OPT_PRIORITY, OPT_VERIFY,
1157 #endif
1158 OPT_URL, OPT_LOCAL, OPT_FORCE_SAVE, OPT_TTYNAME, OPT_TTYTYPE,
1159 OPT_DISPLAY, OPT_LC_CTYPE, OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES,
1160 OPT_PINENTRY, OPT_KEYFILE, OPT_NEW_KEYFILE, OPT_NOLOCK,
1161 OPT_LOCK_TIMEOUT, OPT_SAVE, OPT_OUTPUT_FD, OPT_INQUIRE,
1162 OPT_INQUIRE_FD, OPT_INQUIRE_FILE, OPT_INQUIRE_LINE, OPT_NO_STATUS,
1163 OPT_NAME, OPT_VERSION, OPT_HELP, OPT_KEYGRIP, OPT_SIGN_KEYGRIP,
1164 OPT_NOPASSPHRASE, OPT_CIPHER, OPT_KEYPARAMS, OPT_NO_PINENTRY,
1165 OPT_S2K_COUNT, OPT_ITERATIONS,
1166 #ifdef HAVE_LIBREADLINE
1167 OPT_INTERACTIVE,
1168 #endif
1170 const struct option long_opts[] = {
1171 #ifdef WITH_SSH
1172 { "no-ssh-agent", 0, 0, 0 },
1173 { "identity", 1, 0, 'i' },
1174 { "knownhosts", 1, 0, 'k' },
1175 { "ssh-timeout", 1, 0, 0 },
1176 { "ssh-keepalive", 1, 0, 0 },
1177 #endif
1178 #ifdef WITH_GNUTLS
1179 { "ca-cert", 1, 0, 0 },
1180 { "client-cert", 1, 0, 0 },
1181 { "client-key", 1, 0, 0 },
1182 { "tls-priority", 1, 0, 0 },
1183 { "tls-verify", 0, 0, 0 },
1184 #endif
1185 { "url", 1, 0, 0 },
1186 { "local-pinentry", 0, 0 },
1187 { "force-save", 0, 0 },
1188 { "ttyname", 1, 0, 'y' },
1189 { "ttytype", 1, 0, 't' },
1190 { "display", 1, 0, 'd' },
1191 { "lc-ctype", 1, 0, 0 },
1192 { "lc-messages", 1, 0, 0 },
1193 { "timeout", 1, 0, 0 },
1194 { "tries", 1, 0, 0 },
1195 { "pinentry", 1, 0, 0 },
1196 { "key-file", 1, 0, 0 },
1197 { "new-key-file", 1, 0, 0 },
1198 { "no-lock", 0, 0, 0 },
1199 { "lock-timeout", 1, 0, 0 },
1200 { "save", 0, 0, 'S' },
1201 { "output-fd", 1, 0, 0 },
1202 { "inquire", 1, 0, 0 },
1203 { "inquire-fd", 1, 0, 0 },
1204 { "inquire-file", 1, 0, 0 },
1205 { "inquire-line", 1, 0, 'L' },
1206 { "no-status", 0, 0, 0 },
1207 { "name", 1, 0, 'n' },
1208 { "version", 0, 0, 0 },
1209 { "help", 0, 0, 0 },
1210 { "keygrip", 1, 0, 0 },
1211 { "sign-keygrip", 1, 0, 0 },
1212 { "no-passphrase", 0, 0, 0 },
1213 { "cipher", 1, 0, 0 },
1214 { "key-params", 1, 0, 0 },
1215 { "no-pinentry", 0, 0, 0 },
1216 { "s2k-count", 1, 0, 0 },
1217 { "cipher-iterations", 1, 0, 0 },
1218 #ifdef HAVE_LIBREADLINE
1219 { "interactive", 0, 0 },
1220 #endif
1221 { 0, 0, 0, 0}
1223 #ifdef WITH_SSH
1224 const char *optstring = "L:y:t:d:P:I:Sn:i:k:";
1225 #else
1226 const char *optstring = "L:y:t:d:P:I:Sn:";
1227 #endif
1228 int opt_index = 0;
1230 #ifdef ENABLE_NLS
1231 setlocale(LC_ALL, "");
1232 bindtextdomain("libpwmd", LOCALEDIR);
1233 #endif
1235 #ifdef HAVE_LIBREADLINE
1236 if (!strcmp(basename(argv[0]), "pwmsh"))
1237 interactive = 1;
1238 #endif
1240 tries = DEFAULT_PIN_TRIES;
1241 inquirefd = STDIN_FILENO;
1243 while ((opt = getopt_long(argc, argv, optstring, long_opts, &opt_index)) != -1) {
1244 switch (opt) {
1245 /* Handle long options without a short option part. */
1246 case 0:
1247 switch (opt_index) {
1248 #ifdef WITH_SSH
1249 case OPT_USE_SSH_AGENT:
1250 use_ssh_agent = 0;
1251 break;
1252 case OPT_SSH_TIMEOUT:
1253 ssh_timeout = strtol(optarg, &p, 10);
1254 break;
1255 case OPT_SSH_KEEPALIVE:
1256 ssh_keepalive = strtol(optarg, &p, 10);
1257 break;
1258 #endif
1259 #ifdef WITH_GNUTLS
1260 case OPT_CACERT:
1261 cacert = optarg;
1262 break;
1263 case OPT_CLIENTCERT:
1264 clientcert = optarg;
1265 break;
1266 case OPT_CLIENTKEY:
1267 clientkey = optarg;
1268 break;
1269 case OPT_PRIORITY:
1270 prio = optarg;
1271 break;
1272 case OPT_VERIFY:
1273 tls_verify = 1;
1274 break;
1275 #endif
1276 case OPT_KEYPARAMS:
1277 keyparams = optarg;
1278 break;
1279 case OPT_KEYFILE:
1280 keyfile = pwmd_strdup(optarg);
1281 break;
1282 case OPT_NEW_KEYFILE:
1283 new_keyfile = pwmd_strdup(optarg);
1284 break;
1285 case OPT_NOLOCK:
1286 lock_on_open = 0;
1287 break;
1288 case OPT_LOCK_TIMEOUT:
1289 lock_timeout = strtol(optarg, &p, 10);
1290 break;
1291 case OPT_URL:
1292 url = optarg;
1293 break;
1294 case OPT_LOCAL:
1295 local_pin = 1;
1296 break;
1297 case OPT_FORCE_SAVE:
1298 save = force_save = 1;
1299 break;
1300 case OPT_LC_CTYPE:
1301 lcctype = pwmd_strdup(optarg);
1302 break;
1303 case OPT_LC_MESSAGES:
1304 lcmessages = pwmd_strdup(optarg);
1305 break;
1306 case OPT_TIMEOUT:
1307 timeout = strtol(optarg, &p, 10);
1308 break;
1309 case OPT_TRIES:
1310 tries = strtol(optarg, &p, 10);
1311 break;
1312 case OPT_INQUIRE:
1313 inquire = optarg;
1314 break;
1315 case OPT_INQUIRE_FD:
1316 inquirefd = strtol(optarg, &p, 10);
1317 if (!p) {
1318 inquirefp = fdopen(inquirefd, "r");
1319 if (!inquirefp) {
1320 pwmd_free(password);
1321 err(EXIT_FAILURE, "%i", inquirefd);
1324 break;
1325 case OPT_INQUIRE_FILE:
1326 inquirefd = open(optarg, O_RDONLY);
1327 if (!inquirefd == -1) {
1328 pwmd_free(password);
1329 err(EXIT_FAILURE, "%s", optarg);
1331 inquirefp = fdopen(inquirefd, "r");
1332 break;
1333 case OPT_OUTPUT_FD:
1334 outfd = strtol(optarg, &p, 10);
1335 if (!p) {
1336 outfp = fdopen(outfd, "w");
1337 if (!outfp) {
1338 pwmd_free(password);
1339 err(EXIT_FAILURE, "%i", outfd);
1342 break;
1343 case OPT_NO_STATUS:
1344 show_status = 0;
1345 break;
1346 case OPT_VERSION:
1347 pwmd_free(password);
1348 printf("%s (pwmc)\n\n"
1349 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012\n"
1350 "%s\n"
1351 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1352 "Compile-time features:\n"
1353 #ifdef WITH_SSH
1354 "+SSH "
1355 #else
1356 "-SSH "
1357 #endif
1358 #ifdef WITH_GNUTLS
1359 "+GNUTLS "
1360 #else
1361 "-GNUTLS "
1362 #endif
1363 #ifdef WITH_PINENTRY
1364 "+PINENTRY "
1365 #else
1366 "-PINENTRY "
1367 #endif
1368 #ifdef WITH_QUALITY
1369 "+CRACK "
1370 #else
1371 "-CRACK "
1372 #endif
1373 #ifdef MEM_DEBUG
1374 "+MEM_DEBUG "
1375 #else
1376 "-MEM_DEBUG "
1377 #endif
1378 #ifdef HAVE_LIBREADLINE
1379 "+INTERACTIVE "
1380 #else
1381 "-INTERACTIVE "
1382 #endif
1383 "\n"
1384 , PACKAGE_STRING, PACKAGE_BUGREPORT);
1385 exit(EXIT_SUCCESS);
1386 case OPT_PINENTRY:
1387 pinentry_path = optarg;
1388 break;
1389 case OPT_HELP:
1390 usage(argv[0], EXIT_SUCCESS);
1391 case OPT_KEYGRIP:
1392 keygrip = optarg;
1393 break;
1394 case OPT_SIGN_KEYGRIP:
1395 sign_keygrip = optarg;
1396 break;
1397 case OPT_S2K_COUNT:
1398 s2k_count = strtoul(optarg, &p, 10);
1399 break;
1400 case OPT_ITERATIONS:
1401 iterations = strtoull(optarg, &p, 10);
1402 iterations_arg = 1;
1403 break;
1404 case OPT_NOPASSPHRASE:
1405 no_passphrase = 1;
1406 break;
1407 case OPT_CIPHER:
1408 cipher = optarg;
1409 break;
1410 case OPT_NO_PINENTRY:
1411 no_pinentry = 1;
1412 break;
1413 #ifdef HAVE_LIBREADLINE
1414 case OPT_INTERACTIVE:
1415 interactive = 1;
1416 break;
1417 #endif
1418 default:
1419 usage(argv[0], EXIT_FAILURE);
1422 if (p && *p) {
1423 fprintf(stderr, N_("%s: invalid argument for option '--%s'\n"),
1424 argv[0], long_opts[opt_index].name);
1425 usage(argv[0], EXIT_FAILURE);
1428 break;
1429 #ifdef WITH_SSH
1430 case 'i':
1431 identity = optarg;
1432 break;
1433 case 'k':
1434 knownhosts = optarg;
1435 break;
1436 #endif
1437 case 'L':
1438 inquire_line = optarg;
1439 break;
1440 case 'y':
1441 tty = optarg;
1442 break;
1443 case 't':
1444 ttytype = optarg;
1445 break;
1446 case 'd':
1447 display = optarg;
1448 break;
1449 case 'S':
1450 save = 1;
1451 break;
1452 case 'n':
1453 clientname = optarg;
1454 break;
1455 default:
1456 pwmd_free(password);
1457 usage(argv[0], EXIT_FAILURE);
1461 #ifdef HAVE_LIBREADLINE
1462 if (interactive && !isatty(STDIN_FILENO)) {
1463 pwmd_free(password);
1464 usage(argv[0], EXIT_FAILURE);
1466 else if (isatty(STDIN_FILENO) && !inquire && !inquire_line)
1467 interactive = 1;
1468 #endif
1470 filename = argv[optind];
1471 #ifdef WITH_GNUTLS
1472 gnutls_global_set_mem_functions(pwmd_malloc, pwmd_malloc, NULL,
1473 pwmd_realloc, pwmd_free);
1474 #endif
1475 pwmd_init();
1476 rc = pwmd_new(clientname, &pwm);
1477 if (rc)
1478 goto done;
1480 pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
1481 fprintf(stderr, N_("Connecting ...\n"));
1483 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1484 socktype = is_remote_url(url);
1485 if (socktype != PWMD_SOCKET_LOCAL) {
1486 local_pin = 1;
1487 if (socktype == PWMD_SOCKET_SSH) {
1488 #ifdef WITH_SSH
1489 rc = pwmd_setopt(pwm, PWMD_OPTION_KNOWNHOST_CB, knownhost_cb);
1490 if (rc)
1491 goto done;
1493 rc = pwmd_setopt(pwm, PWMD_OPTION_KNOWNHOST_DATA, clientname);
1494 if (rc)
1495 goto done;
1497 if (!getenv("SSH_AUTH_SOCK") || identity)
1498 use_ssh_agent = 0;
1500 rc = pwmd_setopt(pwm, PWMD_OPTION_SSH_AGENT, use_ssh_agent);
1501 if (rc)
1502 goto done;
1504 rc = pwmd_setopt(pwm, PWMD_OPTION_SSH_TIMEOUT, ssh_timeout);
1505 if (rc)
1506 goto done;
1508 rc = pwmd_setopt(pwm, PWMD_OPTION_SSH_KEEPALIVE, ssh_keepalive);
1509 if (rc)
1510 goto done;
1512 rc = pwmd_connect(pwm, url, identity, knownhosts);
1513 #endif
1515 #ifdef WITH_GNUTLS
1516 else {
1517 rc = pwmd_setopt(pwm, PWMD_OPTION_TLS_VERIFY, tls_verify);
1518 if (rc)
1519 goto done;
1521 rc = pwmd_connect(pwm, url, clientcert, clientkey, cacert, prio);
1523 #endif
1525 else
1526 rc = pwmd_connect(pwm, url);
1527 #else
1528 rc = pwmd_connect(pwm, url);
1529 #endif
1530 if (rc)
1531 goto done;
1533 fprintf(stderr, N_("Connected.\n"));
1534 connected = 1;
1535 if (lock_timeout) {
1536 rc = pwmd_command(pwm, NULL, NULL, NULL, NULL,
1537 "OPTION LOCK-TIMEOUT=%li", lock_timeout);
1538 if (rc)
1539 goto done;
1542 if (lock_on_open) {
1543 rc = pwmd_setopt(pwm, PWMD_OPTION_LOCK_ON_OPEN, 1);
1544 if (rc)
1545 goto done;
1548 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_DESC, NULL);
1549 if (rc)
1550 goto done;
1552 if (timeout > 0) {
1553 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
1554 if (rc)
1555 goto done;
1558 rc = pwmd_setopt(pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1559 if (rc)
1560 goto done;
1562 rc = pwmd_setopt(pwm, PWMD_OPTION_LOCAL_PINENTRY,
1563 (local_pin || keyfile || new_keyfile));
1564 if (rc)
1565 goto done;
1567 if (pinentry_path) {
1568 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
1569 if (rc)
1570 goto done;
1573 if (display) {
1574 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
1575 if (rc)
1576 goto done;
1579 if (tty) {
1580 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TTY, tty);
1581 if (rc)
1582 goto done;
1585 if (ttytype) {
1586 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
1587 if (rc)
1588 goto done;
1591 if (lcctype) {
1592 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
1593 if (rc)
1594 goto done;
1597 if (lcmessages) {
1598 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES,
1599 lcmessages);
1600 if (rc)
1601 goto done;
1604 if (show_status) {
1605 rc = pwmd_setopt(pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
1606 if (rc)
1607 goto done;
1610 if (filename) {
1611 rc = open_command(filename);
1612 if (rc)
1613 goto done;
1616 #ifdef HAVE_LIBREADLINE
1617 if (interactive) {
1618 if (!force_save)
1619 save = 0;
1621 rc = do_interactive();
1622 goto do_exit;
1624 #endif
1626 if (inquire) {
1627 struct inquire_s *inq = NULL;
1629 rc = set_inquire(inquirefd, inquire_line, &inq);
1630 if (!rc)
1631 rc = pwmd_command(pwm, &result, &len, inquire_cb, inq, inquire);
1633 free_inquire(inq);
1634 goto done;
1637 fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
1638 ssize_t n;
1640 for (;;) {
1641 rc = process_cmd();
1643 if (rc)
1644 goto done;
1646 n = read(STDIN_FILENO, command, sizeof(command));
1647 if (n == -1) {
1648 if (errno == EAGAIN) {
1649 usleep(100000);
1650 continue;
1653 rc = gpg_error_from_errno(errno);
1654 goto done;
1656 else if (!n)
1657 goto done;
1659 p = command;
1660 command[n] = 0;
1661 break;
1664 if (!p || !*p || !strcasecmp(p, "BYE"))
1665 goto done;
1668 struct inquire_s *inq = NULL;
1669 rc = set_inquire(inquirefd, inquire_line, &inq);
1670 if (!rc) {
1671 rc = parse_dotcommand(command, &result, &len, inq);
1672 free_inquire(inq);
1675 if (rc)
1676 goto done;
1678 done:
1679 if (result) {
1680 fwrite(result, 1, result[len-1] == 0 ? len-1 : len, outfp);
1681 fflush(outfp);
1682 pwmd_free(result);
1685 pwmd_free(password);
1686 password = NULL;
1687 if (!rc)
1688 rc = finalize();
1690 #ifdef HAVE_LIBREADLINE
1691 do_exit:
1692 #endif
1693 memset(command, 0, sizeof(command));
1694 pwmd_close(pwm);
1695 pwmd_free(keyfile);
1696 pwmd_free(new_keyfile);
1697 pwmd_deinit();
1699 if (rc)
1700 show_error(rc);
1702 if (connected)
1703 fprintf(stderr, N_("Connection closed.\n"));
1705 exit(rc ? EXIT_FAILURE : EXIT_SUCCESS);