pwmc: add --prefix option to the .read command.
[libpwmd.git] / src / pwmc.c
blobe68bb66c8dc8db6c4a8fb5a0756e9a74d9f3aab6
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;
106 static int quiet;
108 struct inquire_s {
109 int fd;
110 char *line;
111 size_t len;
112 size_t size; // from stat(2).
113 int header;
116 static gpg_error_t finalize();
117 static gpg_error_t set_inquire(int fd, const char *line,
118 struct inquire_s **result);
119 static gpg_error_t parse_dotcommand(const char *line, char **result,
120 size_t *len, struct inquire_s *inq);
121 static gpg_error_t open_command(const char *line);
122 #ifdef WITH_SSH
123 static gpg_error_t get_password(char **result, pwmd_pinentry_t w, int echo);
124 #endif
126 static void show_error(gpg_error_t error)
128 fprintf(stderr, "ERR %i %s\n", error, gpg_strerror(error));
131 static void usage(const char *pn, int status)
133 fprintf(status == EXIT_FAILURE ? stderr : stdout, N_(
134 "Read a PWMD protocol command from standard input.\n\n"
135 "Usage: pwmc [options] [file]\n"
136 " --url <string>\n"
137 " a url string to connect to (see below)\n"
138 #ifdef WITH_SSH
139 " --no-ssh-agent\n"
140 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
141 " --identity, -i <filename>\n"
142 " the ssh identity file to use for authentication\n"
143 " --knownhosts, -k <filename>\n"
144 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
145 " --ssh-timeout <seconds>\n"
146 " timeout before a remote command fails (0=disabled, default)\n"
147 " --ssh-keepalive <seconds>\n"
148 " interval to send a keepalive to the remote server (0=disabled, default)\n"
149 #endif
150 #ifdef WITH_GNUTLS
151 " --ca-cert <filename>\n"
152 " certificate authority (CA) used to sign the server cert\n"
153 " --client-cert <filename>\n"
154 " client certificate to use for authentication\n"
155 " --client-key <filename>\n"
156 " key file used to protect the client certificate\n"
157 " --tls-priority <string>\n"
158 " compression, cipher and hash algorithm string (SECURE256)\n"
159 " --tls-verify\n"
160 " verify the hostname against the server certificate\n"
161 #endif
162 " --no-lock\n"
163 " do not lock the data file upon opening it\n"
164 " --lock-timeout <N>\n"
165 " time in tenths of a second to wait for a locked data file\n"
166 " --no-status\n"
167 " disable showing of status messages from the server\n"
168 " --quiet\n"
169 " disable showing of extra messages (implies --no-status)\n"
170 " --name, -n <string>\n"
171 " set the client name\n"
172 " --no-passphrase\n"
173 " do not require a passphrase when saving a new file\n"
174 " --keygrip <string>\n"
175 " the hex string of the keygrip to save to\n"
176 " --sign-keygrip <string>\n"
177 " the hex string of the keygrip to sign with\n"
178 " --key-file <filename>\n"
179 " obtain the passphrase from the specified filename\n"
180 " --new-key-file <filename>\n"
181 " obtain the passphrase to save with from the specified filename\n"
182 " --s2k-count <N>\n"
183 " the number of times to hash the passphrase for a new file\n"
184 " --cipher-iterations <N>\n"
185 " the number of times to encrypt the XML data (N+1)\n"
186 " --timeout <seconds>\n"
187 " pinentry timeout\n"
188 " --tries <N>\n"
189 " number of pinentry tries before failing (3)\n"
190 " --no-pinentry\n"
191 " disable pinentry both remotely and locally\n"
192 " --pinentry <path>\n"
193 " the full path to the pinentry binary (server default)\n"
194 " --ttyname, -y <path>\n"
195 " tty that pinentry will use\n"
196 " --ttytype, -t <string>\n"
197 " pinentry terminal type (default is $TERM)\n"
198 " --display, -d\n"
199 " pinentry display (default is $DISPLAY)\n"
200 " --lc-ctype <string>\n"
201 " locale setting for pinentry\n"
202 " --lc-messages <string>\n"
203 " locale setting for pinentry\n"
204 " --local-pinentry\n"
205 " force using a local pinentry\n"
206 #ifdef HAVE_LIBREADLINE
207 " --interactive\n"
208 " use a shell like interface to pwmd (allows more than one command)\n"
209 #endif
210 " --output-fd <FD>\n"
211 " redirect command output to the specified file descriptor\n"
212 " --inquire <COMMAND>\n"
213 " the specified command (with any options) uses a server inquire while\n"
214 " command data is read via the inquire file descriptor (stdin)\n"
215 " --inquire-fd <FD>\n"
216 " read inquire data from the specified file descriptor (stdin)\n"
217 " --inquire-file <filename>\n"
218 " read inquire data from the specified filename\n"
219 " --inquire-line, -L <STRING>\n"
220 " the initial line to send (i.e., element path) before the inquire data\n"
221 " --cipher <string>\n"
222 " the cipher to use when saving (see pwmd(1))\n"
223 " --save, -S\n"
224 " send the SAVE command before exiting\n"
225 " --key-params <string>\n"
226 " the key parameters to use when saving a new file (pwmd default)\n"
227 " --force-save\n"
228 " like --save but always ask for a passphrase\n"
229 " --version\n"
230 " --help\n"));
231 fprintf(status == EXIT_FAILURE ? stderr : stdout, N_(
232 "\n"
233 "An optional url may be in the form of:\n"
234 " --url /path/to/socket\n"
235 " --url file://[path/to/socket]\n"
236 #ifdef WITH_SSH
237 " or\n"
238 " --url ssh[46]://[username@]hostname[:port]\n"
239 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
240 #endif
241 #ifdef WITH_GNUTLS
242 " or\n"
243 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
244 " --client-key filename\n"
245 #endif
247 exit(status);
250 static gpg_error_t inquire_cb(void *user, const char *keyword, gpg_error_t rc,
251 char **data, size_t *size)
253 struct inquire_s *inq = user;
254 int is_password = 0;
255 int is_newpassword = 0;
257 *data = NULL;
258 *size = 0;
260 if (rc)
261 return rc;
263 if (!strcmp(keyword, "PASSPHRASE"))
264 is_password = 1;
265 else if (!strcmp(keyword, "NEW_PASSPHRASE"))
266 is_newpassword = 1;
267 #ifdef HAVE_LIBREADLINE
268 else if (!strcmp(keyword, "KEYPARAM") && !interactive) {
269 #else
270 else if (!strcmp(keyword, "KEYPARAM")) {
271 #endif
272 if (!keyparams || !*keyparams)
273 return gpg_error(GPG_ERR_INV_PARAMETER);
275 *data = keyparams;
276 *size = strlen(keyparams);
277 return gpg_error(GPG_ERR_EOF);
280 if ((is_newpassword && new_keyfile) || (is_password && keyfile)) {
281 int fd = open(is_password ? keyfile : new_keyfile, O_RDONLY);
283 if (fd == -1) {
284 fprintf(stderr, "%s: %s\n", is_newpassword ? new_keyfile : keyfile,
285 strerror(errno));
286 return gpg_error_from_syserror();
289 rc = set_inquire(fd, NULL, &inq);
290 if (rc) {
291 close(fd);
292 return rc;
295 if (!quiet)
296 fprintf(stderr, N_("Using keyfile '%s' as %s.\n"),
297 is_newpassword ? new_keyfile : keyfile, keyword);
299 if (!new_keyfile || is_newpassword) {
300 pwmd_socket_t t;
302 pwmd_socket_type(pwm, &t);
303 pwmd_setopt(pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
304 if (!no_pinentry && t == PWMD_SOCKET_LOCAL)
305 pwmd_setopt(pwm, PWMD_OPTION_NO_PINENTRY, 0);
308 else if (is_password && !keyfile) {
309 char *tmp;
311 rc = pwmd_password(pwm, keyword, &tmp, &inq->len);
312 if (rc && gpg_err_code(rc) != GPG_ERR_EOF)
313 return rc;
315 pwmd_free(inq->line);
316 inq->line = tmp;
317 *data = inq->line;
318 *size = inq->len;
319 return gpg_error(GPG_ERR_EOF);
321 #ifdef HAVE_LIBREADLINE
322 else if (!inq->header && interactive) {
323 fprintf(stderr, N_(
324 "Press CTRL-D to send the current line. Press twice to end. %s:\n"), keyword);
325 inq->header = 1;
327 #endif
329 /* The first part of the command data. */
330 if (inq->len) {
331 *data = inq->line;
332 *size = inq->len;
333 inq->len = 0;
334 return inq->fd == -1 ? gpg_error(GPG_ERR_EOF) : 0;
337 *size = read(inq->fd, inq->line, ASSUAN_LINELENGTH);
338 if (*size == -1) {
339 *size = 0;
340 return gpg_error(gpg_error_from_syserror());
342 else if (*size)
343 *data = inq->line;
345 if (((is_newpassword && new_keyfile) || (is_password && keyfile))
346 && *size == inq->size)
347 return gpg_error(GPG_ERR_EOF);
349 return *size ? 0 : gpg_error(GPG_ERR_EOF);
352 static int status_msg_cb(void *data, const char *line)
354 char *p = strchr(line, ' ');
356 if (!strcmp(line, "KEEPALIVE"))
357 return 0;
359 if (*line != '#' && p && strchr(p, ' ') && *++p) {
360 char *p1 = strchr(p, ' ');
361 int a = strtol(p, NULL, 10);
363 if (isdigit(*p) && p1) {
364 int b = strtol(p1, NULL, 10);
365 char l[64] = {0};
366 int t = a && b ? a*100/b : 0;
368 strncpy(l, line, strlen(line)-strlen(p)-1);
369 fprintf(stderr, "\r%s %i/%i %i%%%s", l, a, b, t, a == b ? "\n" : "");
370 fflush(stderr);
371 return 0;
375 fprintf(stderr, "%s\n", line);
376 fflush(stderr);
377 #ifdef HAVE_LIBREADLINE
378 rl_on_new_line();
379 #endif
380 return 0;
383 static gpg_error_t process_cmd()
385 return pwmd_process(pwm);
388 #ifdef WITH_SSH
389 static gpg_error_t get_password(char **result, pwmd_pinentry_t w, int echo)
391 char buf[LINE_MAX] = {0}, *p;
392 struct termios told, tnew;
393 char *key = NULL;
395 *result = NULL;
397 if (!isatty(STDIN_FILENO)) {
398 fprintf(stderr, N_("Input is not from a terminal! Failing.\n"));
399 return GPG_ERR_ENOTTY;
402 if (!echo) {
403 if (tcgetattr(STDIN_FILENO, &told) == -1)
404 return gpg_error_from_syserror();
406 memcpy(&tnew, &told, sizeof(struct termios));
407 tnew.c_lflag &= ~(ECHO);
408 tnew.c_lflag |= ICANON|ECHONL;
410 if (tcsetattr(STDIN_FILENO, TCSANOW, &tnew) == -1) {
411 int n = errno;
413 tcsetattr(STDIN_FILENO, TCSANOW, &told);
414 return gpg_error_from_errno(n);
418 switch (w) {
419 case PWMD_PINENTRY_OPEN:
420 fprintf(stderr, N_("Password for %s: "), filename);
421 break;
422 case PWMD_PINENTRY_OPEN_FAILED:
423 fprintf(stderr, N_("Invalid password. Password for %s: "), filename);
424 break;
425 case PWMD_PINENTRY_SAVE:
426 fprintf(stderr, N_("New password for %s: "), filename);
427 break;
428 case PWMD_PINENTRY_SAVE_CONFIRM:
429 fprintf(stderr, N_("Confirm password: "));
430 break;
431 default:
432 break;
435 if ((p = fgets(buf, sizeof(buf), stdin)) == NULL) {
436 tcsetattr(STDIN_FILENO, TCSANOW, &told);
437 return 0;
440 if (!echo)
441 tcsetattr(STDIN_FILENO, TCSANOW, &told);
443 if (feof(stdin)) {
444 clearerr(stdin);
445 return GPG_ERR_CANCELED;
448 p[strlen(p) - 1] = 0;
450 if (buf[0]) {
451 key = pwmd_strdup_printf("%s", p);
452 memset(&buf, 0, sizeof(buf));
454 if (!key)
455 return GPG_ERR_ENOMEM;
458 *result = key;
459 return 0;
462 static gpg_error_t knownhost_cb(void *data, const char *host, const char *key,
463 size_t len)
465 gpg_error_t rc;
466 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);
468 if (no_pinentry && !isatty(STDIN_FILENO)) {
469 fprintf(stderr, N_("Input is not from a terminal! Failing.\n"));
470 pwmd_free(buf);
471 return GPG_ERR_ENOTTY;
473 else if (no_pinentry) {
474 for (char *p = buf, len = 0; *p; p++, len++) {
475 if (*p == '\n')
476 len = 0;
478 if (len == 78) {
479 char *t = p;
481 while (!isspace(*(--p)));
482 *p = '\n';
483 p = t;
484 len = 0;
488 fprintf(stderr, "%s\n\n", buf);
489 pwmd_free(buf);
491 do {
492 char *result;
494 fprintf(stderr, N_("Trust this connection [y/N]: "));
495 fflush(stderr);
496 rc = get_password(&result, PWMD_PINENTRY_CONFIRM, 1);
498 if (rc)
499 return rc;
501 if (!result || !*result || *result == 'n' || *result == 'N') {
502 if (result && *result)
503 pwmd_free(result);
505 return GPG_ERR_NOT_CONFIRMED;
508 if ((*result == 'y' || *result == 'Y') && *(result+1) == 0) {
509 pwmd_free(result);
510 return 0;
512 } while (1);
515 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_DESC, buf);
516 pwmd_free(buf);
518 if (rc)
519 return rc;
521 return pwmd_getpin(pwm, NULL, NULL, NULL, PWMD_PINENTRY_CONFIRM);
523 #endif
525 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
526 static pwmd_socket_t is_remote_url(const char *str)
528 if (!str)
529 return PWMD_SOCKET_LOCAL;
531 #ifdef WITH_SSH
532 if (strstr(str, "ssh://") || strstr(str, "ssh4://")
533 || strstr(str, "ssh6://"))
534 return PWMD_SOCKET_SSH;
535 #endif
537 #ifdef WITH_GNUTLS
538 if (strstr(str, "tls://") || strstr(str, "tls4://")
539 || strstr(str, "tls6://"))
540 return PWMD_SOCKET_TLS;
541 #endif
543 return PWMD_SOCKET_LOCAL;
545 #endif
547 static char *escape(const char *str)
549 const char *p;
550 char *buf = pwmd_malloc(ASSUAN_LINELENGTH+1), *b = buf;
551 size_t len = 0;
553 for (p = str; *p; p++, len++) {
554 if (len == ASSUAN_LINELENGTH)
555 break;
557 if (*p == '\\') {
558 switch (*++p) {
559 case 't':
560 *b++ = '\t';
561 break;
562 case 'n':
563 *b++ = '\n';
564 break;
565 case 'v':
566 *b++ = '\v';
567 break;
568 case 'b':
569 *b++ = '\b';
570 break;
571 case 'f':
572 *b++ = '\f';
573 break;
574 case 'r':
575 *b++ = '\r';
576 break;
577 default:
578 *b++ = *p;
579 break;
582 if (!*p)
583 break;
585 continue;
588 *b++ = *p;
591 *b = 0;
592 return buf;
595 static void free_inquire(struct inquire_s *inq)
597 if (!inq)
598 return;
600 pwmd_free(inq->line);
602 if (inq->fd != -1 && inq->fd != STDIN_FILENO)
603 close(inq->fd);
605 pwmd_free(inq);
608 /* When *result is not NULL it is updated to the new values and not
609 * reallocated. */
610 static gpg_error_t set_inquire(int fd, const char *line,
611 struct inquire_s **result)
613 struct inquire_s inq = {0};
614 struct stat st = {0};
615 gpg_error_t rc;
617 if (fd != -1) {
618 if (fstat(fd, &st) == -1)
619 return gpg_error_from_syserror();
621 inq.size = st.st_size;
624 inq.fd = fd;
625 inq.line = pwmd_calloc(1, ASSUAN_LINELENGTH);
626 if (!inq.line)
627 return GPG_ERR_ENOMEM;
629 if (line) {
630 char *s = escape(line);
632 if (!s) {
633 pwmd_free(inq.line);
634 return GPG_ERR_ENOMEM;
637 if (strlen(s) >= ASSUAN_LINELENGTH) {
638 pwmd_free(inq.line);
639 pwmd_free(s);
640 return GPG_ERR_LINE_TOO_LONG;
643 strncpy(inq.line, s, ASSUAN_LINELENGTH-1);
644 inq.len = strlen(s);
645 pwmd_free(s);
648 rc = pwmd_setopt(pwm, PWMD_OPTION_INQUIRE_TOTAL,
649 st.st_size ? st.st_size+strlen(inq.line) : 0);
650 if (rc) {
651 pwmd_free(inq.line);
652 return rc;
655 if (*result == NULL)
656 *result = pwmd_malloc(sizeof(struct inquire_s));
657 else {
658 if ((*result)->fd != -1 && (*result)->fd != STDIN_FILENO)
659 close((*result)->fd);
661 pwmd_free((*result)->line);
662 (*result)->line = NULL;
663 (*result)->fd = -1;
664 (*result)->len = 0;
667 memcpy(*result, &inq, sizeof(struct inquire_s));
668 memset(&inq, 0, sizeof(struct inquire_s));
669 return rc;
672 #ifdef HAVE_LIBREADLINE
673 static int interactive_hook(void)
675 interactive_error = process_cmd();
677 if (interactive_error)
678 rl_event_hook = NULL;
680 return 0;
683 static void print_help()
685 fprintf(stderr, N_(
686 "------------------------------------------------------------------------------\n"
687 "Elements are TAB delimited. Press CTRL-V then TAB to insert from the prompt.\n"
688 "\n"
689 "Type HELP for protocol commands. Type .help for pwmc commands. Press CTRL-D\n"
690 "to quit.\n"
691 "------------------------------------------------------------------------------\n"
694 #endif
696 static char *parse_arg(const char *src, char *dst, size_t len)
698 char *p = dst;
699 const char *s = src;
700 size_t n = 0;
702 for (; s && *s && *s != ' ' && n < len; s++, n++)
703 *p++ = *s;
705 *p = 0;
706 return dst;
709 static char *parse_opt(char **line, const char *opt, gpg_error_t *rc)
711 static char result[ASSUAN_LINELENGTH] = {0}, *r = result;
712 size_t len = 0;
713 char *s = strstr(*line, opt);
715 *rc = 0;
716 result[0] = 0;
717 r = result;
719 if (s) {
720 int quote = 0;
721 size_t rlen = strlen(opt);
722 char *p = s+rlen;
723 int lastc = 0;
725 while (*p && *p == ' ') {
726 rlen++;
727 p++;
730 for (; *p && len < sizeof(result)-1; p++, rlen++) {
731 if (isspace(*p) && !quote)
732 break;
734 if (*p == '\"' && lastc != '\\') {
735 quote = !quote;
736 lastc = *p;
737 continue;
740 *r++ = lastc = *p;
741 len++;
744 *r = 0;
746 if (len >= sizeof(result)-1)
747 *rc = GPG_ERR_LINE_TOO_LONG;
748 else {
749 p = s+rlen;
751 while (*p && *p == ' ')
752 p++;
754 *line = p;
758 return result;
761 static gpg_error_t read_command(const char *line, char **result, size_t *len)
763 int fd;
764 gpg_error_t rc = 0;
765 char filebuf[ASSUAN_LINELENGTH];
766 char *filename = NULL;
767 struct inquire_s *inq = NULL;
768 char *p = (char *)line;
769 const char *prefix = parse_opt(&p, "--prefix", &rc);
771 if (rc)
772 return rc;
774 rc = GPG_ERR_SYNTAX;
776 if (p && *p) {
777 while (*p && isspace(*p))
778 p++;
780 filename = parse_arg(p, filebuf, sizeof(filebuf));
781 if (filename && *filename) {
782 p += strlen(filename)+1;
784 while (*p && isspace(*p))
785 p++;
787 if (*p)
788 rc = 0;
792 if (rc) {
793 fprintf(stderr, N_("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
794 fprintf(stderr, N_("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\" = \")\n"));
795 return rc;
798 fd = open(filename, O_RDONLY);
799 if (fd == -1)
800 return gpg_error_from_syserror();
802 rc = set_inquire(fd, prefix && *prefix ? prefix : NULL, &inq);
803 if (rc) {
804 close(fd);
805 return rc;
808 inq->header = 1;
809 rc = pwmd_command(pwm, result, len, inquire_cb, inq, p);
810 free_inquire(inq);
811 return rc;
814 static gpg_error_t redir_command(const char *line)
816 const char *p = line;
817 int fd;
818 gpg_error_t rc = GPG_ERR_SYNTAX;
819 char filebuf[ASSUAN_LINELENGTH];
820 char *filename = NULL;
821 struct inquire_s *inq = NULL;
822 char *result = NULL;
823 size_t len = 0;
825 if (p && *p && *++p) {
826 filename = parse_arg(p, filebuf, sizeof(filebuf));
827 if (filename && *filename) {
828 p += strlen(filename)+1;
830 while (*p && isspace(*p))
831 p++;
833 if (*p)
834 rc = 0;
838 if (rc) {
839 fprintf(stderr, N_("Usage: .redir <filename> <command> [args]\n"));
840 return rc;
843 fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0600);
844 if (fd == -1)
845 return gpg_error_from_syserror();
847 #ifdef HAVE_LIBREADLINE
848 rc = set_inquire(interactive ? STDIN_FILENO : inquirefd, NULL, &inq);
849 #else
850 rc = set_inquire(inquirefd, NULL, &inq);
851 #endif
852 if (rc) {
853 close(fd);
854 return rc;
857 rc = parse_dotcommand(p, &result, &len, inq);
858 if (!rc && result && len--) { // null byte which is always appended
859 if (write(fd, result, len) != len)
860 rc = GPG_ERR_TOO_SHORT;
861 pwmd_free(result);
864 free_inquire(inq);
865 close(fd);
866 return rc;
869 static gpg_error_t help_command(const char *line)
871 fprintf(stderr, N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
872 " .redir <filename> <command>\n"
873 " redirect the output of a command to the specified file\n"
874 "\n"
875 " .open <filename>\n"
876 " open the specified filename losing any changes to the current one\n"
877 "\n"
878 " .read [--prefix <string>] <filename> <command> [args]\n"
879 " obtain data from the specified filename for an inquire command\n"
880 "\n"
881 " .set help | <name> [<value>]\n"
882 " set option <name> to <value>\n"
883 "\n"
884 " .help\n"
885 " this help text\n"));
886 return 0;
889 static gpg_error_t open_command(const char *line)
891 struct inquire_s *inq = NULL;
892 const char *filename = line;
893 gpg_error_t rc;
895 while (filename && isspace(*filename))
896 filename++;
898 if (!filename || !*filename) {
899 fprintf(stderr, N_("Usage: .open <filename>\n"));
900 return GPG_ERR_SYNTAX;
903 if (interactive || !quiet)
904 fprintf(stderr, N_("Opening data file \"%s\" ...\n"), filename);
906 #ifdef HAVE_LIBREADLINE
907 rc = set_inquire(interactive ? STDIN_FILENO : -1, NULL, &inq);
908 #else
909 rc = set_inquire(-1, NULL, &inq);
910 #endif
911 if (rc)
912 return rc;
914 if (keyfile)
915 pwmd_setopt(pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
917 #ifdef HAVE_LIBREADLINE
918 // For safety. This file may be a different one. Make the user set it
919 // again if needed.
920 if (interactive) {
921 pwmd_free(new_keyfile);
922 new_keyfile = NULL;
924 #endif
926 rc = pwmd_open(pwm, filename, inquire_cb, inq);
927 free_inquire(inq);
928 return rc;
931 static gpg_error_t set_command(const char *line)
933 gpg_error_t rc = 0;
934 char name[256] = {0};
935 char value[512] = {0};
936 char *namep;
937 char *valuep;
938 const char *p = line;
940 while (p && *p && isspace(*p))
941 p++;
943 namep = parse_arg(p, name, sizeof(name));
944 if (!namep || !*namep) {
945 fprintf(stderr, N_("Usage: .set help | <name> [<value>]\n"));
946 return GPG_ERR_SYNTAX;
949 p += strlen(namep);
950 while (p && *p && isspace(*p))
951 p++;
953 valuep = parse_arg(p, value, sizeof(value));
955 if (!strcmp(name, "keyfile") || !strcmp(name, "new-keyfile")) {
956 int is_newkeyfile = 1;
958 if (!strcmp(name, "keyfile"))
959 is_newkeyfile = 0;
961 if (is_newkeyfile) {
962 pwmd_free(new_keyfile);
963 new_keyfile = NULL;
965 else {
966 pwmd_free(keyfile);
967 keyfile = NULL;
970 if (*valuep) {
971 if (is_newkeyfile)
972 new_keyfile = pwmd_strdup(value);
973 else
974 keyfile = pwmd_strdup(value);
976 rc = pwmd_command(pwm, NULL, NULL, NULL, NULL, "AGENT option pinentry-mode=loopback");
977 if (!rc) {
978 rc = pwmd_setopt(pwm, PWMD_OPTION_NO_PINENTRY, 1);
979 rc = pwmd_setopt(pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
982 else if (!local_pin && !no_pinentry) {
983 pwmd_socket_t t;
985 pwmd_socket_type(pwm, &t);
986 if (t == PWMD_SOCKET_LOCAL) {
987 rc = pwmd_setopt(pwm, PWMD_OPTION_NO_PINENTRY, 0);
988 rc = pwmd_setopt(pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
992 else if (!strcmp(name, "help")) {
993 fprintf(stderr, N_(
994 "Set a libpwmd or pwmc option. The option name and optional value is space\n"
995 "delimited. When no value is specified the option is unset.\n\n"
996 "keyfile [<filename>]\n"
997 " set or unset the keyfile to be used when a passphrase is required\n"
998 "\n"
999 "new-keyfile [<filename>]\n"
1000 " set or unset the keyfile to be used when a new passphrase is required\n"
1003 else
1004 rc = GPG_ERR_UNKNOWN_OPTION;
1006 return rc;
1009 static gpg_error_t parse_dotcommand(const char *line, char **result,
1010 size_t *len, struct inquire_s *inq)
1012 const char *p = line;
1013 gpg_error_t rc = 0;
1015 if (!strncmp(p, ".read", 5))
1016 rc = read_command(p+5, result, len);
1017 else if (!strncmp(p, ".redir", 6))
1018 rc = redir_command(p+6);
1019 else if (!strncmp(p, ".help", 5))
1020 rc = help_command(p+5);
1021 else if (!strncmp(p, ".open", 5))
1022 rc = open_command(p+5);
1023 else if (!strncmp(p, ".set", 4))
1024 rc = set_command(p+4);
1025 else
1026 rc = pwmd_command(pwm, result, len, inquire_cb, inq, line);
1028 return FINISH(rc);
1031 #ifdef HAVE_LIBREADLINE
1032 static gpg_error_t do_interactive()
1034 gpg_error_t rc;
1035 struct inquire_s *inq = NULL;
1037 rl_initialize();
1038 rc = process_cmd();
1039 if (rc)
1040 return rc;
1042 rc = set_inquire(STDIN_FILENO, NULL, &inq);
1043 if (rc)
1044 return rc;
1046 fprintf(stderr, N_("WARNING: interactive mode doesn't use secure memory!\n"));
1047 print_help();
1048 rl_event_hook = &interactive_hook;
1049 rl_set_keyboard_input_timeout(100000);
1051 for (;;) {
1052 char *line;
1053 char *result = NULL;
1054 size_t len;
1056 line = readline("pwm> ");
1057 if (interactive_error) {
1058 rc = interactive_error;
1059 break;
1062 if (!line) {
1063 rc = finalize();
1064 if (!rc)
1065 break;
1067 if (gpg_err_code(rc) != GPG_ERR_CANCELED &&
1068 gpg_err_code(rc) != GPG_ERR_EOF)
1069 fprintf(stderr, "ERR %i: %s\n", rc, gpg_strerror(rc));
1071 continue;
1073 else if (!*line) {
1074 free(line);
1075 continue;
1078 #ifdef HAVE_READLINE_HISTORY
1079 add_history(line);
1080 #endif
1081 inq->header = 0;
1082 rc = parse_dotcommand(line, &result, &len, inq);
1083 free(line);
1084 if (rc)
1085 fprintf(stderr, "ERR %i: %s\n", rc, gpg_strerror(rc));
1086 else if (result && len)
1087 printf("%s%s", result, result[len-1] != '\n' ? "\n" : "");
1089 pwmd_free(result);
1092 free_inquire(inq);
1093 return 0;
1095 #endif
1097 static char *itoa(long long int n)
1099 static char buf[64];
1101 snprintf(buf, sizeof(buf), "%llu", n);
1102 return buf;
1105 static gpg_error_t finalize()
1107 gpg_error_t rc = 0;
1108 #ifdef HAVE_LIBREADLINE
1109 int quit = 0;
1111 if (!force_save && interactive) {
1112 char *p, buf[16];
1113 int finished = 0;
1115 fprintf(stderr, "\n");
1117 do {
1118 fprintf(stderr, N_("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1119 p = fgets(buf, sizeof(buf), stdin);
1121 if (feof(stdin)) {
1122 clearerr(stdin);
1123 return GPG_ERR_EOF;
1126 switch (*p) {
1127 case 'h':
1128 print_help();
1129 break;
1130 case 'c':
1131 return GPG_ERR_CANCELED;
1132 case 'Q':
1133 return 0;
1134 case 'f':
1135 rc = pwmd_command(pwm, NULL, NULL, NULL, NULL,
1136 "CLEARCACHE %s", filename);
1137 if (rc)
1138 return rc;
1140 interactive_hook();
1141 break;
1142 case 'S':
1143 quit = 1;
1144 case 's':
1145 save = 1;
1146 finished = 1;
1147 break;
1148 default:
1149 break;
1151 } while (!finished);
1153 #endif
1155 if (save && !filename) {
1156 fprintf(stderr, N_("No filename was specified on the command line. Aborting.\n"));
1157 return GPG_ERR_CANCELED;
1160 if (save && filename) {
1161 char *args = pwmd_strdup_printf("%s%s %s%s %s %s%s %s%s --s2k-count=%lu",
1162 keygrip ? "--keygrip=" : "", keygrip ? keygrip : "",
1163 sign_keygrip ? "--sign-keygrip=" : "", sign_keygrip ? sign_keygrip : "",
1164 no_passphrase ? "--no-passphrase" : "",
1165 cipher ? "--cipher=" : "", cipher ? cipher : "",
1166 iterations_arg ? "--cipher-iterations=" : "", iterations_arg ? itoa(iterations) : "",
1167 s2k_count);
1169 if (!quiet || interactive) {
1170 fprintf(stderr, "\n");
1171 fprintf(stderr, N_("Saving changes ...\n"));
1174 rc = pwmd_save(pwm, args, inquire_cb, NULL);
1175 pwmd_free(args);
1177 if (!rc)
1178 no_passphrase = 0; // reset to avoid usage error on the next SAVE
1181 #ifdef HAVE_LIBREADLINE
1182 if (interactive)
1183 return rc ? rc : quit ? 0 : GPG_ERR_CANCELED;
1184 #endif
1186 return rc;
1189 int main(int argc, char *argv[])
1191 int connected = 0;
1192 gpg_error_t rc;
1193 int opt;
1194 char command[ASSUAN_LINELENGTH], *p = NULL;
1195 char *result = NULL;
1196 size_t len;
1197 char *pinentry_path = NULL;
1198 char *display = NULL, *tty = NULL, *ttytype = NULL, *lcctype = NULL,
1199 *lcmessages = NULL;
1200 int outfd = STDOUT_FILENO;
1201 FILE *outfp = stdout;
1202 FILE *inquirefp = stdin;
1203 int show_status = 1;
1204 char *clientname = "pwmc";
1205 char *inquire = NULL;
1206 char *inquire_line = NULL;
1207 int timeout = 0;
1208 #ifdef WITH_SSH
1209 int use_ssh_agent = 1;
1210 long ssh_timeout = 0;
1211 int ssh_keepalive = 0;
1212 char *knownhosts = NULL;
1213 char *identity = NULL;
1214 #endif
1215 #ifdef WITH_GNUTLS
1216 char *cacert = NULL;
1217 char *clientcert = NULL;
1218 char *clientkey = NULL;
1219 char *prio = NULL;
1220 int tls_verify = 0;
1221 #endif
1222 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1223 pwmd_socket_t socktype;
1224 #endif
1225 int lock_on_open = 1;
1226 long lock_timeout = 0;
1227 char *url = NULL;
1228 /* The order is important. */
1229 enum {
1230 #ifdef WITH_SSH
1231 OPT_USE_SSH_AGENT, OPT_IDENTITY, OPT_KNOWNHOSTS, OPT_SSH_TIMEOUT,
1232 OPT_SSH_KEEPALIVE,
1233 #endif
1234 #ifdef WITH_GNUTLS
1235 OPT_CACERT, OPT_CLIENTCERT, OPT_CLIENTKEY, OPT_PRIORITY, OPT_VERIFY,
1236 #endif
1237 OPT_URL, OPT_LOCAL, OPT_FORCE_SAVE, OPT_TTYNAME, OPT_TTYTYPE,
1238 OPT_DISPLAY, OPT_LC_CTYPE, OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES,
1239 OPT_PINENTRY, OPT_KEYFILE, OPT_NEW_KEYFILE, OPT_NOLOCK,
1240 OPT_LOCK_TIMEOUT, OPT_SAVE, OPT_OUTPUT_FD, OPT_INQUIRE,
1241 OPT_INQUIRE_FD, OPT_INQUIRE_FILE, OPT_INQUIRE_LINE, OPT_NO_STATUS,
1242 OPT_NAME, OPT_VERSION, OPT_HELP, OPT_KEYGRIP, OPT_SIGN_KEYGRIP,
1243 OPT_NOPASSPHRASE, OPT_CIPHER, OPT_KEYPARAMS, OPT_NO_PINENTRY,
1244 OPT_S2K_COUNT, OPT_ITERATIONS, OPT_QUIET,
1245 #ifdef HAVE_LIBREADLINE
1246 OPT_INTERACTIVE,
1247 #endif
1249 const struct option long_opts[] = {
1250 #ifdef WITH_SSH
1251 { "no-ssh-agent", 0, 0, 0 },
1252 { "identity", 1, 0, 'i' },
1253 { "knownhosts", 1, 0, 'k' },
1254 { "ssh-timeout", 1, 0, 0 },
1255 { "ssh-keepalive", 1, 0, 0 },
1256 #endif
1257 #ifdef WITH_GNUTLS
1258 { "ca-cert", 1, 0, 0 },
1259 { "client-cert", 1, 0, 0 },
1260 { "client-key", 1, 0, 0 },
1261 { "tls-priority", 1, 0, 0 },
1262 { "tls-verify", 0, 0, 0 },
1263 #endif
1264 { "url", 1, 0, 0 },
1265 { "local-pinentry", 0, 0 },
1266 { "force-save", 0, 0 },
1267 { "ttyname", 1, 0, 'y' },
1268 { "ttytype", 1, 0, 't' },
1269 { "display", 1, 0, 'd' },
1270 { "lc-ctype", 1, 0, 0 },
1271 { "lc-messages", 1, 0, 0 },
1272 { "timeout", 1, 0, 0 },
1273 { "tries", 1, 0, 0 },
1274 { "pinentry", 1, 0, 0 },
1275 { "key-file", 1, 0, 0 },
1276 { "new-key-file", 1, 0, 0 },
1277 { "no-lock", 0, 0, 0 },
1278 { "lock-timeout", 1, 0, 0 },
1279 { "save", 0, 0, 'S' },
1280 { "output-fd", 1, 0, 0 },
1281 { "inquire", 1, 0, 0 },
1282 { "inquire-fd", 1, 0, 0 },
1283 { "inquire-file", 1, 0, 0 },
1284 { "inquire-line", 1, 0, 'L' },
1285 { "no-status", 0, 0, 0 },
1286 { "name", 1, 0, 'n' },
1287 { "version", 0, 0, 0 },
1288 { "help", 0, 0, 0 },
1289 { "keygrip", 1, 0, 0 },
1290 { "sign-keygrip", 1, 0, 0 },
1291 { "no-passphrase", 0, 0, 0 },
1292 { "cipher", 1, 0, 0 },
1293 { "key-params", 1, 0, 0 },
1294 { "no-pinentry", 0, 0, 0 },
1295 { "s2k-count", 1, 0, 0 },
1296 { "cipher-iterations", 1, 0, 0 },
1297 { "quiet", 0, 0, 0 },
1298 #ifdef HAVE_LIBREADLINE
1299 { "interactive", 0, 0 },
1300 #endif
1301 { 0, 0, 0, 0}
1303 #ifdef WITH_SSH
1304 const char *optstring = "L:y:t:d:P:I:Sn:i:k:";
1305 #else
1306 const char *optstring = "L:y:t:d:P:I:Sn:";
1307 #endif
1308 int opt_index = 0;
1310 #ifdef ENABLE_NLS
1311 setlocale(LC_ALL, "");
1312 bindtextdomain("libpwmd", LOCALEDIR);
1313 #endif
1315 #ifdef HAVE_LIBREADLINE
1316 if (!strcmp(basename(argv[0]), "pwmsh"))
1317 interactive = 1;
1318 #endif
1320 tries = DEFAULT_PIN_TRIES;
1321 inquirefd = STDIN_FILENO;
1323 while ((opt = getopt_long(argc, argv, optstring, long_opts, &opt_index)) != -1) {
1324 switch (opt) {
1325 /* Handle long options without a short option part. */
1326 case 0:
1327 switch (opt_index) {
1328 #ifdef WITH_SSH
1329 case OPT_USE_SSH_AGENT:
1330 use_ssh_agent = 0;
1331 break;
1332 case OPT_SSH_TIMEOUT:
1333 ssh_timeout = strtol(optarg, &p, 10);
1334 break;
1335 case OPT_SSH_KEEPALIVE:
1336 ssh_keepalive = strtol(optarg, &p, 10);
1337 break;
1338 #endif
1339 #ifdef WITH_GNUTLS
1340 case OPT_CACERT:
1341 cacert = optarg;
1342 break;
1343 case OPT_CLIENTCERT:
1344 clientcert = optarg;
1345 break;
1346 case OPT_CLIENTKEY:
1347 clientkey = optarg;
1348 break;
1349 case OPT_PRIORITY:
1350 prio = optarg;
1351 break;
1352 case OPT_VERIFY:
1353 tls_verify = 1;
1354 break;
1355 #endif
1356 case OPT_KEYPARAMS:
1357 keyparams = optarg;
1358 break;
1359 case OPT_KEYFILE:
1360 keyfile = pwmd_strdup(optarg);
1361 break;
1362 case OPT_NEW_KEYFILE:
1363 new_keyfile = pwmd_strdup(optarg);
1364 break;
1365 case OPT_NOLOCK:
1366 lock_on_open = 0;
1367 break;
1368 case OPT_LOCK_TIMEOUT:
1369 lock_timeout = strtol(optarg, &p, 10);
1370 break;
1371 case OPT_URL:
1372 url = optarg;
1373 break;
1374 case OPT_LOCAL:
1375 local_pin = 1;
1376 break;
1377 case OPT_FORCE_SAVE:
1378 save = force_save = 1;
1379 break;
1380 case OPT_LC_CTYPE:
1381 lcctype = pwmd_strdup(optarg);
1382 break;
1383 case OPT_LC_MESSAGES:
1384 lcmessages = pwmd_strdup(optarg);
1385 break;
1386 case OPT_TIMEOUT:
1387 timeout = strtol(optarg, &p, 10);
1388 break;
1389 case OPT_TRIES:
1390 tries = strtol(optarg, &p, 10);
1391 break;
1392 case OPT_INQUIRE:
1393 inquire = optarg;
1394 break;
1395 case OPT_INQUIRE_FD:
1396 inquirefd = strtol(optarg, &p, 10);
1397 if (!p) {
1398 inquirefp = fdopen(inquirefd, "r");
1399 if (!inquirefp) {
1400 pwmd_free(password);
1401 err(EXIT_FAILURE, "%i", inquirefd);
1404 break;
1405 case OPT_INQUIRE_FILE:
1406 inquirefd = open(optarg, O_RDONLY);
1407 if (!inquirefd == -1) {
1408 pwmd_free(password);
1409 err(EXIT_FAILURE, "%s", optarg);
1411 inquirefp = fdopen(inquirefd, "r");
1412 break;
1413 case OPT_OUTPUT_FD:
1414 outfd = strtol(optarg, &p, 10);
1415 if (!p) {
1416 outfp = fdopen(outfd, "w");
1417 if (!outfp) {
1418 pwmd_free(password);
1419 err(EXIT_FAILURE, "%i", outfd);
1422 break;
1423 case OPT_NO_STATUS:
1424 show_status = 0;
1425 break;
1426 case OPT_VERSION:
1427 pwmd_free(password);
1428 printf("%s (pwmc)\n\n"
1429 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012\n"
1430 "%s\n"
1431 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1432 "Compile-time features:\n"
1433 #ifdef WITH_SSH
1434 "+SSH "
1435 #else
1436 "-SSH "
1437 #endif
1438 #ifdef WITH_GNUTLS
1439 "+GNUTLS "
1440 #else
1441 "-GNUTLS "
1442 #endif
1443 #ifdef WITH_PINENTRY
1444 "+PINENTRY "
1445 #else
1446 "-PINENTRY "
1447 #endif
1448 #ifdef WITH_QUALITY
1449 "+CRACK "
1450 #else
1451 "-CRACK "
1452 #endif
1453 #ifdef MEM_DEBUG
1454 "+MEM_DEBUG "
1455 #else
1456 "-MEM_DEBUG "
1457 #endif
1458 #ifdef HAVE_LIBREADLINE
1459 "+INTERACTIVE "
1460 #else
1461 "-INTERACTIVE "
1462 #endif
1463 "\n"
1464 , PACKAGE_STRING, PACKAGE_BUGREPORT);
1465 exit(EXIT_SUCCESS);
1466 case OPT_PINENTRY:
1467 pinentry_path = optarg;
1468 break;
1469 case OPT_HELP:
1470 usage(argv[0], EXIT_SUCCESS);
1471 case OPT_KEYGRIP:
1472 keygrip = optarg;
1473 break;
1474 case OPT_SIGN_KEYGRIP:
1475 sign_keygrip = optarg;
1476 break;
1477 case OPT_S2K_COUNT:
1478 s2k_count = strtoul(optarg, &p, 10);
1479 break;
1480 case OPT_ITERATIONS:
1481 iterations = strtoull(optarg, &p, 10);
1482 iterations_arg = 1;
1483 break;
1484 case OPT_QUIET:
1485 quiet = 1;
1486 show_status = 0;
1487 break;
1488 case OPT_NOPASSPHRASE:
1489 no_passphrase = 1;
1490 break;
1491 case OPT_CIPHER:
1492 cipher = optarg;
1493 break;
1494 case OPT_NO_PINENTRY:
1495 no_pinentry = 1;
1496 break;
1497 #ifdef HAVE_LIBREADLINE
1498 case OPT_INTERACTIVE:
1499 interactive = 1;
1500 break;
1501 #endif
1502 default:
1503 usage(argv[0], EXIT_FAILURE);
1506 if (p && *p) {
1507 fprintf(stderr, N_("%s: invalid argument for option '--%s'\n"),
1508 argv[0], long_opts[opt_index].name);
1509 usage(argv[0], EXIT_FAILURE);
1512 break;
1513 #ifdef WITH_SSH
1514 case 'i':
1515 identity = optarg;
1516 break;
1517 case 'k':
1518 knownhosts = optarg;
1519 break;
1520 #endif
1521 case 'L':
1522 inquire_line = optarg;
1523 break;
1524 case 'y':
1525 tty = optarg;
1526 break;
1527 case 't':
1528 ttytype = optarg;
1529 break;
1530 case 'd':
1531 display = optarg;
1532 break;
1533 case 'S':
1534 save = 1;
1535 break;
1536 case 'n':
1537 clientname = optarg;
1538 break;
1539 default:
1540 pwmd_free(password);
1541 usage(argv[0], EXIT_FAILURE);
1545 #ifdef HAVE_LIBREADLINE
1546 if (interactive && !isatty(STDIN_FILENO)) {
1547 pwmd_free(password);
1548 usage(argv[0], EXIT_FAILURE);
1550 else if (isatty(STDIN_FILENO) && !inquire && !inquire_line)
1551 interactive = 1;
1552 #endif
1554 filename = argv[optind];
1555 #ifdef WITH_GNUTLS
1556 gnutls_global_set_mem_functions(pwmd_malloc, pwmd_malloc, NULL,
1557 pwmd_realloc, pwmd_free);
1558 #endif
1559 pwmd_init();
1560 rc = pwmd_new(clientname, &pwm);
1561 if (rc)
1562 goto done;
1564 pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
1565 if (!quiet)
1566 fprintf(stderr, N_("Connecting ...\n"));
1568 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1569 socktype = is_remote_url(url);
1570 if (socktype != PWMD_SOCKET_LOCAL) {
1571 local_pin = 1;
1572 if (socktype == PWMD_SOCKET_SSH) {
1573 #ifdef WITH_SSH
1574 rc = pwmd_setopt(pwm, PWMD_OPTION_KNOWNHOST_CB, knownhost_cb);
1575 if (rc)
1576 goto done;
1578 rc = pwmd_setopt(pwm, PWMD_OPTION_KNOWNHOST_DATA, clientname);
1579 if (rc)
1580 goto done;
1582 if (!getenv("SSH_AUTH_SOCK") || identity)
1583 use_ssh_agent = 0;
1585 rc = pwmd_setopt(pwm, PWMD_OPTION_SSH_AGENT, use_ssh_agent);
1586 if (rc)
1587 goto done;
1589 rc = pwmd_setopt(pwm, PWMD_OPTION_SSH_TIMEOUT, ssh_timeout);
1590 if (rc)
1591 goto done;
1593 rc = pwmd_setopt(pwm, PWMD_OPTION_SSH_KEEPALIVE, ssh_keepalive);
1594 if (rc)
1595 goto done;
1597 rc = pwmd_connect(pwm, url, identity, knownhosts);
1598 #endif
1600 #ifdef WITH_GNUTLS
1601 else {
1602 rc = pwmd_setopt(pwm, PWMD_OPTION_TLS_VERIFY, tls_verify);
1603 if (rc)
1604 goto done;
1606 rc = pwmd_connect(pwm, url, clientcert, clientkey, cacert, prio);
1608 #endif
1610 else
1611 rc = pwmd_connect(pwm, url);
1612 #else
1613 rc = pwmd_connect(pwm, url);
1614 #endif
1615 if (rc)
1616 goto done;
1618 if (!quiet)
1619 fprintf(stderr, N_("Connected.\n"));
1621 connected = 1;
1622 if (lock_timeout) {
1623 rc = pwmd_command(pwm, NULL, NULL, NULL, NULL,
1624 "OPTION LOCK-TIMEOUT=%li", lock_timeout);
1625 if (rc)
1626 goto done;
1629 if (lock_on_open) {
1630 rc = pwmd_setopt(pwm, PWMD_OPTION_LOCK_ON_OPEN, 1);
1631 if (rc)
1632 goto done;
1635 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_DESC, NULL);
1636 if (rc)
1637 goto done;
1639 if (timeout > 0) {
1640 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
1641 if (rc)
1642 goto done;
1645 rc = pwmd_setopt(pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1646 if (rc)
1647 goto done;
1649 rc = pwmd_setopt(pwm, PWMD_OPTION_LOCAL_PINENTRY,
1650 (local_pin || keyfile || new_keyfile));
1651 if (rc)
1652 goto done;
1654 if (pinentry_path) {
1655 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
1656 if (rc)
1657 goto done;
1660 if (display) {
1661 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
1662 if (rc)
1663 goto done;
1666 if (tty) {
1667 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TTY, tty);
1668 if (rc)
1669 goto done;
1672 if (ttytype) {
1673 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
1674 if (rc)
1675 goto done;
1678 if (lcctype) {
1679 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
1680 if (rc)
1681 goto done;
1684 if (lcmessages) {
1685 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES,
1686 lcmessages);
1687 if (rc)
1688 goto done;
1691 if (show_status) {
1692 rc = pwmd_setopt(pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
1693 if (rc)
1694 goto done;
1697 if (filename) {
1698 rc = open_command(filename);
1699 if (rc)
1700 goto done;
1703 #ifdef HAVE_LIBREADLINE
1704 if (interactive) {
1705 if (!force_save)
1706 save = 0;
1708 rc = do_interactive();
1709 goto do_exit;
1711 #endif
1713 if (inquire) {
1714 struct inquire_s *inq = NULL;
1716 rc = set_inquire(inquirefd, inquire_line, &inq);
1717 if (!rc)
1718 rc = pwmd_command(pwm, &result, &len, inquire_cb, inq, inquire);
1720 free_inquire(inq);
1721 goto done;
1724 fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
1725 ssize_t n;
1727 for (;;) {
1728 rc = process_cmd();
1730 if (rc)
1731 goto done;
1733 n = read(STDIN_FILENO, command, sizeof(command));
1734 if (n == -1) {
1735 if (errno == EAGAIN) {
1736 usleep(100000);
1737 continue;
1740 rc = gpg_error_from_errno(errno);
1741 goto done;
1743 else if (!n)
1744 goto done;
1746 p = command;
1747 command[n] = 0;
1748 break;
1751 if (!p || !*p || !strcasecmp(p, "BYE"))
1752 goto done;
1755 struct inquire_s *inq = NULL;
1756 rc = set_inquire(inquirefd, inquire_line, &inq);
1757 if (!rc) {
1758 rc = parse_dotcommand(command, &result, &len, inq);
1759 free_inquire(inq);
1762 if (rc)
1763 goto done;
1765 done:
1766 if (result) {
1767 fwrite(result, 1, result[len-1] == 0 ? len-1 : len, outfp);
1768 fflush(outfp);
1769 pwmd_free(result);
1772 pwmd_free(password);
1773 password = NULL;
1774 if (!rc)
1775 rc = finalize();
1777 #ifdef HAVE_LIBREADLINE
1778 do_exit:
1779 #endif
1780 memset(command, 0, sizeof(command));
1781 pwmd_close(pwm);
1782 pwmd_free(keyfile);
1783 pwmd_free(new_keyfile);
1784 pwmd_deinit();
1786 if (rc && !quiet)
1787 show_error(rc);
1789 if (connected && !quiet)
1790 fprintf(stderr, N_("Connection closed.\n"));
1792 exit(rc ? EXIT_FAILURE : EXIT_SUCCESS);