Update to use "OPTION disable-pinentry".
[libpwmd.git] / src / pwmc.c
blob24fa54877be1d7d45c4d437962e4affd3bf14a40
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012
3 Ben Kibbey <bjk@luxsci.net>
5 This file is part of libpwmd.
7 Libpwmd is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 2 of the License, or
10 (at your option) any later version.
12 Libpwmd is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Libpwmd. If not, see <http://www.gnu.org/licenses/>.
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <stdint.h>
28 #include <err.h>
29 #include <errno.h>
30 #include <string.h>
31 #include <libpwmd.h>
32 #include <assuan.h>
33 #include <sys/select.h>
34 #include <fcntl.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <libgen.h>
38 #include <termios.h>
39 #include <limits.h>
40 #include <ctype.h>
42 #ifdef HAVE_LOCALE_H
43 #include <locale.h>
44 #endif
46 #ifdef HAVE_GETOPT_LONG
47 #ifdef HAVE_GETOPT_H
48 #include <getopt.h>
49 #endif
50 #else
51 #include "getopt_long.h"
52 #endif
54 #ifdef HAVE_LIBREADLINE
55 # if defined(HAVE_READLINE_READLINE_H)
56 # include <readline/readline.h>
57 # elif defined(HAVE_READLINE_H)
58 # include <readline.h>
59 # endif /* !defined(HAVE_READLINE_H) */
60 static int interactive_error;
61 static int interactive;
62 #endif /* HAVE_LIBREADLINE */
64 #ifdef HAVE_READLINE_HISTORY
65 # if defined(HAVE_READLINE_HISTORY_H)
66 # include <readline/history.h>
67 # elif defined(HAVE_HISTORY_H)
68 # include <history.h>
69 # endif
70 #endif /* HAVE_READLINE_HISTORY */
72 #ifndef LINE_MAX
73 #define LINE_MAX 2048
74 #endif
76 #include "gettext.h"
77 #define N_(msgid) gettext(msgid)
79 #include "mem.h"
81 #define DEFAULT_PORT 22
82 #define DEFAULT_PIN_TRIES 3
83 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
84 ? gpg_error(rc) : rc
86 static int no_pinentry;
87 static pwm_t *pwm;
88 static char *filename;
89 static int save;
90 static int force_save;
91 static int no_passphrase;
92 static char *cipher;
93 static char *keygrip;
94 static char *sign_keygrip;
95 static char *keyparams;
96 static char *password;
97 static char *keyfile;
98 static char *new_keyfile;
99 static unsigned long s2k_count;
100 static uint64_t iterations;
101 static int iterations_arg;
102 static int tries;
103 static int local_pin;
104 static int inquirefd;
105 static int quiet;
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 rc, const char *str)
127 fprintf(stderr, "ERR %i: %s%s%s%s", rc, gpg_strerror(rc),
128 str ? ": " : "", str ? str : "", str ? "" : "\n");
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 " --tls-fingerprint <string>\n"
162 " a SHA-1 hash of the server fingerprint to verify against\n"
163 #endif
164 " --no-lock\n"
165 " do not lock the data file upon opening it\n"
166 " --lock-timeout <N>\n"
167 " time in tenths of a second to wait for a locked data file\n"
168 " --no-status\n"
169 " disable showing of status messages from the server\n"
170 " --quiet\n"
171 " disable showing of extra messages (implies --no-status)\n"
172 " --name, -n <string>\n"
173 " set the client name\n"
174 " --no-passphrase\n"
175 " do not require a passphrase when saving a new file\n"
176 " --keygrip <string>\n"
177 " the hex string of the keygrip to save to\n"
178 " --sign-keygrip <string>\n"
179 " the hex string of the keygrip to sign with\n"
180 " --key-file <filename>\n"
181 " obtain the passphrase from the specified filename\n"
182 " --new-key-file <filename>\n"
183 " obtain the passphrase to save with from the specified filename\n"
184 " --s2k-count <N>\n"
185 " the number of times to hash the passphrase for a new file\n"
186 " --cipher-iterations <N>\n"
187 " the number of times to encrypt the XML data (N+1)\n"
188 " --timeout <seconds>\n"
189 " pinentry timeout\n"
190 " --tries <N>\n"
191 " number of pinentry tries before failing (3)\n"
192 " --no-pinentry\n"
193 " disable pinentry both remotely and locally\n"
194 " --pinentry <path>\n"
195 " the full path to the pinentry binary (server default)\n"
196 " --ttyname, -y <path>\n"
197 " tty that pinentry will use\n"
198 " --ttytype, -t <string>\n"
199 " pinentry terminal type (default is $TERM)\n"
200 " --display, -d\n"
201 " pinentry display (default is $DISPLAY)\n"
202 " --lc-ctype <string>\n"
203 " locale setting for pinentry\n"
204 " --lc-messages <string>\n"
205 " locale setting for pinentry\n"
206 " --local-pinentry\n"
207 " force using a local pinentry\n"
208 #ifdef HAVE_LIBREADLINE
209 " --interactive\n"
210 " use a shell like interface to pwmd (allows more than one command)\n"
211 #endif
212 " --output-fd <FD>\n"
213 " redirect command output to the specified file descriptor\n"
214 " --inquire <COMMAND>\n"
215 " the specified command (with any options) uses a server inquire while\n"
216 " command data is read via the inquire file descriptor (stdin)\n"
217 " --inquire-fd <FD>\n"
218 " read inquire data from the specified file descriptor (stdin)\n"
219 " --inquire-file <filename>\n"
220 " read inquire data from the specified filename\n"
221 " --inquire-line, -L <STRING>\n"
222 " the initial line to send (i.e., element path) before the inquire data\n"
223 " --cipher <string>\n"
224 " the cipher to use when saving (see pwmd(1))\n"
225 " --save, -S\n"
226 " send the SAVE command before exiting\n"
227 " --key-params <string>\n"
228 " the key parameters to use when saving a new file (pwmd default)\n"
229 " --force-save\n"
230 " like --save but always ask for a passphrase\n"
231 " --version\n"
232 " --help\n"));
233 fprintf(status == EXIT_FAILURE ? stderr : stdout, N_(
234 "\n"
235 "An optional url may be in the form of:\n"
236 " --url /path/to/socket\n"
237 " --url file://[path/to/socket]\n"
238 #ifdef WITH_SSH
239 " or\n"
240 " --url ssh[46]://[username@]hostname[:port]\n"
241 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
242 #endif
243 #ifdef WITH_GNUTLS
244 " or\n"
245 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
246 " --client-key filename\n"
247 #endif
249 exit(status);
252 static gpg_error_t inquire_cb(void *user, const char *keyword, gpg_error_t rc,
253 char **data, size_t *size)
255 struct inquire_s *inq = user;
256 int is_password = 0;
257 int is_newpassword = 0;
259 *data = NULL;
260 *size = 0;
262 if (rc)
263 return rc;
265 if (!strcmp(keyword, "PASSPHRASE"))
266 is_password = 1;
267 else if (!strcmp(keyword, "NEW_PASSPHRASE"))
268 is_newpassword = 1;
269 #ifdef HAVE_LIBREADLINE
270 else if (!strcmp(keyword, "KEYPARAM") && !interactive) {
271 #else
272 else if (!strcmp(keyword, "KEYPARAM")) {
273 #endif
274 if (!keyparams || !*keyparams)
275 return gpg_error(GPG_ERR_INV_PARAMETER);
277 *data = keyparams;
278 *size = strlen(keyparams);
279 return gpg_error(GPG_ERR_EOF);
282 if ((is_newpassword && new_keyfile) || (is_password && keyfile)) {
283 int fd = open(is_password ? keyfile : new_keyfile, O_RDONLY);
285 if (fd == -1) {
286 fprintf(stderr, "%s: %s\n", is_newpassword ? new_keyfile : keyfile,
287 strerror(errno));
288 return gpg_error_from_syserror();
291 rc = set_inquire(fd, NULL, &inq);
292 if (rc) {
293 close(fd);
294 return rc;
297 if (!quiet)
298 fprintf(stderr, N_("Using keyfile '%s' as %s.\n"),
299 is_newpassword ? new_keyfile : keyfile, keyword);
301 if (!new_keyfile || is_newpassword) {
302 pwmd_socket_t t;
304 pwmd_socket_type(pwm, &t);
305 pwmd_setopt(pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
306 if (!no_pinentry && t == PWMD_SOCKET_LOCAL)
307 pwmd_setopt(pwm, PWMD_OPTION_NO_PINENTRY, 0);
310 else if (is_password && !keyfile) {
311 char *tmp;
313 rc = pwmd_password(pwm, keyword, &tmp, &inq->len);
314 if (rc && gpg_err_code(rc) != GPG_ERR_EOF)
315 return rc;
317 pwmd_free(inq->line);
318 inq->line = tmp;
319 *data = inq->line;
320 *size = inq->len;
321 return gpg_error(GPG_ERR_EOF);
323 #ifdef HAVE_LIBREADLINE
324 else if (!inq->header && interactive) {
325 fprintf(stderr, N_(
326 "Press CTRL-D to send the current line. Press twice to end. %s:\n"), keyword);
327 inq->header = 1;
329 #endif
331 /* The first part of the command data. */
332 if (inq->len) {
333 *data = inq->line;
334 *size = inq->len;
335 inq->len = 0;
336 return inq->fd == -1 ? gpg_error(GPG_ERR_EOF) : 0;
339 *size = read(inq->fd, inq->line, ASSUAN_LINELENGTH);
340 if (*size == -1) {
341 *size = 0;
342 return gpg_error(gpg_error_from_syserror());
344 else if (*size)
345 *data = inq->line;
347 if (((is_newpassword && new_keyfile) || (is_password && keyfile))
348 && *size == inq->size)
349 return gpg_error(GPG_ERR_EOF);
351 return *size ? 0 : gpg_error(GPG_ERR_EOF);
354 static int status_msg_cb(void *data, const char *line)
356 char *p = strchr(line, ' ');
358 if (!strcmp(line, "KEEPALIVE"))
359 return 0;
361 if (*line != '#' && p && strchr(p, ' ') && *++p) {
362 char *p1 = strchr(p, ' ');
363 int a = strtol(p, NULL, 10);
365 if (isdigit(*p) && p1) {
366 int b = strtol(p1, NULL, 10);
367 char l[64] = {0};
368 int t = a && b ? a*100/b : 0;
370 strncpy(l, line, strlen(line)-strlen(p)-1);
371 fprintf(stderr, "\r%s %i/%i %i%%%s", l, a, b, t, a == b ? "\n" : "");
372 fflush(stderr);
373 return 0;
377 fprintf(stderr, "%s\n", line);
378 fflush(stderr);
379 #ifdef HAVE_LIBREADLINE
380 rl_on_new_line();
381 #endif
382 return 0;
385 static gpg_error_t process_cmd()
387 return pwmd_process(pwm);
390 #ifdef WITH_SSH
391 static gpg_error_t get_password(char **result, pwmd_pinentry_t w, int echo)
393 char buf[LINE_MAX] = {0}, *p;
394 struct termios told, tnew;
395 char *key = NULL;
397 *result = NULL;
399 if (!isatty(STDIN_FILENO)) {
400 fprintf(stderr, N_("Input is not from a terminal! Failing.\n"));
401 return GPG_ERR_ENOTTY;
404 if (!echo) {
405 if (tcgetattr(STDIN_FILENO, &told) == -1)
406 return gpg_error_from_syserror();
408 memcpy(&tnew, &told, sizeof(struct termios));
409 tnew.c_lflag &= ~(ECHO);
410 tnew.c_lflag |= ICANON|ECHONL;
412 if (tcsetattr(STDIN_FILENO, TCSANOW, &tnew) == -1) {
413 int n = errno;
415 tcsetattr(STDIN_FILENO, TCSANOW, &told);
416 return gpg_error_from_errno(n);
420 switch (w) {
421 case PWMD_PINENTRY_OPEN:
422 fprintf(stderr, N_("Password for %s: "), filename);
423 break;
424 case PWMD_PINENTRY_OPEN_FAILED:
425 fprintf(stderr, N_("Invalid password. Password for %s: "), filename);
426 break;
427 case PWMD_PINENTRY_SAVE:
428 fprintf(stderr, N_("New password for %s: "), filename);
429 break;
430 case PWMD_PINENTRY_SAVE_CONFIRM:
431 fprintf(stderr, N_("Confirm password: "));
432 break;
433 default:
434 break;
437 if ((p = fgets(buf, sizeof(buf), stdin)) == NULL) {
438 tcsetattr(STDIN_FILENO, TCSANOW, &told);
439 return 0;
442 if (!echo)
443 tcsetattr(STDIN_FILENO, TCSANOW, &told);
445 if (feof(stdin)) {
446 clearerr(stdin);
447 return GPG_ERR_CANCELED;
450 p[strlen(p) - 1] = 0;
452 if (buf[0]) {
453 key = pwmd_strdup_printf("%s", p);
454 memset(&buf, 0, sizeof(buf));
456 if (!key)
457 return GPG_ERR_ENOMEM;
460 *result = key;
461 return 0;
464 static gpg_error_t knownhost_cb(void *data, const char *host, const char *key,
465 size_t len)
467 gpg_error_t rc;
468 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);
470 if (no_pinentry && !isatty(STDIN_FILENO)) {
471 fprintf(stderr, N_("Input is not from a terminal! Failing.\n"));
472 pwmd_free(buf);
473 return GPG_ERR_ENOTTY;
475 else if (no_pinentry) {
476 for (char *p = buf, len = 0; *p; p++, len++) {
477 if (*p == '\n')
478 len = 0;
480 if (len == 78) {
481 char *t = p;
483 while (!isspace(*(--p)));
484 *p = '\n';
485 p = t;
486 len = 0;
490 fprintf(stderr, "%s\n\n", buf);
491 pwmd_free(buf);
493 do {
494 char *result;
496 fprintf(stderr, N_("Trust this connection [y/N]: "));
497 fflush(stderr);
498 rc = get_password(&result, PWMD_PINENTRY_CONFIRM, 1);
500 if (rc)
501 return rc;
503 if (!result || !*result || *result == 'n' || *result == 'N') {
504 if (result && *result)
505 pwmd_free(result);
507 return GPG_ERR_NOT_CONFIRMED;
510 if ((*result == 'y' || *result == 'Y') && *(result+1) == 0) {
511 pwmd_free(result);
512 return 0;
514 } while (1);
517 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_DESC, buf);
518 pwmd_free(buf);
520 if (rc)
521 return rc;
523 return pwmd_getpin(pwm, NULL, NULL, NULL, PWMD_PINENTRY_CONFIRM);
525 #endif
527 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
528 static pwmd_socket_t is_remote_url(const char *str)
530 if (!str)
531 return PWMD_SOCKET_LOCAL;
533 #ifdef WITH_SSH
534 if (strstr(str, "ssh://") || strstr(str, "ssh4://")
535 || strstr(str, "ssh6://"))
536 return PWMD_SOCKET_SSH;
537 #endif
539 #ifdef WITH_GNUTLS
540 if (strstr(str, "tls://") || strstr(str, "tls4://")
541 || strstr(str, "tls6://"))
542 return PWMD_SOCKET_TLS;
543 #endif
545 return PWMD_SOCKET_LOCAL;
547 #endif
549 static char *escape(const char *str)
551 const char *p;
552 char *buf = pwmd_malloc(ASSUAN_LINELENGTH+1), *b = buf;
553 size_t len = 0;
555 for (p = str; *p; p++, len++) {
556 if (len == ASSUAN_LINELENGTH)
557 break;
559 if (*p == '\\') {
560 switch (*++p) {
561 case 't':
562 *b++ = '\t';
563 break;
564 case 'n':
565 *b++ = '\n';
566 break;
567 case 'v':
568 *b++ = '\v';
569 break;
570 case 'b':
571 *b++ = '\b';
572 break;
573 case 'f':
574 *b++ = '\f';
575 break;
576 case 'r':
577 *b++ = '\r';
578 break;
579 default:
580 *b++ = *p;
581 break;
584 if (!*p)
585 break;
587 continue;
590 *b++ = *p;
593 *b = 0;
594 return buf;
597 static void free_inquire(struct inquire_s *inq)
599 if (!inq)
600 return;
602 pwmd_free(inq->line);
604 if (inq->fd != -1 && inq->fd != STDIN_FILENO)
605 close(inq->fd);
607 pwmd_free(inq);
610 /* When *result is not NULL it is updated to the new values and not
611 * reallocated. */
612 static gpg_error_t set_inquire(int fd, const char *line,
613 struct inquire_s **result)
615 struct inquire_s inq = {0};
616 struct stat st = {0};
617 gpg_error_t rc;
619 if (fd != -1) {
620 if (fstat(fd, &st) == -1)
621 return gpg_error_from_syserror();
623 inq.size = st.st_size;
626 inq.fd = fd;
627 inq.line = pwmd_calloc(1, ASSUAN_LINELENGTH);
628 if (!inq.line)
629 return GPG_ERR_ENOMEM;
631 if (line) {
632 char *s = escape(line);
634 if (!s) {
635 pwmd_free(inq.line);
636 return GPG_ERR_ENOMEM;
639 if (strlen(s) >= ASSUAN_LINELENGTH) {
640 pwmd_free(inq.line);
641 pwmd_free(s);
642 return GPG_ERR_LINE_TOO_LONG;
645 strncpy(inq.line, s, ASSUAN_LINELENGTH-1);
646 inq.len = strlen(s);
647 pwmd_free(s);
650 rc = pwmd_setopt(pwm, PWMD_OPTION_INQUIRE_TOTAL,
651 st.st_size ? st.st_size+strlen(inq.line) : 0);
652 if (rc) {
653 pwmd_free(inq.line);
654 return rc;
657 if (*result == NULL)
658 *result = pwmd_malloc(sizeof(struct inquire_s));
659 else {
660 if ((*result)->fd != -1 && (*result)->fd != STDIN_FILENO)
661 close((*result)->fd);
663 pwmd_free((*result)->line);
664 (*result)->line = NULL;
665 (*result)->fd = -1;
666 (*result)->len = 0;
669 memcpy(*result, &inq, sizeof(struct inquire_s));
670 memset(&inq, 0, sizeof(struct inquire_s));
671 return rc;
674 #ifdef HAVE_LIBREADLINE
675 static int interactive_hook(void)
677 interactive_error = process_cmd();
679 if (interactive_error)
680 rl_event_hook = NULL;
682 return 0;
685 static void print_help()
687 fprintf(stderr, N_(
688 "------------------------------------------------------------------------------\n"
689 "Elements are TAB delimited. Press CTRL-V then TAB to insert from the prompt.\n"
690 "\n"
691 "Type HELP for protocol commands. Type .help for pwmc commands. Press CTRL-D\n"
692 "to quit.\n"
693 "------------------------------------------------------------------------------\n"
696 #endif
698 static char *parse_arg(const char *src, char *dst, size_t len)
700 char *p = dst;
701 const char *s = src;
702 size_t n = 0;
704 for (; s && *s && *s != ' ' && n < len; s++, n++)
705 *p++ = *s;
707 *p = 0;
708 return dst;
711 static char *parse_opt(char **line, const char *opt, gpg_error_t *rc)
713 static char result[ASSUAN_LINELENGTH] = {0}, *r = result;
714 size_t len = 0;
715 char *s = strstr(*line, opt);
717 *rc = 0;
718 result[0] = 0;
719 r = result;
721 if (s) {
722 int quote = 0;
723 size_t rlen = strlen(opt);
724 char *p = s+rlen;
725 int lastc = 0;
727 while (*p && *p == ' ') {
728 rlen++;
729 p++;
732 for (; *p && len < sizeof(result)-1; p++, rlen++) {
733 if (isspace(*p) && !quote)
734 break;
736 if (*p == '\"' && lastc != '\\') {
737 quote = !quote;
738 lastc = *p;
739 continue;
742 *r++ = lastc = *p;
743 len++;
746 *r = 0;
748 if (len >= sizeof(result)-1)
749 *rc = GPG_ERR_LINE_TOO_LONG;
750 else {
751 p = s+rlen;
753 while (*p && *p == ' ')
754 p++;
756 *line = p;
760 return result;
763 static gpg_error_t read_command(const char *line, char **result, size_t *len)
765 int fd;
766 gpg_error_t rc = 0;
767 char filebuf[ASSUAN_LINELENGTH];
768 char *filename = NULL;
769 struct inquire_s *inq = NULL;
770 char *p = (char *)line;
771 const char *prefix = parse_opt(&p, "--prefix", &rc);
773 if (rc)
774 return rc;
776 rc = GPG_ERR_SYNTAX;
778 if (p && *p) {
779 while (*p && isspace(*p))
780 p++;
782 filename = parse_arg(p, filebuf, sizeof(filebuf));
783 if (filename && *filename) {
784 p += strlen(filename)+1;
786 while (*p && isspace(*p))
787 p++;
789 if (*p)
790 rc = 0;
794 if (rc) {
795 fprintf(stderr, N_("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
796 fprintf(stderr, N_("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\" = \")\n"));
797 return rc;
800 fd = open(filename, O_RDONLY);
801 if (fd == -1)
802 return gpg_error_from_syserror();
804 rc = set_inquire(fd, prefix && *prefix ? prefix : NULL, &inq);
805 if (rc) {
806 close(fd);
807 return rc;
810 inq->header = 1;
811 rc = pwmd_command(pwm, result, len, inquire_cb, inq, p);
812 free_inquire(inq);
813 return rc;
816 static gpg_error_t redir_command(const char *line)
818 const char *p = line;
819 int fd;
820 gpg_error_t rc = GPG_ERR_SYNTAX;
821 char filebuf[ASSUAN_LINELENGTH];
822 char *filename = NULL;
823 struct inquire_s *inq = NULL;
824 char *result = NULL;
825 size_t len = 0;
827 if (p && *p && *++p) {
828 filename = parse_arg(p, filebuf, sizeof(filebuf));
829 if (filename && *filename) {
830 p += strlen(filename)+1;
832 while (*p && isspace(*p))
833 p++;
835 if (*p)
836 rc = 0;
840 if (rc) {
841 fprintf(stderr, N_("Usage: .redir <filename> <command> [args]\n"));
842 return rc;
845 fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0600);
846 if (fd == -1)
847 return gpg_error_from_syserror();
849 #ifdef HAVE_LIBREADLINE
850 rc = set_inquire(interactive ? STDIN_FILENO : inquirefd, NULL, &inq);
851 #else
852 rc = set_inquire(inquirefd, NULL, &inq);
853 #endif
854 if (rc) {
855 close(fd);
856 return rc;
859 rc = parse_dotcommand(p, &result, &len, inq);
860 if (!rc && result && len--) { // null byte which is always appended
861 if (write(fd, result, len) != len)
862 rc = GPG_ERR_TOO_SHORT;
863 pwmd_free(result);
866 free_inquire(inq);
867 close(fd);
868 return rc;
871 static gpg_error_t help_command(const char *line)
873 fprintf(stderr, N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
874 " .redir <filename> <command>\n"
875 " redirect the output of a command to the specified file\n"
876 "\n"
877 " .open <filename>\n"
878 " open the specified filename losing any changes to the current one\n"
879 "\n"
880 " .read [--prefix <string>] <filename> <command> [args]\n"
881 " obtain data from the specified filename for an inquire command\n"
882 "\n"
883 " .set help | <name> [<value>]\n"
884 " set option <name> to <value>\n"
885 "\n"
886 " .help\n"
887 " this help text\n"));
888 return 0;
891 static gpg_error_t open_command(const char *line)
893 struct inquire_s *inq = NULL;
894 const char *filename = line;
895 gpg_error_t rc;
897 while (filename && isspace(*filename))
898 filename++;
900 if (!filename || !*filename) {
901 fprintf(stderr, N_("Usage: .open <filename>\n"));
902 return GPG_ERR_SYNTAX;
905 #ifdef HAVE_LIBREADLINE
906 if (interactive || !quiet)
907 #else
908 if (!quiet)
909 #endif
910 fprintf(stderr, N_("Opening data file \"%s\" ...\n"), filename);
912 #ifdef HAVE_LIBREADLINE
913 rc = set_inquire(interactive ? STDIN_FILENO : -1, NULL, &inq);
914 #else
915 rc = set_inquire(-1, NULL, &inq);
916 #endif
917 if (rc)
918 return rc;
920 if (keyfile)
921 pwmd_setopt(pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
923 #ifdef HAVE_LIBREADLINE
924 // For safety. This file may be a different one. Make the user set it
925 // again if needed.
926 if (interactive) {
927 pwmd_free(new_keyfile);
928 new_keyfile = NULL;
930 #endif
932 rc = pwmd_open(pwm, filename, inquire_cb, inq);
933 free_inquire(inq);
934 return rc;
937 static gpg_error_t set_command(const char *line)
939 gpg_error_t rc = 0;
940 char name[256] = {0};
941 char value[512] = {0};
942 char *namep;
943 char *valuep;
944 const char *p = line;
946 while (p && *p && isspace(*p))
947 p++;
949 namep = parse_arg(p, name, sizeof(name));
950 if (!namep || !*namep) {
951 fprintf(stderr, N_("Usage: .set help | <name> [<value>]\n"));
952 return GPG_ERR_SYNTAX;
955 p += strlen(namep);
956 while (p && *p && isspace(*p))
957 p++;
959 valuep = parse_arg(p, value, sizeof(value));
961 if (!strcmp(name, "keyfile") || !strcmp(name, "new-keyfile")) {
962 int is_newkeyfile = 1;
963 int is_pkcs = 1;
964 char datafile[256];
966 if (!strcmp(name, "keyfile"))
967 is_newkeyfile = 0;
969 if (is_newkeyfile) {
970 pwmd_free(new_keyfile);
971 new_keyfile = NULL;
973 else {
974 pwmd_free(keyfile);
975 keyfile = NULL;
978 p += strlen (valuep);
979 while (p && *p && isspace(*p))
980 p++;
982 valuep = (char *)p;
983 if (*valuep)
985 memcpy (datafile, value, sizeof(datafile));
986 valuep = parse_arg (p, value, sizeof(value));
987 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "KEYGRIP %s", datafile);
988 if (gpg_err_code (rc) == GPG_ERR_NOT_SUPPORTED)
990 rc = 0;
991 is_pkcs = 0;
993 else if (!rc)
994 is_pkcs = 1;
997 if (!rc && *valuep) {
998 if (is_newkeyfile)
999 new_keyfile = pwmd_strdup(value);
1000 else
1001 keyfile = pwmd_strdup(value);
1003 if (!is_pkcs)
1004 rc = 0;
1005 else
1006 rc = pwmd_command(pwm, NULL, NULL, NULL, NULL,
1007 "AGENT option pinentry-mode=loopback");
1009 if (!rc) {
1010 rc = pwmd_setopt(pwm, PWMD_OPTION_NO_PINENTRY, 1);
1011 rc = pwmd_setopt(pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1014 else if (!local_pin && !no_pinentry) {
1015 pwmd_socket_t t;
1017 pwmd_socket_type(pwm, &t);
1018 if (t == PWMD_SOCKET_LOCAL) {
1019 rc = pwmd_setopt(pwm, PWMD_OPTION_NO_PINENTRY, 0);
1020 rc = pwmd_setopt(pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1024 else if (!strcmp(name, "help")) {
1025 fprintf(stderr, N_(
1026 "Set a libpwmd or pwmc option. The option name and optional value is space\n"
1027 "delimited. When no value is specified the option is unset.\n\n"
1028 "keyfile <datafile> [<filename>]\n"
1029 " set or unset the keyfile to be used when a passphrase is required\n"
1030 "\n"
1031 "new-keyfile <datafile> [<filename>]\n"
1032 " set or unset the keyfile to be used when a new passphrase is required\n"
1035 else
1036 rc = GPG_ERR_UNKNOWN_OPTION;
1038 return rc;
1041 static gpg_error_t parse_dotcommand(const char *line, char **result,
1042 size_t *len, struct inquire_s *inq)
1044 const char *p = line;
1045 gpg_error_t rc = 0;
1047 if (!strncmp(p, ".read", 5))
1048 rc = read_command(p+5, result, len);
1049 else if (!strncmp(p, ".redir", 6))
1050 rc = redir_command(p+6);
1051 else if (!strncmp(p, ".help", 5))
1052 rc = help_command(p+5);
1053 else if (!strncmp(p, ".open", 5))
1054 rc = open_command(p+5);
1055 else if (!strncmp(p, ".set", 4))
1056 rc = set_command(p+4);
1057 else
1058 rc = pwmd_command(pwm, result, len, inquire_cb, inq, line);
1060 return FINISH(rc);
1063 #ifdef HAVE_LIBREADLINE
1064 static gpg_error_t do_interactive()
1066 gpg_error_t rc;
1067 struct inquire_s *inq = NULL;
1069 rl_initialize();
1070 rc = process_cmd();
1071 if (rc)
1072 return rc;
1074 rc = set_inquire(STDIN_FILENO, NULL, &inq);
1075 if (rc)
1076 return rc;
1078 fprintf(stderr, N_("WARNING: interactive mode doesn't use secure memory!\n"));
1079 print_help();
1080 rl_event_hook = &interactive_hook;
1081 rl_set_keyboard_input_timeout(100000);
1083 for (;;) {
1084 char *line;
1085 char *result = NULL;
1086 size_t len;
1088 line = readline("pwm> ");
1089 if (interactive_error) {
1090 rc = interactive_error;
1091 break;
1094 if (!line) {
1095 rc = finalize();
1096 if (!rc)
1097 break;
1099 if (gpg_err_code(rc) != GPG_ERR_CANCELED &&
1100 gpg_err_code(rc) != GPG_ERR_EOF)
1101 fprintf(stderr, "ERR %i: %s\n", rc, gpg_strerror(rc));
1103 continue;
1105 else if (!*line) {
1106 free(line);
1107 continue;
1110 #ifdef HAVE_READLINE_HISTORY
1111 add_history(line);
1112 #endif
1113 inq->header = 0;
1114 rc = parse_dotcommand(line, &result, &len, inq);
1115 free(line);
1116 if (rc) {
1117 char *tmp = NULL;
1119 if (gpg_err_code(rc) == GPG_ERR_BAD_DATA)
1120 (void)pwmd_command(pwm, &tmp, NULL, NULL, NULL,
1121 "GETINFO last_error");
1123 show_error(rc, tmp);
1124 pwmd_free(tmp);
1126 else if (result && len)
1127 printf("%s%s", result, result[len-1] != '\n' ? "\n" : "");
1129 pwmd_free(result);
1132 free_inquire(inq);
1133 return 0;
1135 #endif
1137 static char *itoa(long long int n)
1139 static char buf[64];
1141 snprintf(buf, sizeof(buf), "%llu", n);
1142 return buf;
1145 static gpg_error_t finalize()
1147 gpg_error_t rc = 0;
1148 #ifdef HAVE_LIBREADLINE
1149 int quit = 0;
1151 if (!force_save && interactive) {
1152 char *p, buf[16];
1153 int finished = 0;
1155 fprintf(stderr, "\n");
1157 do {
1158 fprintf(stderr, N_("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1159 p = fgets(buf, sizeof(buf), stdin);
1161 if (feof(stdin)) {
1162 clearerr(stdin);
1163 return GPG_ERR_EOF;
1166 switch (*p) {
1167 case 'h':
1168 print_help();
1169 break;
1170 case 'c':
1171 return GPG_ERR_CANCELED;
1172 case 'Q':
1173 return 0;
1174 case 'f':
1175 rc = pwmd_command(pwm, NULL, NULL, NULL, NULL,
1176 "CLEARCACHE %s", filename);
1177 if (rc)
1178 return rc;
1180 interactive_hook();
1181 break;
1182 case 'S':
1183 quit = 1;
1184 case 's':
1185 save = 1;
1186 finished = 1;
1187 break;
1188 default:
1189 break;
1191 } while (!finished);
1193 #endif
1195 if (save && !filename) {
1196 fprintf(stderr, N_("No filename was specified on the command line. Aborting.\n"));
1197 return GPG_ERR_CANCELED;
1200 if (save && filename) {
1201 char *args = pwmd_strdup_printf("%s%s %s%s %s %s%s %s%s --s2k-count=%lu",
1202 keygrip ? "--keygrip=" : "", keygrip ? keygrip : "",
1203 sign_keygrip ? "--sign-keygrip=" : "", sign_keygrip ? sign_keygrip : "",
1204 no_passphrase ? "--no-passphrase" : "",
1205 cipher ? "--cipher=" : "", cipher ? cipher : "",
1206 iterations_arg ? "--cipher-iterations=" : "", iterations_arg ? itoa(iterations) : "",
1207 s2k_count);
1209 #ifdef HAVE_LIBREADLINE
1210 if (!quiet || interactive) {
1211 #else
1212 if (!quiet) {
1213 #endif
1214 fprintf(stderr, "\n");
1215 fprintf(stderr, N_("Saving changes ...\n"));
1218 rc = pwmd_save(pwm, args, inquire_cb, NULL);
1219 pwmd_free(args);
1221 if (!rc)
1222 no_passphrase = 0; // reset to avoid usage error on the next SAVE
1225 #ifdef HAVE_LIBREADLINE
1226 if (interactive)
1227 return rc ? rc : quit ? 0 : GPG_ERR_CANCELED;
1228 #endif
1230 return rc;
1233 int main(int argc, char *argv[])
1235 int connected = 0;
1236 gpg_error_t rc;
1237 int opt;
1238 char command[ASSUAN_LINELENGTH], *p = NULL;
1239 char *result = NULL;
1240 size_t len;
1241 char *pinentry_path = NULL;
1242 char *display = NULL, *tty = NULL, *ttytype = NULL, *lcctype = NULL,
1243 *lcmessages = NULL;
1244 int outfd = STDOUT_FILENO;
1245 FILE *outfp = stdout;
1246 FILE *inquirefp = stdin;
1247 int show_status = 1;
1248 char *clientname = "pwmc";
1249 char *inquire = NULL;
1250 char *inquire_line = NULL;
1251 int timeout = 0;
1252 #ifdef WITH_SSH
1253 int use_ssh_agent = 1;
1254 long ssh_timeout = 0;
1255 int ssh_keepalive = 0;
1256 char *knownhosts = NULL;
1257 char *identity = NULL;
1258 #endif
1259 #ifdef WITH_GNUTLS
1260 char *cacert = NULL;
1261 char *clientcert = NULL;
1262 char *clientkey = NULL;
1263 char *prio = NULL;
1264 int tls_verify = 0;
1265 char *tls_fingerprint = NULL;
1266 #endif
1267 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1268 pwmd_socket_t socktype;
1269 #endif
1270 int lock_on_open = 1;
1271 long lock_timeout = 0;
1272 char *url = NULL;
1273 /* The order is important. */
1274 enum {
1275 #ifdef WITH_SSH
1276 OPT_USE_SSH_AGENT, OPT_IDENTITY, OPT_KNOWNHOSTS, OPT_SSH_TIMEOUT,
1277 OPT_SSH_KEEPALIVE,
1278 #endif
1279 #ifdef WITH_GNUTLS
1280 OPT_CACERT, OPT_CLIENTCERT, OPT_CLIENTKEY, OPT_PRIORITY, OPT_VERIFY,
1281 OPT_SERVER_FP,
1282 #endif
1283 OPT_URL, OPT_LOCAL, OPT_FORCE_SAVE, OPT_TTYNAME, OPT_TTYTYPE,
1284 OPT_DISPLAY, OPT_LC_CTYPE, OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES,
1285 OPT_PINENTRY, OPT_KEYFILE, OPT_NEW_KEYFILE, OPT_NOLOCK,
1286 OPT_LOCK_TIMEOUT, OPT_SAVE, OPT_OUTPUT_FD, OPT_INQUIRE,
1287 OPT_INQUIRE_FD, OPT_INQUIRE_FILE, OPT_INQUIRE_LINE, OPT_NO_STATUS,
1288 OPT_NAME, OPT_VERSION, OPT_HELP, OPT_KEYGRIP, OPT_SIGN_KEYGRIP,
1289 OPT_NOPASSPHRASE, OPT_CIPHER, OPT_KEYPARAMS, OPT_NO_PINENTRY,
1290 OPT_S2K_COUNT, OPT_ITERATIONS, OPT_QUIET,
1291 #ifdef HAVE_LIBREADLINE
1292 OPT_INTERACTIVE,
1293 #endif
1295 const struct option long_opts[] = {
1296 #ifdef WITH_SSH
1297 { "no-ssh-agent", 0, 0, 0 },
1298 { "identity", 1, 0, 'i' },
1299 { "knownhosts", 1, 0, 'k' },
1300 { "ssh-timeout", 1, 0, 0 },
1301 { "ssh-keepalive", 1, 0, 0 },
1302 #endif
1303 #ifdef WITH_GNUTLS
1304 { "ca-cert", 1, 0, 0 },
1305 { "client-cert", 1, 0, 0 },
1306 { "client-key", 1, 0, 0 },
1307 { "tls-priority", 1, 0, 0 },
1308 { "tls-verify", 0, 0, 0 },
1309 { "tls-fingerprint", 1, 0, 0 },
1310 #endif
1311 { "url", 1, 0, 0 },
1312 { "local-pinentry", 0, 0 },
1313 { "force-save", 0, 0 },
1314 { "ttyname", 1, 0, 'y' },
1315 { "ttytype", 1, 0, 't' },
1316 { "display", 1, 0, 'd' },
1317 { "lc-ctype", 1, 0, 0 },
1318 { "lc-messages", 1, 0, 0 },
1319 { "timeout", 1, 0, 0 },
1320 { "tries", 1, 0, 0 },
1321 { "pinentry", 1, 0, 0 },
1322 { "key-file", 1, 0, 0 },
1323 { "new-key-file", 1, 0, 0 },
1324 { "no-lock", 0, 0, 0 },
1325 { "lock-timeout", 1, 0, 0 },
1326 { "save", 0, 0, 'S' },
1327 { "output-fd", 1, 0, 0 },
1328 { "inquire", 1, 0, 0 },
1329 { "inquire-fd", 1, 0, 0 },
1330 { "inquire-file", 1, 0, 0 },
1331 { "inquire-line", 1, 0, 'L' },
1332 { "no-status", 0, 0, 0 },
1333 { "name", 1, 0, 'n' },
1334 { "version", 0, 0, 0 },
1335 { "help", 0, 0, 0 },
1336 { "keygrip", 1, 0, 0 },
1337 { "sign-keygrip", 1, 0, 0 },
1338 { "no-passphrase", 0, 0, 0 },
1339 { "cipher", 1, 0, 0 },
1340 { "key-params", 1, 0, 0 },
1341 { "no-pinentry", 0, 0, 0 },
1342 { "s2k-count", 1, 0, 0 },
1343 { "cipher-iterations", 1, 0, 0 },
1344 { "quiet", 0, 0, 0 },
1345 #ifdef HAVE_LIBREADLINE
1346 { "interactive", 0, 0 },
1347 #endif
1348 { 0, 0, 0, 0}
1350 #ifdef WITH_SSH
1351 const char *optstring = "L:y:t:d:P:I:Sn:i:k:";
1352 #else
1353 const char *optstring = "L:y:t:d:P:I:Sn:";
1354 #endif
1355 int opt_index = 0;
1357 #ifdef ENABLE_NLS
1358 setlocale(LC_ALL, "");
1359 bindtextdomain("libpwmd", LOCALEDIR);
1360 #endif
1362 #ifdef HAVE_LIBREADLINE
1363 if (!strcmp(basename(argv[0]), "pwmsh"))
1364 interactive = 1;
1365 #endif
1367 tries = DEFAULT_PIN_TRIES;
1368 inquirefd = STDIN_FILENO;
1370 while ((opt = getopt_long(argc, argv, optstring, long_opts, &opt_index)) != -1) {
1371 switch (opt) {
1372 /* Handle long options without a short option part. */
1373 case 0:
1374 switch (opt_index) {
1375 #ifdef WITH_SSH
1376 case OPT_USE_SSH_AGENT:
1377 use_ssh_agent = 0;
1378 break;
1379 case OPT_SSH_TIMEOUT:
1380 ssh_timeout = strtol(optarg, &p, 10);
1381 break;
1382 case OPT_SSH_KEEPALIVE:
1383 ssh_keepalive = strtol(optarg, &p, 10);
1384 break;
1385 #endif
1386 #ifdef WITH_GNUTLS
1387 case OPT_CACERT:
1388 cacert = optarg;
1389 break;
1390 case OPT_CLIENTCERT:
1391 clientcert = optarg;
1392 break;
1393 case OPT_CLIENTKEY:
1394 clientkey = optarg;
1395 break;
1396 case OPT_PRIORITY:
1397 prio = optarg;
1398 break;
1399 case OPT_VERIFY:
1400 tls_verify = 1;
1401 break;
1402 case OPT_SERVER_FP:
1403 tls_fingerprint = optarg;
1404 break;
1405 #endif
1406 case OPT_KEYPARAMS:
1407 keyparams = optarg;
1408 break;
1409 case OPT_KEYFILE:
1410 keyfile = pwmd_strdup(optarg);
1411 break;
1412 case OPT_NEW_KEYFILE:
1413 new_keyfile = pwmd_strdup(optarg);
1414 break;
1415 case OPT_NOLOCK:
1416 lock_on_open = 0;
1417 break;
1418 case OPT_LOCK_TIMEOUT:
1419 lock_timeout = strtol(optarg, &p, 10);
1420 break;
1421 case OPT_URL:
1422 url = optarg;
1423 break;
1424 case OPT_LOCAL:
1425 local_pin = 1;
1426 break;
1427 case OPT_FORCE_SAVE:
1428 save = force_save = 1;
1429 break;
1430 case OPT_LC_CTYPE:
1431 lcctype = pwmd_strdup(optarg);
1432 break;
1433 case OPT_LC_MESSAGES:
1434 lcmessages = pwmd_strdup(optarg);
1435 break;
1436 case OPT_TIMEOUT:
1437 timeout = strtol(optarg, &p, 10);
1438 break;
1439 case OPT_TRIES:
1440 tries = strtol(optarg, &p, 10);
1441 break;
1442 case OPT_INQUIRE:
1443 inquire = optarg;
1444 break;
1445 case OPT_INQUIRE_FD:
1446 inquirefd = strtol(optarg, &p, 10);
1447 if (!p) {
1448 inquirefp = fdopen(inquirefd, "r");
1449 if (!inquirefp) {
1450 pwmd_free(password);
1451 err(EXIT_FAILURE, "%i", inquirefd);
1454 break;
1455 case OPT_INQUIRE_FILE:
1456 inquirefd = open(optarg, O_RDONLY);
1457 if (!inquirefd == -1) {
1458 pwmd_free(password);
1459 err(EXIT_FAILURE, "%s", optarg);
1461 inquirefp = fdopen(inquirefd, "r");
1462 break;
1463 case OPT_OUTPUT_FD:
1464 outfd = strtol(optarg, &p, 10);
1465 if (!p) {
1466 outfp = fdopen(outfd, "w");
1467 if (!outfp) {
1468 pwmd_free(password);
1469 err(EXIT_FAILURE, "%i", outfd);
1472 break;
1473 case OPT_NO_STATUS:
1474 show_status = 0;
1475 break;
1476 case OPT_VERSION:
1477 pwmd_free(password);
1478 printf("%s (pwmc)\n\n"
1479 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012\n"
1480 "%s\n"
1481 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1482 "Compile-time features:\n"
1483 #ifdef HAVE_LIBREADLINE
1484 "+INTERACTIVE "
1485 #else
1486 "-INTERACTIVE "
1487 #endif
1488 #ifdef WITH_SSH
1489 "+SSH "
1490 #else
1491 "-SSH "
1492 #endif
1493 #ifdef WITH_GNUTLS
1494 "+GNUTLS "
1495 #else
1496 "-GNUTLS "
1497 #endif
1498 #ifdef WITH_PINENTRY
1499 "+PINENTRY "
1500 #else
1501 "-PINENTRY "
1502 #endif
1503 #ifdef WITH_QUALITY
1504 "+CRACK "
1505 #else
1506 "-CRACK "
1507 #endif
1508 #ifdef MEM_DEBUG
1509 "+MEM_DEBUG "
1510 #else
1511 "-MEM_DEBUG "
1512 #endif
1513 "\n"
1514 , PACKAGE_STRING, PACKAGE_BUGREPORT);
1515 exit(EXIT_SUCCESS);
1516 case OPT_PINENTRY:
1517 pinentry_path = optarg;
1518 break;
1519 case OPT_HELP:
1520 usage(argv[0], EXIT_SUCCESS);
1521 case OPT_KEYGRIP:
1522 keygrip = optarg;
1523 break;
1524 case OPT_SIGN_KEYGRIP:
1525 sign_keygrip = optarg;
1526 break;
1527 case OPT_S2K_COUNT:
1528 s2k_count = strtoul(optarg, &p, 10);
1529 break;
1530 case OPT_ITERATIONS:
1531 iterations = strtoull(optarg, &p, 10);
1532 iterations_arg = 1;
1533 break;
1534 case OPT_QUIET:
1535 quiet = 1;
1536 show_status = 0;
1537 break;
1538 case OPT_NOPASSPHRASE:
1539 no_passphrase = 1;
1540 break;
1541 case OPT_CIPHER:
1542 cipher = optarg;
1543 break;
1544 case OPT_NO_PINENTRY:
1545 no_pinentry = 1;
1546 break;
1547 #ifdef HAVE_LIBREADLINE
1548 case OPT_INTERACTIVE:
1549 interactive = 1;
1550 break;
1551 #endif
1552 default:
1553 usage(argv[0], EXIT_FAILURE);
1556 if (p && *p) {
1557 fprintf(stderr, N_("%s: invalid argument for option '--%s'\n"),
1558 argv[0], long_opts[opt_index].name);
1559 usage(argv[0], EXIT_FAILURE);
1562 break;
1563 #ifdef WITH_SSH
1564 case 'i':
1565 identity = optarg;
1566 break;
1567 case 'k':
1568 knownhosts = optarg;
1569 break;
1570 #endif
1571 case 'L':
1572 inquire_line = optarg;
1573 break;
1574 case 'y':
1575 tty = optarg;
1576 break;
1577 case 't':
1578 ttytype = optarg;
1579 break;
1580 case 'd':
1581 display = optarg;
1582 break;
1583 case 'S':
1584 save = 1;
1585 break;
1586 case 'n':
1587 clientname = optarg;
1588 break;
1589 default:
1590 pwmd_free(password);
1591 usage(argv[0], EXIT_FAILURE);
1595 #ifdef HAVE_LIBREADLINE
1596 if (interactive && !isatty(STDIN_FILENO)) {
1597 pwmd_free(password);
1598 usage(argv[0], EXIT_FAILURE);
1600 else if (isatty(STDIN_FILENO) && !inquire && !inquire_line)
1601 interactive = 1;
1602 #endif
1604 filename = argv[optind];
1605 #ifdef WITH_GNUTLS
1606 gnutls_global_set_mem_functions(pwmd_malloc, pwmd_malloc, NULL,
1607 pwmd_realloc, pwmd_free);
1608 #endif
1609 pwmd_init();
1610 rc = pwmd_new(clientname, &pwm);
1611 if (rc)
1612 goto done;
1614 pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
1615 if (!quiet)
1616 fprintf(stderr, N_("Connecting ...\n"));
1618 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1619 socktype = is_remote_url(url);
1620 if (socktype != PWMD_SOCKET_LOCAL) {
1621 local_pin = 1;
1622 if (socktype == PWMD_SOCKET_SSH) {
1623 #ifdef WITH_SSH
1624 rc = pwmd_setopt(pwm, PWMD_OPTION_KNOWNHOST_CB, knownhost_cb);
1625 if (rc)
1626 goto done;
1628 rc = pwmd_setopt(pwm, PWMD_OPTION_KNOWNHOST_DATA, clientname);
1629 if (rc)
1630 goto done;
1632 if (!getenv("SSH_AUTH_SOCK") || identity)
1633 use_ssh_agent = 0;
1635 rc = pwmd_setopt(pwm, PWMD_OPTION_SSH_AGENT, use_ssh_agent);
1636 if (rc)
1637 goto done;
1639 rc = pwmd_setopt(pwm, PWMD_OPTION_SSH_TIMEOUT, ssh_timeout);
1640 if (rc)
1641 goto done;
1643 rc = pwmd_setopt(pwm, PWMD_OPTION_SSH_KEEPALIVE, ssh_keepalive);
1644 if (rc)
1645 goto done;
1647 rc = pwmd_connect(pwm, url, identity, knownhosts);
1648 #endif
1650 #ifdef WITH_GNUTLS
1651 else {
1652 rc = pwmd_setopt(pwm, PWMD_OPTION_TLS_VERIFY, tls_verify);
1653 if (rc)
1654 goto done;
1656 rc = pwmd_connect(pwm, url, clientcert, clientkey, cacert, prio,
1657 tls_fingerprint);
1659 #endif
1661 else
1662 rc = pwmd_connect(pwm, url);
1663 #else
1664 rc = pwmd_connect(pwm, url);
1665 #endif
1666 if (rc)
1667 goto done;
1669 if (!quiet)
1670 fprintf(stderr, N_("Connected.\n"));
1672 connected = 1;
1673 if (lock_timeout) {
1674 rc = pwmd_command(pwm, NULL, NULL, NULL, NULL,
1675 "OPTION LOCK-TIMEOUT=%li", lock_timeout);
1676 if (rc)
1677 goto done;
1680 if (lock_on_open) {
1681 rc = pwmd_setopt(pwm, PWMD_OPTION_LOCK_ON_OPEN, 1);
1682 if (rc)
1683 goto done;
1686 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_DESC, NULL);
1687 if (rc)
1688 goto done;
1690 if (timeout > 0) {
1691 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
1692 if (rc)
1693 goto done;
1696 rc = pwmd_setopt(pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1697 if (rc)
1698 goto done;
1700 rc = pwmd_setopt(pwm, PWMD_OPTION_LOCAL_PINENTRY,
1701 (local_pin || keyfile || new_keyfile));
1702 if (rc)
1703 goto done;
1705 if (pinentry_path) {
1706 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
1707 if (rc)
1708 goto done;
1711 if (display) {
1712 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
1713 if (rc)
1714 goto done;
1717 if (tty) {
1718 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TTY, tty);
1719 if (rc)
1720 goto done;
1723 if (ttytype) {
1724 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
1725 if (rc)
1726 goto done;
1729 if (lcctype) {
1730 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
1731 if (rc)
1732 goto done;
1735 if (lcmessages) {
1736 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES,
1737 lcmessages);
1738 if (rc)
1739 goto done;
1742 if (show_status) {
1743 rc = pwmd_setopt(pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
1744 if (rc)
1745 goto done;
1748 if (filename) {
1749 rc = open_command(filename);
1750 if (rc)
1751 goto done;
1754 #ifdef HAVE_LIBREADLINE
1755 if (interactive) {
1756 if (!force_save)
1757 save = 0;
1759 rc = do_interactive();
1760 result = NULL;
1761 goto do_exit;
1763 #endif
1765 if (inquire) {
1766 struct inquire_s *inq = NULL;
1768 rc = set_inquire(inquirefd, inquire_line, &inq);
1769 if (!rc)
1770 rc = pwmd_command(pwm, &result, &len, inquire_cb, inq, inquire);
1772 free_inquire(inq);
1773 goto done;
1776 fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
1777 ssize_t n;
1779 for (;;) {
1780 rc = process_cmd();
1782 if (rc)
1783 goto done;
1785 n = read(STDIN_FILENO, command, sizeof(command));
1786 if (n == -1) {
1787 if (errno == EAGAIN) {
1788 usleep(100000);
1789 continue;
1792 rc = gpg_error_from_errno(errno);
1793 goto done;
1795 else if (!n)
1796 goto done;
1798 p = command;
1799 command[n] = 0;
1800 break;
1803 if (!p || !*p || !strcasecmp(p, "BYE"))
1804 goto done;
1807 struct inquire_s *inq = NULL;
1808 rc = set_inquire(inquirefd, inquire_line, &inq);
1809 if (!rc) {
1810 rc = parse_dotcommand(command, &result, &len, inq);
1811 free_inquire(inq);
1814 if (rc)
1815 goto done;
1817 done:
1818 if (result) {
1819 fwrite(result, 1, result[len-1] == 0 ? len-1 : len, outfp);
1820 fflush(outfp);
1821 pwmd_free(result);
1824 pwmd_free(password);
1825 password = result = NULL;
1826 if (!rc)
1827 rc = finalize();
1828 else if (gpg_err_code(rc) == GPG_ERR_BAD_DATA)
1829 (void)pwmd_command(pwm, &result, NULL, NULL, NULL, "GETINFO last_error");
1831 #ifdef HAVE_LIBREADLINE
1832 do_exit:
1833 #endif
1834 memset(command, 0, sizeof(command));
1835 pwmd_close(pwm);
1836 pwmd_free(keyfile);
1837 pwmd_free(new_keyfile);
1838 pwmd_deinit();
1840 if (rc && !quiet)
1841 show_error(rc, result);
1843 pwmd_free(result);
1844 if (connected && !quiet)
1845 fprintf(stderr, N_("Connection closed.\n"));
1847 exit(rc ? EXIT_FAILURE : EXIT_SUCCESS);