pwmc: fix prompting with pinentry when no --new-key-file was specified.
[libpwmd.git] / src / pwmc.c
blobc511ae4af3956dcefbcf17f44fdd1d53decaabee
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
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_PIN_TRIES 3
82 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
83 ? gpg_error(rc) : rc
85 static int no_pinentry;
86 static pwm_t *pwm;
87 static char *filename;
88 static int save;
89 static int force_save;
90 static int no_passphrase;
91 static char *cipher;
92 static char *keygrip;
93 static char *sign_keygrip;
94 static char *keyparams;
95 static char *keyfile;
96 static char *new_keyfile;
97 static unsigned long s2k_count;
98 static uint64_t iterations;
99 static int iterations_arg;
100 static int tries;
101 static int local_pin;
102 static int inquirefd;
103 static int quiet;
104 static int no_gpg_agent;
106 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
126 show_error (gpg_error_t rc, const char *str)
128 fprintf (stderr, "ERR %i: %s%s%s%s", rc, gpg_strerror (rc),
129 str ? ": " : "", str ? str : "", str ? "" : "\n");
132 static void
133 usage (const char *pn, int status)
135 fprintf (status == EXIT_FAILURE ? stderr : stdout,
136 N_("Usage: pwmc [options] [file]\n"
137 " --url <string>\n"
138 " a url string to connect to (~/.pwmd/socket, see below)\n"
139 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
140 " --connect-timeout <seconds>\n"
141 " seconds before connecting to a remote host fails (0=disabled, 120)\n"
142 " --socket-timeout <seconds>\n"
143 " seconds before a remote command fails (0=disabled, 300)\n"
144 #endif
145 #ifdef WITH_GNUTLS
146 " --ca-cert <filename>\n"
147 " certificate authority (CA) used to sign the server cert\n"
148 " --client-cert <filename>\n"
149 " client certificate to use for authentication\n"
150 " --client-key <filename>\n"
151 " key file used to protect the client certificate\n"
152 " --tls-priority <string>\n"
153 " compression, cipher and hash algorithm string (SECURE256)\n"
154 " --tls-verify\n"
155 " verify the hostname against the server certificate\n"
156 " --tls-fingerprint <string>\n"
157 " a SHA-1 hash of the server fingerprint to verify against\n"
158 #endif
159 #ifdef WITH_SSH
160 " --no-ssh-agent\n"
161 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
162 " --identity, -i <filename>\n"
163 " the ssh identity file to use for authentication\n"
164 " --knownhosts, -k <filename>\n"
165 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
166 #endif
167 " --no-lock\n"
168 " do not lock the data file upon opening it\n"
169 " --lock-timeout <N>\n"
170 " time in tenths of a second to wait for a locked data file (50)\n"
171 " --name, -n <string>\n"
172 " set the client name\n"
173 " --pinentry <path>\n"
174 " the full path to the pinentry binary (server default)\n"
175 " --local-pinentry\n"
176 " force using a local pinentry\n"
177 " --no-pinentry\n"
178 " disable pinentry both remotely and locally\n"
179 " --ttyname, -y <path>\n"
180 " tty that pinentry will use\n"
181 " --ttytype, -t <string>\n"
182 " pinentry terminal type (default is $TERM)\n"
183 " --display, -d\n"
184 " pinentry display (default is $DISPLAY)\n"
185 " --lc-ctype <string>\n"
186 " locale setting for pinentry\n"
187 " --lc-messages <string>\n"
188 " locale setting for pinentry\n"
189 " --tries <N>\n"
190 " number of pinentry tries before failing (3)\n"
191 " --timeout <seconds>\n"
192 " pinentry timeout\n"
193 " --inquire <COMMAND>\n"
194 " the specified command (with any options) uses a server inquire while\n"
195 " command data is read via the inquire file descriptor (stdin)\n"
196 " --inquire-line, -L <STRING>\n"
197 " the initial line to send (i.e., element path) before the inquire data\n"
198 " --inquire-fd <FD>\n"
199 " read inquire data from the specified file descriptor (stdin)\n"
200 " --inquire-file <filename>\n"
201 " read inquire data from the specified filename\n"
202 " --output-fd <FD>\n"
203 " redirect command output to the specified file descriptor\n"
204 " --save, -S\n"
205 " send the SAVE command before exiting\n"
206 " --force-save\n"
207 " like --save but always ask for a passphrase\n"
208 " --no-passphrase\n"
209 " do not require a passphrase when saving a new file\n"
210 " --no-gpg-agent\n"
211 " disable use of gpg-agent when saving to a new file\n"
212 " --key-file <filename>\n"
213 " obtain the passphrase from the specified filename\n"
214 " --new-key-file <filename>\n"
215 " obtain the passphrase to save with from the specified filename\n"
216 " --cipher <string>\n"
217 " the cipher to use when saving (see pwmd(1))\n"
218 " --cipher-iterations <N>\n"
219 " the number of times to encrypt the XML data (N+1)\n"
220 " --key-params <string>\n"
221 " the key parameters to use when saving a new file (pwmd default)\n"
222 " --keygrip <string>\n"
223 " the hex string of the keygrip to save to\n"
224 " --sign-keygrip <string>\n"
225 " the hex string of the keygrip to sign with\n"
226 " --s2k-count <N>\n"
227 " the number of times to hash the passphrase for a new file\n"
228 " --no-status\n"
229 " disable showing of status messages from the server\n"
230 " --quiet\n"
231 " disable showing of extra messages (implies --no-status)\n"
232 #ifdef HAVE_LIBREADLINE
233 " --interactive\n"
234 " use a shell like interface to pwmd (allows more than one command)\n"
235 #endif
236 " --version\n"
237 " --help\n"));
238 fprintf (status == EXIT_FAILURE ? stderr : stdout,
239 N_("\n"
240 "An optional url may be in the form of:\n"
241 " --url /path/to/socket\n"
242 " --url file://[path/to/socket]\n"
243 #ifdef WITH_SSH
244 " or\n"
245 " --url ssh[46]://[username@]hostname[:port]\n"
246 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
247 #endif
248 #ifdef WITH_GNUTLS
249 " or\n"
250 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
251 " --client-key filename\n"
252 #endif
253 #ifdef HAVE_LIBREADLINE
254 "\n"
255 "Interactive mode is used when input is from a terminal.\n"
256 #endif
258 exit (status);
261 static gpg_error_t
262 inquire_cb (void *user, const char *keyword, gpg_error_t rc,
263 char **data, size_t * size)
265 struct inquire_s *inq = user;
266 int is_password = 0;
267 int is_newpassword = 0;
269 *data = NULL;
270 *size = 0;
272 if (rc)
273 return rc;
275 if (!strcmp (keyword, "PASSPHRASE"))
276 is_password = 1;
277 else if (!strcmp (keyword, "NEW_PASSPHRASE"))
278 is_newpassword = 1;
279 #ifdef HAVE_LIBREADLINE
280 else if (!strcmp (keyword, "KEYPARAM") && !interactive)
282 #else
283 else if (!strcmp (keyword, "KEYPARAM"))
285 #endif
286 if (!keyparams || !*keyparams)
287 return gpg_error (GPG_ERR_INV_PARAMETER);
289 *data = keyparams;
290 *size = strlen (keyparams);
291 return gpg_error (GPG_ERR_EOF);
294 if ((is_newpassword && new_keyfile) || (is_password && keyfile))
296 int fd = open (is_password ? keyfile : new_keyfile, O_RDONLY);
298 if (fd == -1)
300 fprintf (stderr, "%s: %s\n", is_newpassword ? new_keyfile : keyfile,
301 strerror (errno));
302 return gpg_error_from_syserror ();
305 rc = set_inquire (fd, NULL, &inq);
306 if (rc)
308 close (fd);
309 return rc;
312 if (!quiet)
313 fprintf (stderr, N_("Using keyfile '%s' as %s.\n"),
314 is_newpassword ? new_keyfile : keyfile, keyword);
316 if (!new_keyfile || is_newpassword)
318 pwmd_socket_t t;
320 pwmd_socket_type (pwm, &t);
321 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
322 if (!no_pinentry && t == PWMD_SOCKET_LOCAL)
323 pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 0);
326 else if ((is_password && !keyfile) || (is_newpassword && !new_keyfile))
328 char *tmp;
330 rc = pwmd_password (pwm, keyword, &tmp, &inq->len);
331 if (rc && gpg_err_code (rc) != GPG_ERR_EOF)
332 return rc;
334 pwmd_free (inq->line);
335 inq->line = tmp;
336 *data = inq->line;
337 *size = inq->len;
338 return gpg_error (GPG_ERR_EOF);
340 #ifdef HAVE_LIBREADLINE
341 else if (!inq->header && interactive)
343 fprintf (stderr,
345 ("Press CTRL-D to send the current line. Press twice to end. %s:\n"),
346 keyword);
347 inq->header = 1;
349 #endif
351 /* The first part of the command data. */
352 if (inq->len)
354 *data = inq->line;
355 *size = inq->len;
356 inq->len = 0;
357 return inq->fd == -1 ? gpg_error (GPG_ERR_EOF) : 0;
360 *size = read (inq->fd, inq->line, ASSUAN_LINELENGTH);
361 if (*size == -1)
363 *size = 0;
364 return gpg_error (gpg_error_from_syserror ());
366 else if (*size)
367 *data = inq->line;
368 else if (inq->fd != STDIN_FILENO && (is_newpassword || is_password))
370 *inq->line = 0;
371 inq->size = 1;
372 *data = inq->line;
373 *size = 1;
376 if (((is_newpassword && new_keyfile) || (is_password && keyfile))
377 && *size == inq->size)
378 return gpg_error (GPG_ERR_EOF);
380 return *size ? 0 : gpg_error (GPG_ERR_EOF);
383 static int
384 status_msg_cb (void *data, const char *line)
386 char *p = strchr (line, ' ');
388 if (!strcmp (line, "KEEPALIVE"))
389 return 0;
391 if (*line != '#' && p && strchr (p, ' ') && *++p)
393 char *p1 = strchr (p, ' ');
394 int a = strtol (p, NULL, 10);
396 if (isdigit (*p) && p1)
398 int b = strtol (p1, NULL, 10);
399 char l[64] = { 0 };
400 int t = a && b ? a * 100 / b : 0;
402 strncpy (l, line, strlen (line) - strlen (p) - 1);
403 fprintf (stderr, "\r%s %i/%i %i%%%s", l, a, b, t,
404 a == b ? "\n" : "");
405 fflush (stderr);
406 return 0;
410 fprintf (stderr, "%s\n", line);
411 fflush (stderr);
412 #ifdef HAVE_LIBREADLINE
413 rl_on_new_line ();
414 #endif
415 return 0;
418 static gpg_error_t
419 process_cmd ()
421 return pwmd_process (pwm);
424 #ifdef WITH_SSH
425 static gpg_error_t
426 get_password (char **result, pwmd_pinentry_t w, int echo)
428 char buf[LINE_MAX] = { 0 }, *p;
429 struct termios told, tnew;
430 char *key = NULL;
432 *result = NULL;
434 if (!isatty (STDIN_FILENO))
436 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
437 return GPG_ERR_ENOTTY;
440 if (!echo)
442 if (tcgetattr (STDIN_FILENO, &told) == -1)
443 return gpg_error_from_syserror ();
445 memcpy (&tnew, &told, sizeof (struct termios));
446 tnew.c_lflag &= ~(ECHO);
447 tnew.c_lflag |= ICANON | ECHONL;
449 if (tcsetattr (STDIN_FILENO, TCSANOW, &tnew) == -1)
451 int n = errno;
453 tcsetattr (STDIN_FILENO, TCSANOW, &told);
454 return gpg_error_from_errno (n);
458 switch (w)
460 case PWMD_PINENTRY_OPEN:
461 fprintf (stderr, N_("Password for %s: "), filename);
462 break;
463 case PWMD_PINENTRY_OPEN_FAILED:
464 fprintf (stderr, N_("Invalid password. Password for %s: "), filename);
465 break;
466 case PWMD_PINENTRY_SAVE:
467 fprintf (stderr, N_("New password for %s: "), filename);
468 break;
469 case PWMD_PINENTRY_SAVE_CONFIRM:
470 fprintf (stderr, N_("Confirm password: "));
471 break;
472 default:
473 break;
476 if ((p = fgets (buf, sizeof (buf), stdin)) == NULL)
478 tcsetattr (STDIN_FILENO, TCSANOW, &told);
479 return 0;
482 if (!echo)
483 tcsetattr (STDIN_FILENO, TCSANOW, &told);
485 if (feof (stdin))
487 clearerr (stdin);
488 return GPG_ERR_CANCELED;
491 p[strlen (p) - 1] = 0;
493 if (buf[0])
495 key = pwmd_strdup_printf ("%s", p);
496 memset (&buf, 0, sizeof (buf));
498 if (!key)
499 return GPG_ERR_ENOMEM;
502 *result = key;
503 return 0;
506 static gpg_error_t
507 knownhost_cb (void *data, const char *host, const char *key, size_t len)
509 gpg_error_t rc;
510 char *buf =
511 pwmd_strdup_printf (N_
512 ("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?"),
513 (char *) data, host, host);
515 if (no_pinentry && !isatty (STDIN_FILENO))
517 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
518 pwmd_free (buf);
519 return GPG_ERR_ENOTTY;
521 else if (no_pinentry)
523 for (char *p = buf, len = 0; *p; p++, len++)
525 if (*p == '\n')
526 len = 0;
528 if (len == 78)
530 char *t = p;
532 while (!isspace (*(--p)));
533 *p = '\n';
534 p = t;
535 len = 0;
539 fprintf (stderr, "%s\n\n", buf);
540 pwmd_free (buf);
544 char *result;
546 fprintf (stderr, N_("Trust this connection [y/N]: "));
547 fflush (stderr);
548 rc = get_password (&result, PWMD_PINENTRY_CONFIRM, 1);
550 if (rc)
551 return rc;
553 if (!result || !*result || *result == 'n' || *result == 'N')
555 if (result && *result)
556 pwmd_free (result);
558 return GPG_ERR_NOT_CONFIRMED;
561 if ((*result == 'y' || *result == 'Y') && *(result + 1) == 0)
563 pwmd_free (result);
564 return 0;
567 while (1);
570 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, buf);
571 pwmd_free (buf);
573 if (rc)
574 return rc;
576 return pwmd_getpin (pwm, NULL, NULL, NULL, PWMD_PINENTRY_CONFIRM);
578 #endif
580 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
581 static pwmd_socket_t
582 is_remote_url (const char *str)
584 if (!str)
585 return PWMD_SOCKET_LOCAL;
587 #ifdef WITH_SSH
588 if (strstr (str, "ssh://") || strstr (str, "ssh4://")
589 || strstr (str, "ssh6://"))
590 return PWMD_SOCKET_SSH;
591 #endif
593 #ifdef WITH_GNUTLS
594 if (strstr (str, "tls://") || strstr (str, "tls4://")
595 || strstr (str, "tls6://"))
596 return PWMD_SOCKET_TLS;
597 #endif
599 return PWMD_SOCKET_LOCAL;
601 #endif
603 static char *
604 escape (const char *str)
606 const char *p;
607 char *buf = pwmd_malloc (ASSUAN_LINELENGTH + 1), *b = buf;
608 size_t len = 0;
610 for (p = str; *p; p++, len++)
612 if (len == ASSUAN_LINELENGTH)
613 break;
615 if (*p == '\\')
617 switch (*++p)
619 case 't':
620 *b++ = '\t';
621 break;
622 case 'n':
623 *b++ = '\n';
624 break;
625 case 'v':
626 *b++ = '\v';
627 break;
628 case 'b':
629 *b++ = '\b';
630 break;
631 case 'f':
632 *b++ = '\f';
633 break;
634 case 'r':
635 *b++ = '\r';
636 break;
637 default:
638 *b++ = *p;
639 break;
642 if (!*p)
643 break;
645 continue;
648 *b++ = *p;
651 *b = 0;
652 return buf;
655 static void
656 free_inquire (struct inquire_s *inq)
658 if (!inq)
659 return;
661 pwmd_free (inq->line);
663 if (inq->fd != -1 && inq->fd != STDIN_FILENO)
664 close (inq->fd);
666 pwmd_free (inq);
669 /* When *result is not NULL it is updated to the new values and not
670 * reallocated. */
671 static gpg_error_t
672 set_inquire (int fd, const char *line, struct inquire_s **result)
674 struct inquire_s inq = { 0 };
675 struct stat st = { 0 };
676 gpg_error_t rc;
678 if (fd != -1)
680 if (fstat (fd, &st) == -1)
681 return gpg_error_from_syserror ();
683 inq.size = st.st_size;
686 inq.fd = fd;
687 inq.line = pwmd_calloc (1, ASSUAN_LINELENGTH);
688 if (!inq.line)
689 return GPG_ERR_ENOMEM;
691 if (line)
693 char *s = escape (line);
695 if (!s)
697 pwmd_free (inq.line);
698 return GPG_ERR_ENOMEM;
701 if (strlen (s) >= ASSUAN_LINELENGTH)
703 pwmd_free (inq.line);
704 pwmd_free (s);
705 return GPG_ERR_LINE_TOO_LONG;
708 strncpy (inq.line, s, ASSUAN_LINELENGTH - 1);
709 inq.len = strlen (s);
710 pwmd_free (s);
713 rc = pwmd_setopt (pwm, PWMD_OPTION_INQUIRE_TOTAL,
714 st.st_size ? st.st_size + strlen (inq.line) : 0);
715 if (rc)
717 pwmd_free (inq.line);
718 return rc;
721 if (*result == NULL)
722 *result = pwmd_malloc (sizeof (struct inquire_s));
723 else
725 if ((*result)->fd != -1 && (*result)->fd != STDIN_FILENO)
726 close ((*result)->fd);
728 pwmd_free ((*result)->line);
729 (*result)->line = NULL;
730 (*result)->fd = -1;
731 (*result)->len = 0;
734 memcpy (*result, &inq, sizeof (struct inquire_s));
735 memset (&inq, 0, sizeof (struct inquire_s));
736 return rc;
739 #ifdef HAVE_LIBREADLINE
740 static int
741 interactive_hook (void)
743 interactive_error = process_cmd ();
745 if (interactive_error)
746 rl_event_hook = NULL;
748 return 0;
751 static void
752 print_help ()
754 fprintf (stderr,
756 ("------------------------------------------------------------------------------\n"
757 "Elements are TAB delimited. Press CTRL-V then TAB to insert from the prompt.\n"
758 "\n"
759 "Type HELP for protocol commands. Type .help for pwmc commands. Press CTRL-D\n"
760 "to quit.\n"
761 "------------------------------------------------------------------------------\n"));
763 #endif
765 static char *
766 parse_arg (const char *src, char *dst, size_t len)
768 char *p = dst;
769 const char *s = src;
770 size_t n = 0;
772 for (; s && *s && *s != ' ' && n < len; s++, n++)
773 *p++ = *s;
775 *p = 0;
776 return dst;
779 static char *
780 parse_opt (char **line, const char *opt, gpg_error_t * rc)
782 static char result[ASSUAN_LINELENGTH] = { 0 }, *r = result;
783 size_t len = 0;
784 char *s = strstr (*line, opt);
786 *rc = 0;
787 result[0] = 0;
788 r = result;
790 if (s)
792 int quote = 0;
793 size_t rlen = strlen (opt);
794 char *p = s + rlen;
795 int lastc = 0;
797 while (*p && *p == ' ')
799 rlen++;
800 p++;
803 for (; *p && len < sizeof (result) - 1; p++, rlen++)
805 if (isspace (*p) && !quote)
806 break;
808 if (*p == '\"' && lastc != '\\')
810 quote = !quote;
811 lastc = *p;
812 continue;
815 *r++ = lastc = *p;
816 len++;
819 *r = 0;
821 if (len >= sizeof (result) - 1)
822 *rc = GPG_ERR_LINE_TOO_LONG;
823 else
825 p = s + rlen;
827 while (*p && *p == ' ')
828 p++;
830 *line = p;
834 return result;
837 static gpg_error_t
838 read_command (const char *line, char **result, size_t * len)
840 int fd;
841 gpg_error_t rc = 0;
842 char filebuf[ASSUAN_LINELENGTH];
843 char *filename = NULL;
844 struct inquire_s *inq = NULL;
845 char *p = (char *) line;
846 const char *prefix = parse_opt (&p, "--prefix", &rc);
848 if (rc)
849 return rc;
851 rc = GPG_ERR_SYNTAX;
853 if (p && *p)
855 while (*p && isspace (*p))
856 p++;
858 filename = parse_arg (p, filebuf, sizeof (filebuf));
859 if (filename && *filename)
861 p += strlen (filename) + 1;
863 while (*p && isspace (*p))
864 p++;
866 if (*p)
867 rc = 0;
871 if (rc)
873 fprintf (stderr,
875 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
876 fprintf (stderr,
878 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\" = \")\n"));
879 return rc;
882 fd = open (filename, O_RDONLY);
883 if (fd == -1)
884 return gpg_error_from_syserror ();
886 rc = set_inquire (fd, prefix && *prefix ? prefix : NULL, &inq);
887 if (rc)
889 close (fd);
890 return rc;
893 inq->header = 1;
894 rc = pwmd_command (pwm, result, len, inquire_cb, inq, p);
895 free_inquire (inq);
896 return rc;
899 static gpg_error_t
900 redir_command (const char *line)
902 const char *p = line;
903 int fd;
904 gpg_error_t rc = GPG_ERR_SYNTAX;
905 char filebuf[ASSUAN_LINELENGTH];
906 char *filename = NULL;
907 struct inquire_s *inq = NULL;
908 char *result = NULL;
909 size_t len = 0;
911 if (p && *p && *++p)
913 filename = parse_arg (p, filebuf, sizeof (filebuf));
914 if (filename && *filename)
916 p += strlen (filename) + 1;
918 while (*p && isspace (*p))
919 p++;
921 if (*p)
922 rc = 0;
926 if (rc)
928 fprintf (stderr, N_("Usage: .redir <filename> <command> [args]\n"));
929 return rc;
932 fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
933 if (fd == -1)
934 return gpg_error_from_syserror ();
936 #ifdef HAVE_LIBREADLINE
937 rc = set_inquire (interactive ? STDIN_FILENO : inquirefd, NULL, &inq);
938 #else
939 rc = set_inquire (inquirefd, NULL, &inq);
940 #endif
941 if (rc)
943 close (fd);
944 return rc;
947 rc = parse_dotcommand (p, &result, &len, inq);
948 if (!rc && result && len--)
949 { // null byte which is always appended
950 if (write (fd, result, len) != len)
951 rc = GPG_ERR_TOO_SHORT;
952 pwmd_free (result);
955 free_inquire (inq);
956 close (fd);
957 return rc;
960 static gpg_error_t
961 help_command (const char *line)
963 fprintf (stderr,
964 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
965 " .redir <filename> <command>\n"
966 " redirect the output of a command to the specified file\n"
967 "\n"
968 " .open <filename>\n"
969 " open the specified filename losing any changes to the current one\n"
970 "\n"
971 " .read [--prefix <string>] <filename> <command> [args]\n"
972 " obtain data from the specified filename for an inquire command\n"
973 "\n"
974 " .set help | <name> [<value>]\n"
975 " set option <name> to <value>\n"
976 "\n"
977 " .save [args]\n"
978 " write changes of the file to disk\n"
979 "\n"
980 " .help\n"
981 " this help text\n"));
982 return 0;
985 static gpg_error_t
986 open_command (const char *line)
988 struct inquire_s *inq = NULL;
989 const char *filename = line;
990 gpg_error_t rc;
992 while (filename && isspace (*filename))
993 filename++;
995 if (!filename || !*filename)
997 fprintf (stderr, N_("Usage: .open <filename>\n"));
998 return GPG_ERR_SYNTAX;
1001 #ifdef HAVE_LIBREADLINE
1002 if (interactive || !quiet)
1003 #else
1004 if (!quiet)
1005 #endif
1006 fprintf (stderr, N_("Opening data file \"%s\" ...\n"), filename);
1008 #ifdef HAVE_LIBREADLINE
1009 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1010 #else
1011 rc = set_inquire (-1, NULL, &inq);
1012 #endif
1013 if (rc)
1014 return rc;
1016 if (keyfile)
1017 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1019 rc = pwmd_open (pwm, filename, inquire_cb, inq);
1020 free_inquire (inq);
1021 return rc;
1024 static gpg_error_t
1025 set_command (const char *line)
1027 gpg_error_t rc = 0;
1028 char name[256] = { 0 };
1029 char value[512] = { 0 };
1030 char *namep;
1031 char *valuep;
1032 const char *p = line;
1034 while (p && *p && isspace (*p))
1035 p++;
1037 namep = parse_arg (p, name, sizeof (name));
1038 if (!namep || !*namep)
1040 fprintf (stderr, N_("Usage: .set help | <name> [<value>]\n"));
1041 return GPG_ERR_SYNTAX;
1044 p += strlen (namep);
1045 while (p && *p && isspace (*p))
1046 p++;
1048 valuep = parse_arg (p, value, sizeof (value));
1050 if (!strcmp (name, "keyfile") || !strcmp (name, "new-keyfile"))
1052 int is_newkeyfile = 1;
1053 int is_pkcs = 1;
1054 char datafile[256];
1056 if (!strcmp (name, "keyfile"))
1057 is_newkeyfile = 0;
1059 if (is_newkeyfile)
1061 pwmd_free (new_keyfile);
1062 new_keyfile = NULL;
1064 else
1066 pwmd_free (keyfile);
1067 keyfile = NULL;
1070 p += strlen (valuep);
1071 while (p && *p && isspace (*p))
1072 p++;
1074 valuep = (char *) p;
1075 if (*valuep)
1077 memcpy (datafile, value, sizeof (datafile));
1078 valuep = parse_arg (p, value, sizeof (value));
1079 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "KEYGRIP %s",
1080 datafile);
1081 if (gpg_err_code (rc) == GPG_ERR_NOT_SUPPORTED
1082 || (gpg_err_source (rc) == GPG_ERR_SOURCE_USER_1
1083 && gpg_err_code (rc) == GPG_ERR_ENOENT))
1085 rc = 0;
1086 is_pkcs = 0;
1088 else if (!rc)
1089 is_pkcs = 1;
1092 if (!rc && *valuep)
1094 if (is_newkeyfile)
1095 new_keyfile = pwmd_strdup (value);
1096 else
1097 keyfile = pwmd_strdup (value);
1099 if (!is_pkcs)
1100 rc = 0;
1101 else
1102 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1103 "AGENT option pinentry-mode=loopback");
1105 if (!rc)
1107 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 1);
1108 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1111 else if (!local_pin && !no_pinentry)
1113 pwmd_socket_t t;
1115 pwmd_socket_type (pwm, &t);
1116 if (t == PWMD_SOCKET_LOCAL)
1118 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 0);
1119 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1123 else if (!strcmp (name, "help"))
1125 fprintf (stderr,
1127 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1128 "delimited. When no value is specified the option is unset.\n\n"
1129 "keyfile <datafile> [<filename>]\n"
1130 " set or unset the keyfile to be used when a passphrase is required (*)\n"
1131 "\n"
1132 "new-keyfile <datafile> [<filename>]\n"
1133 " set or unset the keyfile to be used when a new passphrase is required (*)\n"
1134 "\n"
1135 "* = the next protocol command will unset this value\n"
1138 else
1139 rc = GPG_ERR_UNKNOWN_OPTION;
1141 return rc;
1144 static gpg_error_t
1145 save_command (const char *line)
1147 struct inquire_s *inq = NULL;
1148 gpg_error_t rc;
1150 #ifdef HAVE_LIBREADLINE
1151 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1152 #else
1153 rc = set_inquire (-1, NULL, &inq);
1154 #endif
1155 if (rc)
1156 return rc;
1158 if (new_keyfile || keyfile)
1159 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1161 rc = pwmd_save (pwm, line, inquire_cb, inq);
1162 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1163 free_inquire (inq);
1164 return rc;
1167 static gpg_error_t
1168 parse_dotcommand (const char *line, char **result,
1169 size_t * len, struct inquire_s *inq)
1171 const char *p = line;
1172 gpg_error_t rc = 0;
1174 if (!strncmp (p, ".read", 5))
1175 rc = read_command (p + 5, result, len);
1176 else if (!strncmp (p, ".redir", 6))
1177 rc = redir_command (p + 6);
1178 else if (!strncmp (p, ".help", 5))
1179 rc = help_command (p + 5);
1180 else if (!strncmp (p, ".open", 5))
1181 rc = open_command (p + 5);
1182 else if (!strncmp (p, ".set", 4))
1183 rc = set_command (p + 4);
1184 else if (!strncmp (p, ".save", 5))
1185 rc = save_command (p + 5);
1186 else
1188 rc = pwmd_command (pwm, result, len, inquire_cb, inq, line);
1189 #ifdef HAVE_LIBREADLINE
1190 if (interactive)
1192 #endif
1193 pwmd_free (keyfile);
1194 pwmd_free (new_keyfile);
1195 keyfile = new_keyfile = NULL;
1196 #ifdef HAVE_LIBREADLINE
1198 #endif
1201 return FINISH (rc);
1204 #ifdef HAVE_LIBREADLINE
1205 static gpg_error_t
1206 do_interactive ()
1208 gpg_error_t rc;
1209 struct inquire_s *inq = NULL;
1211 rl_initialize ();
1212 rc = process_cmd ();
1213 if (rc)
1214 return rc;
1216 rc = set_inquire (STDIN_FILENO, NULL, &inq);
1217 if (rc)
1218 return rc;
1220 fprintf (stderr,
1221 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1222 print_help ();
1223 rl_event_hook = &interactive_hook;
1224 rl_set_keyboard_input_timeout (100000);
1226 for (;;)
1228 char *line;
1229 char *result = NULL;
1230 size_t len;
1232 rc = 0;
1233 line = readline ("pwm> ");
1234 if (interactive_error)
1236 rc = interactive_error;
1237 break;
1240 if (!line)
1242 rc = finalize ();
1243 if (!rc)
1244 break;
1246 if (gpg_err_code (rc) != GPG_ERR_CANCELED &&
1247 gpg_err_code (rc) != GPG_ERR_EOF)
1248 fprintf (stderr, "ERR %i: %s\n", rc, gpg_strerror (rc));
1250 continue;
1252 else if (!*line)
1254 free (line);
1255 continue;
1258 #ifdef HAVE_READLINE_HISTORY
1259 add_history (line);
1260 #endif
1261 inq->header = 0;
1262 rc = parse_dotcommand (line, &result, &len, inq);
1263 free (line);
1264 if (rc)
1266 char *tmp = NULL;
1268 if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
1269 (void) pwmd_command (pwm, &tmp, NULL, NULL, NULL,
1270 "GETINFO last_error");
1272 show_error (rc, tmp);
1273 pwmd_free (tmp);
1275 else if (result && len)
1276 printf ("%s%s", result, result[len - 1] != '\n' ? "\n" : "");
1278 pwmd_free (result);
1281 free_inquire (inq);
1282 return rc;
1284 #endif
1286 static char *
1287 itoa (long long int n)
1289 static char buf[64];
1291 snprintf (buf, sizeof (buf), "%llu", n);
1292 return buf;
1295 static gpg_error_t
1296 finalize ()
1298 gpg_error_t rc = 0;
1299 #ifdef HAVE_LIBREADLINE
1300 int quit = 0;
1302 if (!force_save && interactive)
1304 char *p, buf[16];
1305 int finished = 0;
1307 fprintf (stderr, "\n");
1311 fprintf (stderr,
1313 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1314 p = fgets (buf, sizeof (buf), stdin);
1316 if (feof (stdin))
1318 clearerr (stdin);
1319 return GPG_ERR_EOF;
1322 switch (*p)
1324 case 'h':
1325 print_help ();
1326 break;
1327 case 'c':
1328 return GPG_ERR_CANCELED;
1329 case 'Q':
1330 return 0;
1331 case 'f':
1332 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1333 "CLEARCACHE %s", filename);
1334 if (rc)
1335 return rc;
1337 interactive_hook ();
1338 break;
1339 case 'S':
1340 quit = 1;
1341 case 's':
1342 save = 1;
1343 finished = 1;
1344 break;
1345 default:
1346 break;
1349 while (!finished);
1351 #endif
1353 if (save && !filename)
1355 fprintf (stderr,
1357 ("No filename was specified on the command line. Aborting.\n"));
1358 return GPG_ERR_CANCELED;
1361 if (save && filename)
1363 char *args =
1364 pwmd_strdup_printf ("%s%s %s%s %s %s%s %s%s %s %s --s2k-count=%lu",
1365 keygrip ? "--keygrip=" : "",
1366 keygrip ? keygrip : "",
1367 sign_keygrip ? "--sign-keygrip=" : "",
1368 sign_keygrip ? sign_keygrip : "",
1369 no_passphrase ? "--no-passphrase" : "",
1370 cipher ? "--cipher=" : "", cipher ? cipher : "",
1371 iterations_arg ? "--cipher-iterations=" : "",
1372 iterations_arg ? itoa (iterations) : "",
1373 no_gpg_agent ? "--no-agent" : "",
1374 keyparams ? "--inquire-keyparam" : "",
1375 s2k_count);
1377 #ifdef HAVE_LIBREADLINE
1378 if (!quiet || interactive)
1380 #else
1381 if (!quiet)
1383 #endif
1384 fprintf (stderr, "\n");
1385 fprintf (stderr, N_("Saving changes ...\n"));
1388 rc = save_command (args);
1389 pwmd_free (args);
1390 if (!rc)
1391 no_passphrase = 0; // reset to avoid usage error on the next SAVE
1394 #ifdef HAVE_LIBREADLINE
1395 if (interactive)
1396 return rc ? rc : quit ? 0 : GPG_ERR_CANCELED;
1397 #endif
1399 return rc;
1403 main (int argc, char *argv[])
1405 int connected = 0;
1406 gpg_error_t rc;
1407 int opt;
1408 char command[ASSUAN_LINELENGTH], *p = NULL;
1409 char *result = NULL;
1410 size_t len;
1411 char *pinentry_path = NULL;
1412 char *display = NULL, *tty = NULL, *ttytype = NULL;
1413 char *lcctype = NULL, *lcmessages = NULL;
1414 int outfd = STDOUT_FILENO;
1415 FILE *outfp = stdout;
1416 FILE *inquirefp = stdin;
1417 int show_status = 1;
1418 char *clientname = "pwmc";
1419 char *inquire = NULL;
1420 char *inquire_line = NULL;
1421 int timeout = 0;
1422 #ifdef WITH_SSH
1423 int use_ssh_agent = 1;
1424 char *knownhosts = NULL;
1425 char *identity = NULL;
1426 #endif
1427 #ifdef WITH_GNUTLS
1428 char *cacert = NULL;
1429 char *clientcert = NULL;
1430 char *clientkey = NULL;
1431 char *prio = NULL;
1432 int tls_verify = 0;
1433 char *tls_fingerprint = NULL;
1434 #endif
1435 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1436 pwmd_socket_t socktype;
1437 long socket_timeout = 300;
1438 int connect_timeout = 120;
1439 #endif
1440 int lock_on_open = 1;
1441 long lock_timeout = 50;
1442 char *url = NULL;
1443 /* The order is important. */
1444 enum
1446 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1447 OPT_SOCKET_TIMEOUT, OPT_CONNECT_TIMEOUT,
1448 #endif
1449 #ifdef WITH_SSH
1450 OPT_USE_SSH_AGENT, OPT_IDENTITY, OPT_KNOWNHOSTS,
1451 #endif
1452 #ifdef WITH_GNUTLS
1453 OPT_CACERT, OPT_CLIENTCERT, OPT_CLIENTKEY, OPT_PRIORITY, OPT_VERIFY,
1454 OPT_SERVER_FP,
1455 #endif
1456 OPT_URL, OPT_LOCAL, OPT_FORCE_SAVE, OPT_TTYNAME, OPT_TTYTYPE,
1457 OPT_DISPLAY, OPT_LC_CTYPE, OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES,
1458 OPT_PINENTRY, OPT_KEYFILE, OPT_NEW_KEYFILE, OPT_NOLOCK,
1459 OPT_LOCK_TIMEOUT, OPT_SAVE, OPT_OUTPUT_FD, OPT_INQUIRE,
1460 OPT_INQUIRE_FD, OPT_INQUIRE_FILE, OPT_INQUIRE_LINE, OPT_NO_STATUS,
1461 OPT_NAME, OPT_VERSION, OPT_HELP, OPT_KEYGRIP, OPT_SIGN_KEYGRIP,
1462 OPT_NOPASSPHRASE, OPT_CIPHER, OPT_KEYPARAMS, OPT_NO_PINENTRY,
1463 OPT_S2K_COUNT, OPT_ITERATIONS, OPT_QUIET, OPT_NO_GPG_AGENT,
1464 #ifdef HAVE_LIBREADLINE
1465 OPT_INTERACTIVE,
1466 #endif
1468 const struct option long_opts[] = {
1469 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1470 {"socket-timeout", 1, 0, 0},
1471 {"connect-timeout", 1, 0, 0},
1472 #endif
1474 #ifdef WITH_SSH
1475 {"no-ssh-agent", 0, 0, 0},
1476 {"identity", 1, 0, 'i'},
1477 {"knownhosts", 1, 0, 'k'},
1478 #endif
1479 #ifdef WITH_GNUTLS
1480 {"ca-cert", 1, 0, 0},
1481 {"client-cert", 1, 0, 0},
1482 {"client-key", 1, 0, 0},
1483 {"tls-priority", 1, 0, 0},
1484 {"tls-verify", 0, 0, 0},
1485 {"tls-fingerprint", 1, 0, 0},
1486 #endif
1487 {"url", 1, 0, 0},
1488 {"local-pinentry", 0, 0},
1489 {"force-save", 0, 0},
1490 {"ttyname", 1, 0, 'y'},
1491 {"ttytype", 1, 0, 't'},
1492 {"display", 1, 0, 'd'},
1493 {"lc-ctype", 1, 0, 0},
1494 {"lc-messages", 1, 0, 0},
1495 {"timeout", 1, 0, 0},
1496 {"tries", 1, 0, 0},
1497 {"pinentry", 1, 0, 0},
1498 {"key-file", 1, 0, 0},
1499 {"new-key-file", 1, 0, 0},
1500 {"no-lock", 0, 0, 0},
1501 {"lock-timeout", 1, 0, 0},
1502 {"save", 0, 0, 'S'},
1503 {"output-fd", 1, 0, 0},
1504 {"inquire", 1, 0, 0},
1505 {"inquire-fd", 1, 0, 0},
1506 {"inquire-file", 1, 0, 0},
1507 {"inquire-line", 1, 0, 'L'},
1508 {"no-status", 0, 0, 0},
1509 {"name", 1, 0, 'n'},
1510 {"version", 0, 0, 0},
1511 {"help", 0, 0, 0},
1512 {"keygrip", 1, 0, 0},
1513 {"sign-keygrip", 1, 0, 0},
1514 {"no-passphrase", 0, 0, 0},
1515 {"cipher", 1, 0, 0},
1516 {"key-params", 1, 0, 0},
1517 {"no-pinentry", 0, 0, 0},
1518 {"s2k-count", 1, 0, 0},
1519 {"cipher-iterations", 1, 0, 0},
1520 {"quiet", 0, 0, 0},
1521 {"no-gpg-agent", 0, 0, 0},
1522 #ifdef HAVE_LIBREADLINE
1523 {"interactive", 0, 0},
1524 #endif
1525 {0, 0, 0, 0}
1527 #ifdef WITH_SSH
1528 const char *optstring = "L:y:t:d:P:I:Sn:i:k:";
1529 #else
1530 const char *optstring = "L:y:t:d:P:I:Sn:";
1531 #endif
1532 int opt_index = 0;
1534 #ifdef ENABLE_NLS
1535 setlocale (LC_ALL, "");
1536 bindtextdomain ("libpwmd", LOCALEDIR);
1537 #endif
1539 tries = DEFAULT_PIN_TRIES;
1540 inquirefd = STDIN_FILENO;
1542 while ((opt =
1543 getopt_long (argc, argv, optstring, long_opts, &opt_index)) != -1)
1545 switch (opt)
1547 /* Handle long options without a short option part. */
1548 case 0:
1549 switch (opt_index)
1551 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1552 case OPT_SOCKET_TIMEOUT:
1553 socket_timeout = strtol (optarg, &p, 10);
1554 break;
1555 case OPT_CONNECT_TIMEOUT:
1556 connect_timeout = strtol (optarg, &p, 10);
1557 break;
1558 #endif
1559 #ifdef WITH_SSH
1560 case OPT_USE_SSH_AGENT:
1561 use_ssh_agent = 0;
1562 break;
1563 #endif
1564 #ifdef WITH_GNUTLS
1565 case OPT_CACERT:
1566 cacert = optarg;
1567 break;
1568 case OPT_CLIENTCERT:
1569 clientcert = optarg;
1570 break;
1571 case OPT_CLIENTKEY:
1572 clientkey = optarg;
1573 break;
1574 case OPT_PRIORITY:
1575 prio = optarg;
1576 break;
1577 case OPT_VERIFY:
1578 tls_verify = 1;
1579 break;
1580 case OPT_SERVER_FP:
1581 tls_fingerprint = optarg;
1582 break;
1583 #endif
1584 case OPT_NO_GPG_AGENT:
1585 no_gpg_agent = 1;
1586 break;
1587 case OPT_KEYPARAMS:
1588 keyparams = optarg;
1589 break;
1590 case OPT_KEYFILE:
1591 keyfile = pwmd_strdup (optarg);
1592 break;
1593 case OPT_NEW_KEYFILE:
1594 new_keyfile = pwmd_strdup (optarg);
1595 break;
1596 case OPT_NOLOCK:
1597 lock_on_open = 0;
1598 break;
1599 case OPT_LOCK_TIMEOUT:
1600 lock_timeout = strtol (optarg, &p, 10);
1601 break;
1602 case OPT_URL:
1603 url = optarg;
1604 break;
1605 case OPT_LOCAL:
1606 local_pin = 1;
1607 break;
1608 case OPT_FORCE_SAVE:
1609 save = force_save = 1;
1610 break;
1611 case OPT_LC_CTYPE:
1612 lcctype = pwmd_strdup (optarg);
1613 break;
1614 case OPT_LC_MESSAGES:
1615 lcmessages = pwmd_strdup (optarg);
1616 break;
1617 case OPT_TIMEOUT:
1618 timeout = strtol (optarg, &p, 10);
1619 break;
1620 case OPT_TRIES:
1621 tries = strtol (optarg, &p, 10);
1622 break;
1623 case OPT_INQUIRE:
1624 inquire = escape (optarg);
1625 break;
1626 case OPT_INQUIRE_FD:
1627 inquirefd = strtol (optarg, &p, 10);
1628 if (!p)
1630 inquirefp = fdopen (inquirefd, "r");
1631 if (!inquirefp)
1632 err (EXIT_FAILURE, "%i", inquirefd);
1634 break;
1635 case OPT_INQUIRE_FILE:
1636 inquirefd = open (optarg, O_RDONLY);
1637 if (inquirefd == -1)
1638 err (EXIT_FAILURE, "%s", optarg);
1639 inquirefp = fdopen (inquirefd, "r");
1640 break;
1641 case OPT_OUTPUT_FD:
1642 outfd = strtol (optarg, &p, 10);
1643 if (!p)
1645 outfp = fdopen (outfd, "w");
1646 if (!outfp)
1647 err (EXIT_FAILURE, "%i", outfd);
1649 break;
1650 case OPT_NO_STATUS:
1651 show_status = 0;
1652 break;
1653 case OPT_VERSION:
1654 printf ("%s (pwmc)\n\n"
1655 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013\n"
1656 "%s\n"
1657 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1658 "Compile-time features:\n"
1659 #ifdef HAVE_LIBREADLINE
1660 "+INTERACTIVE "
1661 #else
1662 "-INTERACTIVE "
1663 #endif
1664 #ifdef WITH_SSH
1665 "+SSH "
1666 #else
1667 "-SSH "
1668 #endif
1669 #ifdef WITH_GNUTLS
1670 "+GNUTLS "
1671 #else
1672 "-GNUTLS "
1673 #endif
1674 #ifdef WITH_PINENTRY
1675 "+PINENTRY "
1676 #else
1677 "-PINENTRY "
1678 #endif
1679 #ifdef WITH_QUALITY
1680 "+CRACK "
1681 #else
1682 "-CRACK "
1683 #endif
1684 #ifdef MEM_DEBUG
1685 "+MEM_DEBUG "
1686 #else
1687 "-MEM_DEBUG "
1688 #endif
1689 "\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1690 exit (EXIT_SUCCESS);
1691 case OPT_PINENTRY:
1692 pinentry_path = optarg;
1693 break;
1694 case OPT_HELP:
1695 usage (argv[0], EXIT_SUCCESS);
1696 case OPT_KEYGRIP:
1697 keygrip = optarg;
1698 break;
1699 case OPT_SIGN_KEYGRIP:
1700 sign_keygrip = optarg;
1701 break;
1702 case OPT_S2K_COUNT:
1703 s2k_count = strtoul (optarg, &p, 10);
1704 break;
1705 case OPT_ITERATIONS:
1706 iterations = strtoull (optarg, &p, 10);
1707 iterations_arg = 1;
1708 break;
1709 case OPT_QUIET:
1710 quiet = 1;
1711 show_status = 0;
1712 break;
1713 case OPT_NOPASSPHRASE:
1714 no_passphrase = 1;
1715 break;
1716 case OPT_CIPHER:
1717 cipher = optarg;
1718 break;
1719 case OPT_NO_PINENTRY:
1720 no_pinentry = 1;
1721 break;
1722 #ifdef HAVE_LIBREADLINE
1723 case OPT_INTERACTIVE:
1724 interactive = 1;
1725 break;
1726 #endif
1727 default:
1728 usage (argv[0], EXIT_FAILURE);
1731 if (p && *p)
1733 fprintf (stderr, N_("%s: invalid argument for option '--%s'\n"),
1734 argv[0], long_opts[opt_index].name);
1735 usage (argv[0], EXIT_FAILURE);
1738 break;
1739 #ifdef WITH_SSH
1740 case 'i':
1741 identity = optarg;
1742 break;
1743 case 'k':
1744 knownhosts = optarg;
1745 break;
1746 #endif
1747 case 'L':
1748 inquire_line = optarg;
1749 break;
1750 case 'y':
1751 tty = optarg;
1752 break;
1753 case 't':
1754 ttytype = optarg;
1755 break;
1756 case 'd':
1757 display = optarg;
1758 break;
1759 case 'S':
1760 save = 1;
1761 break;
1762 case 'n':
1763 clientname = optarg;
1764 break;
1765 default:
1766 usage (argv[0], EXIT_FAILURE);
1770 #ifdef HAVE_LIBREADLINE
1771 if (interactive && !isatty (STDIN_FILENO))
1772 usage (argv[0], EXIT_FAILURE);
1773 else if (isatty (STDIN_FILENO) && !inquire && !inquire_line)
1774 interactive = 1;
1775 #endif
1777 filename = argv[optind];
1778 #ifdef WITH_GNUTLS
1779 gnutls_global_set_mem_functions (pwmd_malloc, pwmd_malloc, NULL,
1780 pwmd_realloc, pwmd_free);
1781 #endif
1782 pwmd_init ();
1783 rc = pwmd_new (clientname, &pwm);
1784 if (rc)
1785 goto done;
1787 pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
1788 if (!quiet)
1789 fprintf (stderr, N_("Connecting ...\n"));
1791 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1792 socktype = is_remote_url (url);
1793 if (socktype != PWMD_SOCKET_LOCAL)
1795 local_pin = 1;
1796 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1797 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, connect_timeout);
1798 if (rc)
1799 goto done;
1800 #endif
1802 if (socktype == PWMD_SOCKET_SSH)
1804 #ifdef WITH_SSH
1805 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_CB, knownhost_cb);
1806 if (rc)
1807 goto done;
1809 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_DATA, clientname);
1810 if (rc)
1811 goto done;
1813 if (!getenv ("SSH_AUTH_SOCK") || identity)
1814 use_ssh_agent = 0;
1816 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_AGENT, use_ssh_agent);
1817 if (rc)
1818 goto done;
1820 rc = pwmd_connect (pwm, url, identity, knownhosts);
1821 #endif
1823 #ifdef WITH_GNUTLS
1824 else
1826 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_VERIFY, tls_verify);
1827 if (rc)
1828 goto done;
1830 rc = pwmd_connect (pwm, url, clientcert, clientkey, cacert, prio,
1831 tls_fingerprint);
1833 #endif
1835 else
1836 rc = pwmd_connect (pwm, url);
1837 #else
1838 rc = pwmd_connect (pwm, url);
1839 #endif
1840 if (rc)
1841 goto done;
1843 if (!quiet)
1844 fprintf (stderr, N_("Connected.\n"));
1846 connected = 1;
1847 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1848 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, socket_timeout);
1849 if (rc)
1850 goto done;
1851 #endif
1853 if (lock_timeout)
1855 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1856 "OPTION LOCK-TIMEOUT=%li", lock_timeout);
1857 if (rc)
1858 goto done;
1861 if (lock_on_open)
1863 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCK_ON_OPEN, 1);
1864 if (rc)
1865 goto done;
1868 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, NULL);
1869 if (rc)
1870 goto done;
1872 if (timeout > 0)
1874 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
1875 if (rc)
1876 goto done;
1879 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1880 if (rc)
1881 goto done;
1883 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY,
1884 (local_pin || keyfile || new_keyfile));
1885 if (rc)
1886 goto done;
1888 if (pinentry_path)
1890 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
1891 if (rc)
1892 goto done;
1895 if (display)
1897 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
1898 if (rc)
1899 goto done;
1902 if (tty)
1904 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, tty);
1905 if (rc)
1906 goto done;
1909 if (ttytype)
1911 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
1912 if (rc)
1913 goto done;
1916 if (lcctype)
1918 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
1919 if (rc)
1920 goto done;
1923 if (lcmessages)
1925 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES, lcmessages);
1926 if (rc)
1927 goto done;
1930 if (show_status)
1932 rc = pwmd_setopt (pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
1933 if (rc)
1934 goto done;
1937 if (filename)
1939 rc = open_command (filename);
1940 if (rc)
1941 goto done;
1944 #ifdef HAVE_LIBREADLINE
1945 if (interactive)
1947 if (!force_save)
1948 save = 0;
1950 rc = do_interactive ();
1951 result = NULL;
1952 goto do_exit;
1954 #endif
1956 if (inquire)
1958 struct inquire_s *inq = NULL;
1960 rc = set_inquire (inquirefd, inquire_line, &inq);
1961 if (!rc)
1962 rc = pwmd_command (pwm, &result, &len, inquire_cb, inq, inquire);
1964 free_inquire (inq);
1965 goto done;
1968 fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK);
1969 ssize_t n;
1971 for (;;)
1973 rc = process_cmd ();
1975 if (rc)
1976 goto done;
1978 n = read (STDIN_FILENO, command, sizeof (command));
1979 if (n == -1)
1981 if (errno == EAGAIN)
1983 usleep (100000);
1984 continue;
1987 rc = gpg_error_from_errno (errno);
1988 goto done;
1990 else if (!n)
1991 goto done;
1993 p = command;
1994 command[n] = 0;
1995 break;
1998 if (!p || !*p || !strcasecmp (p, "BYE"))
1999 goto done;
2002 struct inquire_s *inq = NULL;
2003 rc = set_inquire (inquirefd, inquire_line, &inq);
2004 if (!rc)
2006 rc = parse_dotcommand (command, &result, &len, inq);
2007 free_inquire (inq);
2010 if (rc)
2011 goto done;
2013 done:
2014 if (result)
2016 fwrite (result, 1, result[len - 1] == 0 ? len - 1 : len, outfp);
2017 fflush (outfp);
2018 pwmd_free (result);
2021 result = NULL;
2022 if (!rc)
2023 rc = finalize ();
2024 else if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
2025 (void) pwmd_command (pwm, &result, NULL, NULL, NULL,
2026 "GETINFO last_error");
2028 #ifdef HAVE_LIBREADLINE
2029 do_exit:
2030 #endif
2031 memset (command, 0, sizeof (command));
2032 pwmd_close (pwm);
2033 pwmd_free (keyfile);
2034 pwmd_free (new_keyfile);
2035 pwmd_deinit ();
2037 if (rc && !quiet)
2038 show_error (rc, result);
2040 pwmd_free (result);
2041 if (connected && !quiet)
2042 fprintf (stderr, N_("Connection closed.\n"));
2044 exit (rc ? EXIT_FAILURE : EXIT_SUCCESS);