Compile time fix for commit 9615853.
[libpwmd.git] / src / pwmc.c
blobc54ce2fa40b06e2937aeba09f500b0d72f2618f0
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 #ifdef HAVE_LIBREADLINE
904 if (interactive || !quiet)
905 #else
906 if (!quiet)
907 #endif
908 fprintf(stderr, N_("Opening data file \"%s\" ...\n"), filename);
910 #ifdef HAVE_LIBREADLINE
911 rc = set_inquire(interactive ? STDIN_FILENO : -1, NULL, &inq);
912 #else
913 rc = set_inquire(-1, NULL, &inq);
914 #endif
915 if (rc)
916 return rc;
918 if (keyfile)
919 pwmd_setopt(pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
921 #ifdef HAVE_LIBREADLINE
922 // For safety. This file may be a different one. Make the user set it
923 // again if needed.
924 if (interactive) {
925 pwmd_free(new_keyfile);
926 new_keyfile = NULL;
928 #endif
930 rc = pwmd_open(pwm, filename, inquire_cb, inq);
931 free_inquire(inq);
932 return rc;
935 static gpg_error_t set_command(const char *line)
937 gpg_error_t rc = 0;
938 char name[256] = {0};
939 char value[512] = {0};
940 char *namep;
941 char *valuep;
942 const char *p = line;
944 while (p && *p && isspace(*p))
945 p++;
947 namep = parse_arg(p, name, sizeof(name));
948 if (!namep || !*namep) {
949 fprintf(stderr, N_("Usage: .set help | <name> [<value>]\n"));
950 return GPG_ERR_SYNTAX;
953 p += strlen(namep);
954 while (p && *p && isspace(*p))
955 p++;
957 valuep = parse_arg(p, value, sizeof(value));
959 if (!strcmp(name, "keyfile") || !strcmp(name, "new-keyfile")) {
960 int is_newkeyfile = 1;
962 if (!strcmp(name, "keyfile"))
963 is_newkeyfile = 0;
965 if (is_newkeyfile) {
966 pwmd_free(new_keyfile);
967 new_keyfile = NULL;
969 else {
970 pwmd_free(keyfile);
971 keyfile = NULL;
974 if (*valuep) {
975 if (is_newkeyfile)
976 new_keyfile = pwmd_strdup(value);
977 else
978 keyfile = pwmd_strdup(value);
980 rc = pwmd_command(pwm, NULL, NULL, NULL, NULL, "AGENT option pinentry-mode=loopback");
981 if (!rc) {
982 rc = pwmd_setopt(pwm, PWMD_OPTION_NO_PINENTRY, 1);
983 rc = pwmd_setopt(pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
986 else if (!local_pin && !no_pinentry) {
987 pwmd_socket_t t;
989 pwmd_socket_type(pwm, &t);
990 if (t == PWMD_SOCKET_LOCAL) {
991 rc = pwmd_setopt(pwm, PWMD_OPTION_NO_PINENTRY, 0);
992 rc = pwmd_setopt(pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
996 else if (!strcmp(name, "help")) {
997 fprintf(stderr, N_(
998 "Set a libpwmd or pwmc option. The option name and optional value is space\n"
999 "delimited. When no value is specified the option is unset.\n\n"
1000 "keyfile [<filename>]\n"
1001 " set or unset the keyfile to be used when a passphrase is required\n"
1002 "\n"
1003 "new-keyfile [<filename>]\n"
1004 " set or unset the keyfile to be used when a new passphrase is required\n"
1007 else
1008 rc = GPG_ERR_UNKNOWN_OPTION;
1010 return rc;
1013 static gpg_error_t parse_dotcommand(const char *line, char **result,
1014 size_t *len, struct inquire_s *inq)
1016 const char *p = line;
1017 gpg_error_t rc = 0;
1019 if (!strncmp(p, ".read", 5))
1020 rc = read_command(p+5, result, len);
1021 else if (!strncmp(p, ".redir", 6))
1022 rc = redir_command(p+6);
1023 else if (!strncmp(p, ".help", 5))
1024 rc = help_command(p+5);
1025 else if (!strncmp(p, ".open", 5))
1026 rc = open_command(p+5);
1027 else if (!strncmp(p, ".set", 4))
1028 rc = set_command(p+4);
1029 else
1030 rc = pwmd_command(pwm, result, len, inquire_cb, inq, line);
1032 return FINISH(rc);
1035 #ifdef HAVE_LIBREADLINE
1036 static gpg_error_t do_interactive()
1038 gpg_error_t rc;
1039 struct inquire_s *inq = NULL;
1041 rl_initialize();
1042 rc = process_cmd();
1043 if (rc)
1044 return rc;
1046 rc = set_inquire(STDIN_FILENO, NULL, &inq);
1047 if (rc)
1048 return rc;
1050 fprintf(stderr, N_("WARNING: interactive mode doesn't use secure memory!\n"));
1051 print_help();
1052 rl_event_hook = &interactive_hook;
1053 rl_set_keyboard_input_timeout(100000);
1055 for (;;) {
1056 char *line;
1057 char *result = NULL;
1058 size_t len;
1060 line = readline("pwm> ");
1061 if (interactive_error) {
1062 rc = interactive_error;
1063 break;
1066 if (!line) {
1067 rc = finalize();
1068 if (!rc)
1069 break;
1071 if (gpg_err_code(rc) != GPG_ERR_CANCELED &&
1072 gpg_err_code(rc) != GPG_ERR_EOF)
1073 fprintf(stderr, "ERR %i: %s\n", rc, gpg_strerror(rc));
1075 continue;
1077 else if (!*line) {
1078 free(line);
1079 continue;
1082 #ifdef HAVE_READLINE_HISTORY
1083 add_history(line);
1084 #endif
1085 inq->header = 0;
1086 rc = parse_dotcommand(line, &result, &len, inq);
1087 free(line);
1088 if (rc)
1089 fprintf(stderr, "ERR %i: %s\n", rc, gpg_strerror(rc));
1090 else if (result && len)
1091 printf("%s%s", result, result[len-1] != '\n' ? "\n" : "");
1093 pwmd_free(result);
1096 free_inquire(inq);
1097 return 0;
1099 #endif
1101 static char *itoa(long long int n)
1103 static char buf[64];
1105 snprintf(buf, sizeof(buf), "%llu", n);
1106 return buf;
1109 static gpg_error_t finalize()
1111 gpg_error_t rc = 0;
1112 #ifdef HAVE_LIBREADLINE
1113 int quit = 0;
1115 if (!force_save && interactive) {
1116 char *p, buf[16];
1117 int finished = 0;
1119 fprintf(stderr, "\n");
1121 do {
1122 fprintf(stderr, N_("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1123 p = fgets(buf, sizeof(buf), stdin);
1125 if (feof(stdin)) {
1126 clearerr(stdin);
1127 return GPG_ERR_EOF;
1130 switch (*p) {
1131 case 'h':
1132 print_help();
1133 break;
1134 case 'c':
1135 return GPG_ERR_CANCELED;
1136 case 'Q':
1137 return 0;
1138 case 'f':
1139 rc = pwmd_command(pwm, NULL, NULL, NULL, NULL,
1140 "CLEARCACHE %s", filename);
1141 if (rc)
1142 return rc;
1144 interactive_hook();
1145 break;
1146 case 'S':
1147 quit = 1;
1148 case 's':
1149 save = 1;
1150 finished = 1;
1151 break;
1152 default:
1153 break;
1155 } while (!finished);
1157 #endif
1159 if (save && !filename) {
1160 fprintf(stderr, N_("No filename was specified on the command line. Aborting.\n"));
1161 return GPG_ERR_CANCELED;
1164 if (save && filename) {
1165 char *args = pwmd_strdup_printf("%s%s %s%s %s %s%s %s%s --s2k-count=%lu",
1166 keygrip ? "--keygrip=" : "", keygrip ? keygrip : "",
1167 sign_keygrip ? "--sign-keygrip=" : "", sign_keygrip ? sign_keygrip : "",
1168 no_passphrase ? "--no-passphrase" : "",
1169 cipher ? "--cipher=" : "", cipher ? cipher : "",
1170 iterations_arg ? "--cipher-iterations=" : "", iterations_arg ? itoa(iterations) : "",
1171 s2k_count);
1173 #ifdef HAVE_LIBREADLINE
1174 if (!quiet || interactive) {
1175 #else
1176 if (!quiet) {
1177 #endif
1178 fprintf(stderr, "\n");
1179 fprintf(stderr, N_("Saving changes ...\n"));
1182 rc = pwmd_save(pwm, args, inquire_cb, NULL);
1183 pwmd_free(args);
1185 if (!rc)
1186 no_passphrase = 0; // reset to avoid usage error on the next SAVE
1189 #ifdef HAVE_LIBREADLINE
1190 if (interactive)
1191 return rc ? rc : quit ? 0 : GPG_ERR_CANCELED;
1192 #endif
1194 return rc;
1197 int main(int argc, char *argv[])
1199 int connected = 0;
1200 gpg_error_t rc;
1201 int opt;
1202 char command[ASSUAN_LINELENGTH], *p = NULL;
1203 char *result = NULL;
1204 size_t len;
1205 char *pinentry_path = NULL;
1206 char *display = NULL, *tty = NULL, *ttytype = NULL, *lcctype = NULL,
1207 *lcmessages = NULL;
1208 int outfd = STDOUT_FILENO;
1209 FILE *outfp = stdout;
1210 FILE *inquirefp = stdin;
1211 int show_status = 1;
1212 char *clientname = "pwmc";
1213 char *inquire = NULL;
1214 char *inquire_line = NULL;
1215 int timeout = 0;
1216 #ifdef WITH_SSH
1217 int use_ssh_agent = 1;
1218 long ssh_timeout = 0;
1219 int ssh_keepalive = 0;
1220 char *knownhosts = NULL;
1221 char *identity = NULL;
1222 #endif
1223 #ifdef WITH_GNUTLS
1224 char *cacert = NULL;
1225 char *clientcert = NULL;
1226 char *clientkey = NULL;
1227 char *prio = NULL;
1228 int tls_verify = 0;
1229 #endif
1230 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1231 pwmd_socket_t socktype;
1232 #endif
1233 int lock_on_open = 1;
1234 long lock_timeout = 0;
1235 char *url = NULL;
1236 /* The order is important. */
1237 enum {
1238 #ifdef WITH_SSH
1239 OPT_USE_SSH_AGENT, OPT_IDENTITY, OPT_KNOWNHOSTS, OPT_SSH_TIMEOUT,
1240 OPT_SSH_KEEPALIVE,
1241 #endif
1242 #ifdef WITH_GNUTLS
1243 OPT_CACERT, OPT_CLIENTCERT, OPT_CLIENTKEY, OPT_PRIORITY, OPT_VERIFY,
1244 #endif
1245 OPT_URL, OPT_LOCAL, OPT_FORCE_SAVE, OPT_TTYNAME, OPT_TTYTYPE,
1246 OPT_DISPLAY, OPT_LC_CTYPE, OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES,
1247 OPT_PINENTRY, OPT_KEYFILE, OPT_NEW_KEYFILE, OPT_NOLOCK,
1248 OPT_LOCK_TIMEOUT, OPT_SAVE, OPT_OUTPUT_FD, OPT_INQUIRE,
1249 OPT_INQUIRE_FD, OPT_INQUIRE_FILE, OPT_INQUIRE_LINE, OPT_NO_STATUS,
1250 OPT_NAME, OPT_VERSION, OPT_HELP, OPT_KEYGRIP, OPT_SIGN_KEYGRIP,
1251 OPT_NOPASSPHRASE, OPT_CIPHER, OPT_KEYPARAMS, OPT_NO_PINENTRY,
1252 OPT_S2K_COUNT, OPT_ITERATIONS, OPT_QUIET,
1253 #ifdef HAVE_LIBREADLINE
1254 OPT_INTERACTIVE,
1255 #endif
1257 const struct option long_opts[] = {
1258 #ifdef WITH_SSH
1259 { "no-ssh-agent", 0, 0, 0 },
1260 { "identity", 1, 0, 'i' },
1261 { "knownhosts", 1, 0, 'k' },
1262 { "ssh-timeout", 1, 0, 0 },
1263 { "ssh-keepalive", 1, 0, 0 },
1264 #endif
1265 #ifdef WITH_GNUTLS
1266 { "ca-cert", 1, 0, 0 },
1267 { "client-cert", 1, 0, 0 },
1268 { "client-key", 1, 0, 0 },
1269 { "tls-priority", 1, 0, 0 },
1270 { "tls-verify", 0, 0, 0 },
1271 #endif
1272 { "url", 1, 0, 0 },
1273 { "local-pinentry", 0, 0 },
1274 { "force-save", 0, 0 },
1275 { "ttyname", 1, 0, 'y' },
1276 { "ttytype", 1, 0, 't' },
1277 { "display", 1, 0, 'd' },
1278 { "lc-ctype", 1, 0, 0 },
1279 { "lc-messages", 1, 0, 0 },
1280 { "timeout", 1, 0, 0 },
1281 { "tries", 1, 0, 0 },
1282 { "pinentry", 1, 0, 0 },
1283 { "key-file", 1, 0, 0 },
1284 { "new-key-file", 1, 0, 0 },
1285 { "no-lock", 0, 0, 0 },
1286 { "lock-timeout", 1, 0, 0 },
1287 { "save", 0, 0, 'S' },
1288 { "output-fd", 1, 0, 0 },
1289 { "inquire", 1, 0, 0 },
1290 { "inquire-fd", 1, 0, 0 },
1291 { "inquire-file", 1, 0, 0 },
1292 { "inquire-line", 1, 0, 'L' },
1293 { "no-status", 0, 0, 0 },
1294 { "name", 1, 0, 'n' },
1295 { "version", 0, 0, 0 },
1296 { "help", 0, 0, 0 },
1297 { "keygrip", 1, 0, 0 },
1298 { "sign-keygrip", 1, 0, 0 },
1299 { "no-passphrase", 0, 0, 0 },
1300 { "cipher", 1, 0, 0 },
1301 { "key-params", 1, 0, 0 },
1302 { "no-pinentry", 0, 0, 0 },
1303 { "s2k-count", 1, 0, 0 },
1304 { "cipher-iterations", 1, 0, 0 },
1305 { "quiet", 0, 0, 0 },
1306 #ifdef HAVE_LIBREADLINE
1307 { "interactive", 0, 0 },
1308 #endif
1309 { 0, 0, 0, 0}
1311 #ifdef WITH_SSH
1312 const char *optstring = "L:y:t:d:P:I:Sn:i:k:";
1313 #else
1314 const char *optstring = "L:y:t:d:P:I:Sn:";
1315 #endif
1316 int opt_index = 0;
1318 #ifdef ENABLE_NLS
1319 setlocale(LC_ALL, "");
1320 bindtextdomain("libpwmd", LOCALEDIR);
1321 #endif
1323 #ifdef HAVE_LIBREADLINE
1324 if (!strcmp(basename(argv[0]), "pwmsh"))
1325 interactive = 1;
1326 #endif
1328 tries = DEFAULT_PIN_TRIES;
1329 inquirefd = STDIN_FILENO;
1331 while ((opt = getopt_long(argc, argv, optstring, long_opts, &opt_index)) != -1) {
1332 switch (opt) {
1333 /* Handle long options without a short option part. */
1334 case 0:
1335 switch (opt_index) {
1336 #ifdef WITH_SSH
1337 case OPT_USE_SSH_AGENT:
1338 use_ssh_agent = 0;
1339 break;
1340 case OPT_SSH_TIMEOUT:
1341 ssh_timeout = strtol(optarg, &p, 10);
1342 break;
1343 case OPT_SSH_KEEPALIVE:
1344 ssh_keepalive = strtol(optarg, &p, 10);
1345 break;
1346 #endif
1347 #ifdef WITH_GNUTLS
1348 case OPT_CACERT:
1349 cacert = optarg;
1350 break;
1351 case OPT_CLIENTCERT:
1352 clientcert = optarg;
1353 break;
1354 case OPT_CLIENTKEY:
1355 clientkey = optarg;
1356 break;
1357 case OPT_PRIORITY:
1358 prio = optarg;
1359 break;
1360 case OPT_VERIFY:
1361 tls_verify = 1;
1362 break;
1363 #endif
1364 case OPT_KEYPARAMS:
1365 keyparams = optarg;
1366 break;
1367 case OPT_KEYFILE:
1368 keyfile = pwmd_strdup(optarg);
1369 break;
1370 case OPT_NEW_KEYFILE:
1371 new_keyfile = pwmd_strdup(optarg);
1372 break;
1373 case OPT_NOLOCK:
1374 lock_on_open = 0;
1375 break;
1376 case OPT_LOCK_TIMEOUT:
1377 lock_timeout = strtol(optarg, &p, 10);
1378 break;
1379 case OPT_URL:
1380 url = optarg;
1381 break;
1382 case OPT_LOCAL:
1383 local_pin = 1;
1384 break;
1385 case OPT_FORCE_SAVE:
1386 save = force_save = 1;
1387 break;
1388 case OPT_LC_CTYPE:
1389 lcctype = pwmd_strdup(optarg);
1390 break;
1391 case OPT_LC_MESSAGES:
1392 lcmessages = pwmd_strdup(optarg);
1393 break;
1394 case OPT_TIMEOUT:
1395 timeout = strtol(optarg, &p, 10);
1396 break;
1397 case OPT_TRIES:
1398 tries = strtol(optarg, &p, 10);
1399 break;
1400 case OPT_INQUIRE:
1401 inquire = optarg;
1402 break;
1403 case OPT_INQUIRE_FD:
1404 inquirefd = strtol(optarg, &p, 10);
1405 if (!p) {
1406 inquirefp = fdopen(inquirefd, "r");
1407 if (!inquirefp) {
1408 pwmd_free(password);
1409 err(EXIT_FAILURE, "%i", inquirefd);
1412 break;
1413 case OPT_INQUIRE_FILE:
1414 inquirefd = open(optarg, O_RDONLY);
1415 if (!inquirefd == -1) {
1416 pwmd_free(password);
1417 err(EXIT_FAILURE, "%s", optarg);
1419 inquirefp = fdopen(inquirefd, "r");
1420 break;
1421 case OPT_OUTPUT_FD:
1422 outfd = strtol(optarg, &p, 10);
1423 if (!p) {
1424 outfp = fdopen(outfd, "w");
1425 if (!outfp) {
1426 pwmd_free(password);
1427 err(EXIT_FAILURE, "%i", outfd);
1430 break;
1431 case OPT_NO_STATUS:
1432 show_status = 0;
1433 break;
1434 case OPT_VERSION:
1435 pwmd_free(password);
1436 printf("%s (pwmc)\n\n"
1437 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012\n"
1438 "%s\n"
1439 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1440 "Compile-time features:\n"
1441 #ifdef WITH_SSH
1442 "+SSH "
1443 #else
1444 "-SSH "
1445 #endif
1446 #ifdef WITH_GNUTLS
1447 "+GNUTLS "
1448 #else
1449 "-GNUTLS "
1450 #endif
1451 #ifdef WITH_PINENTRY
1452 "+PINENTRY "
1453 #else
1454 "-PINENTRY "
1455 #endif
1456 #ifdef WITH_QUALITY
1457 "+CRACK "
1458 #else
1459 "-CRACK "
1460 #endif
1461 #ifdef MEM_DEBUG
1462 "+MEM_DEBUG "
1463 #else
1464 "-MEM_DEBUG "
1465 #endif
1466 #ifdef HAVE_LIBREADLINE
1467 "+INTERACTIVE "
1468 #else
1469 "-INTERACTIVE "
1470 #endif
1471 "\n"
1472 , PACKAGE_STRING, PACKAGE_BUGREPORT);
1473 exit(EXIT_SUCCESS);
1474 case OPT_PINENTRY:
1475 pinentry_path = optarg;
1476 break;
1477 case OPT_HELP:
1478 usage(argv[0], EXIT_SUCCESS);
1479 case OPT_KEYGRIP:
1480 keygrip = optarg;
1481 break;
1482 case OPT_SIGN_KEYGRIP:
1483 sign_keygrip = optarg;
1484 break;
1485 case OPT_S2K_COUNT:
1486 s2k_count = strtoul(optarg, &p, 10);
1487 break;
1488 case OPT_ITERATIONS:
1489 iterations = strtoull(optarg, &p, 10);
1490 iterations_arg = 1;
1491 break;
1492 case OPT_QUIET:
1493 quiet = 1;
1494 show_status = 0;
1495 break;
1496 case OPT_NOPASSPHRASE:
1497 no_passphrase = 1;
1498 break;
1499 case OPT_CIPHER:
1500 cipher = optarg;
1501 break;
1502 case OPT_NO_PINENTRY:
1503 no_pinentry = 1;
1504 break;
1505 #ifdef HAVE_LIBREADLINE
1506 case OPT_INTERACTIVE:
1507 interactive = 1;
1508 break;
1509 #endif
1510 default:
1511 usage(argv[0], EXIT_FAILURE);
1514 if (p && *p) {
1515 fprintf(stderr, N_("%s: invalid argument for option '--%s'\n"),
1516 argv[0], long_opts[opt_index].name);
1517 usage(argv[0], EXIT_FAILURE);
1520 break;
1521 #ifdef WITH_SSH
1522 case 'i':
1523 identity = optarg;
1524 break;
1525 case 'k':
1526 knownhosts = optarg;
1527 break;
1528 #endif
1529 case 'L':
1530 inquire_line = optarg;
1531 break;
1532 case 'y':
1533 tty = optarg;
1534 break;
1535 case 't':
1536 ttytype = optarg;
1537 break;
1538 case 'd':
1539 display = optarg;
1540 break;
1541 case 'S':
1542 save = 1;
1543 break;
1544 case 'n':
1545 clientname = optarg;
1546 break;
1547 default:
1548 pwmd_free(password);
1549 usage(argv[0], EXIT_FAILURE);
1553 #ifdef HAVE_LIBREADLINE
1554 if (interactive && !isatty(STDIN_FILENO)) {
1555 pwmd_free(password);
1556 usage(argv[0], EXIT_FAILURE);
1558 else if (isatty(STDIN_FILENO) && !inquire && !inquire_line)
1559 interactive = 1;
1560 #endif
1562 filename = argv[optind];
1563 #ifdef WITH_GNUTLS
1564 gnutls_global_set_mem_functions(pwmd_malloc, pwmd_malloc, NULL,
1565 pwmd_realloc, pwmd_free);
1566 #endif
1567 pwmd_init();
1568 rc = pwmd_new(clientname, &pwm);
1569 if (rc)
1570 goto done;
1572 pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
1573 if (!quiet)
1574 fprintf(stderr, N_("Connecting ...\n"));
1576 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1577 socktype = is_remote_url(url);
1578 if (socktype != PWMD_SOCKET_LOCAL) {
1579 local_pin = 1;
1580 if (socktype == PWMD_SOCKET_SSH) {
1581 #ifdef WITH_SSH
1582 rc = pwmd_setopt(pwm, PWMD_OPTION_KNOWNHOST_CB, knownhost_cb);
1583 if (rc)
1584 goto done;
1586 rc = pwmd_setopt(pwm, PWMD_OPTION_KNOWNHOST_DATA, clientname);
1587 if (rc)
1588 goto done;
1590 if (!getenv("SSH_AUTH_SOCK") || identity)
1591 use_ssh_agent = 0;
1593 rc = pwmd_setopt(pwm, PWMD_OPTION_SSH_AGENT, use_ssh_agent);
1594 if (rc)
1595 goto done;
1597 rc = pwmd_setopt(pwm, PWMD_OPTION_SSH_TIMEOUT, ssh_timeout);
1598 if (rc)
1599 goto done;
1601 rc = pwmd_setopt(pwm, PWMD_OPTION_SSH_KEEPALIVE, ssh_keepalive);
1602 if (rc)
1603 goto done;
1605 rc = pwmd_connect(pwm, url, identity, knownhosts);
1606 #endif
1608 #ifdef WITH_GNUTLS
1609 else {
1610 rc = pwmd_setopt(pwm, PWMD_OPTION_TLS_VERIFY, tls_verify);
1611 if (rc)
1612 goto done;
1614 rc = pwmd_connect(pwm, url, clientcert, clientkey, cacert, prio);
1616 #endif
1618 else
1619 rc = pwmd_connect(pwm, url);
1620 #else
1621 rc = pwmd_connect(pwm, url);
1622 #endif
1623 if (rc)
1624 goto done;
1626 if (!quiet)
1627 fprintf(stderr, N_("Connected.\n"));
1629 connected = 1;
1630 if (lock_timeout) {
1631 rc = pwmd_command(pwm, NULL, NULL, NULL, NULL,
1632 "OPTION LOCK-TIMEOUT=%li", lock_timeout);
1633 if (rc)
1634 goto done;
1637 if (lock_on_open) {
1638 rc = pwmd_setopt(pwm, PWMD_OPTION_LOCK_ON_OPEN, 1);
1639 if (rc)
1640 goto done;
1643 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_DESC, NULL);
1644 if (rc)
1645 goto done;
1647 if (timeout > 0) {
1648 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
1649 if (rc)
1650 goto done;
1653 rc = pwmd_setopt(pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1654 if (rc)
1655 goto done;
1657 rc = pwmd_setopt(pwm, PWMD_OPTION_LOCAL_PINENTRY,
1658 (local_pin || keyfile || new_keyfile));
1659 if (rc)
1660 goto done;
1662 if (pinentry_path) {
1663 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
1664 if (rc)
1665 goto done;
1668 if (display) {
1669 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
1670 if (rc)
1671 goto done;
1674 if (tty) {
1675 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TTY, tty);
1676 if (rc)
1677 goto done;
1680 if (ttytype) {
1681 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
1682 if (rc)
1683 goto done;
1686 if (lcctype) {
1687 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
1688 if (rc)
1689 goto done;
1692 if (lcmessages) {
1693 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES,
1694 lcmessages);
1695 if (rc)
1696 goto done;
1699 if (show_status) {
1700 rc = pwmd_setopt(pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
1701 if (rc)
1702 goto done;
1705 if (filename) {
1706 rc = open_command(filename);
1707 if (rc)
1708 goto done;
1711 #ifdef HAVE_LIBREADLINE
1712 if (interactive) {
1713 if (!force_save)
1714 save = 0;
1716 rc = do_interactive();
1717 goto do_exit;
1719 #endif
1721 if (inquire) {
1722 struct inquire_s *inq = NULL;
1724 rc = set_inquire(inquirefd, inquire_line, &inq);
1725 if (!rc)
1726 rc = pwmd_command(pwm, &result, &len, inquire_cb, inq, inquire);
1728 free_inquire(inq);
1729 goto done;
1732 fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
1733 ssize_t n;
1735 for (;;) {
1736 rc = process_cmd();
1738 if (rc)
1739 goto done;
1741 n = read(STDIN_FILENO, command, sizeof(command));
1742 if (n == -1) {
1743 if (errno == EAGAIN) {
1744 usleep(100000);
1745 continue;
1748 rc = gpg_error_from_errno(errno);
1749 goto done;
1751 else if (!n)
1752 goto done;
1754 p = command;
1755 command[n] = 0;
1756 break;
1759 if (!p || !*p || !strcasecmp(p, "BYE"))
1760 goto done;
1763 struct inquire_s *inq = NULL;
1764 rc = set_inquire(inquirefd, inquire_line, &inq);
1765 if (!rc) {
1766 rc = parse_dotcommand(command, &result, &len, inq);
1767 free_inquire(inq);
1770 if (rc)
1771 goto done;
1773 done:
1774 if (result) {
1775 fwrite(result, 1, result[len-1] == 0 ? len-1 : len, outfp);
1776 fflush(outfp);
1777 pwmd_free(result);
1780 pwmd_free(password);
1781 password = NULL;
1782 if (!rc)
1783 rc = finalize();
1785 #ifdef HAVE_LIBREADLINE
1786 do_exit:
1787 #endif
1788 memset(command, 0, sizeof(command));
1789 pwmd_close(pwm);
1790 pwmd_free(keyfile);
1791 pwmd_free(new_keyfile);
1792 pwmd_deinit();
1794 if (rc && !quiet)
1795 show_error(rc);
1797 if (connected && !quiet)
1798 fprintf(stderr, N_("Connection closed.\n"));
1800 exit(rc ? EXIT_FAILURE : EXIT_SUCCESS);