Require an SHA-256 hash for an TLS fingerprint.
[libpwmd.git] / src / pwmc.c
blob0fbcd6bbaad333407239f224a357adac316e603a
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014
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_TIMEOUT 30
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 *keyfile;
97 static char *new_keyfile;
98 static unsigned long s2k_count;
99 static uint64_t iterations;
100 static int iterations_arg;
101 static int tries;
102 static int local_pin;
103 static int inquirefd;
104 static int quiet;
105 static int no_gpg_agent;
107 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
127 show_error (gpg_error_t rc, const char *str)
129 fprintf (stderr, "ERR %i: %s%s%s%s", rc, gpg_strerror (rc),
130 str ? ": " : "", str ? str : "", str ? "" : "\n");
133 static void
134 usage (const char *pn, int status)
136 fprintf (status == EXIT_FAILURE ? stderr : stdout,
137 N_("Usage: pwmc [options] [file]\n"
138 " --url <string>\n"
139 " a url string to connect to (%s, see below)\n"
140 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
141 " --connect-timeout <seconds>\n"
142 " seconds before connecting to a remote host fails (0=disabled, 120)\n"
143 " --socket-timeout <seconds>\n"
144 " seconds before a remote command fails (0=disabled, 300)\n"
145 #endif
146 #ifdef WITH_GNUTLS
147 " --ca-cert <filename>\n"
148 " certificate authority (CA) used to sign the server cert\n"
149 " --client-cert <filename>\n"
150 " client certificate to use for authentication\n"
151 " --client-key <filename>\n"
152 " key file used to protect the client certificate\n"
153 " --tls-priority <string>\n"
154 " compression, cipher and hash algorithm string (SECURE256)\n"
155 " --tls-verify\n"
156 " verify the hostname against the server certificate\n"
157 " --tls-fingerprint <string>\n"
158 " a SHA-256 hash of the server fingerprint to verify against\n"
159 #endif
160 #ifdef WITH_SSH
161 " --no-ssh-agent\n"
162 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
163 " --identity, -i <filename>\n"
164 " the ssh identity file to use for authentication\n"
165 " --knownhosts, -k <filename>\n"
166 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
167 #endif
168 " --no-lock\n"
169 " do not lock the data file upon opening it\n"
170 " --lock-timeout <N>\n"
171 " time in tenths of a second to wait for a locked data file (50)\n"
172 " --name, -n <string>\n"
173 " set the client name\n"
174 " --pinentry <path>\n"
175 " the full path to the pinentry binary (server default)\n"
176 " --local-pinentry\n"
177 " force using a local pinentry\n"
178 " --no-pinentry\n"
179 " disable pinentry both remotely and locally\n"
180 " --ttyname, -y <path>\n"
181 " tty that pinentry will use\n"
182 " --ttytype, -t <string>\n"
183 " pinentry terminal type (default is $TERM)\n"
184 " --display, -d\n"
185 " pinentry display (default is $DISPLAY)\n"
186 " --lc-ctype <string>\n"
187 " locale setting for pinentry\n"
188 " --lc-messages <string>\n"
189 " locale setting for pinentry\n"
190 " --tries <N>\n"
191 " number of pinentry tries before failing (3)\n"
192 " --timeout <seconds>\n"
193 " pinentry timeout\n"
194 " --inquire <COMMAND>\n"
195 " the specified command (with any options) uses a server inquire while\n"
196 " command data is read via the inquire file descriptor (stdin)\n"
197 " --inquire-line, -L <STRING>\n"
198 " the initial line to send (i.e., element path) before the inquire data\n"
199 " --inquire-fd <FD>\n"
200 " read inquire data from the specified file descriptor (stdin)\n"
201 " --inquire-file <filename>\n"
202 " read inquire data from the specified filename\n"
203 " --output-fd <FD>\n"
204 " redirect command output to the specified file descriptor\n"
205 " --save, -S\n"
206 " send the SAVE command before exiting\n"
207 " --force-save\n"
208 " like --save but always ask for a passphrase\n"
209 " --no-passphrase\n"
210 " do not require a passphrase when saving a new file\n"
211 " --no-gpg-agent\n"
212 " disable use of gpg-agent when saving to a new file\n"
213 " --key-file <filename>\n"
214 " obtain the passphrase from the specified filename\n"
215 " --new-key-file <filename>\n"
216 " obtain the passphrase to save with from the specified filename\n"
217 " --cipher <string>\n"
218 " the cipher to use when saving (see pwmd(1))\n"
219 " --cipher-iterations <N>\n"
220 " the number of times to encrypt the XML data (N+1)\n"
221 " --key-params <string>\n"
222 " the key parameters to use when saving a new file (pwmd default)\n"
223 " --keygrip <string>\n"
224 " the hex string of the keygrip to save to\n"
225 " --sign-keygrip <string>\n"
226 " the hex string of the keygrip to sign with\n"
227 " --s2k-count <N>\n"
228 " the number of times to hash the passphrase for a new file\n"
229 " --no-status\n"
230 " disable showing of status messages from the server\n"
231 " --quiet\n"
232 " disable showing of extra messages (implies --no-status)\n"
233 #ifdef HAVE_LIBREADLINE
234 " --interactive\n"
235 " use a shell like interface to pwmd (allows more than one command)\n"
236 #endif
237 " --version\n"
238 " --help\n"),
239 #ifdef DEFAULT_PWMD_SOCKET
240 DEFAULT_PWMD_SOCKET
241 #else
242 "~/.pwmd/socket"
243 #endif
245 fprintf (status == EXIT_FAILURE ? stderr : stdout,
246 N_("\n"
247 "An optional url may be in the form of:\n"
248 " --url /path/to/socket\n"
249 " --url file://[path/to/socket]\n"
250 #ifdef WITH_SSH
251 " or\n"
252 " --url ssh[46]://[username@]hostname[:port]\n"
253 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
254 #endif
255 #ifdef WITH_GNUTLS
256 " or\n"
257 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
258 " --client-key filename\n"
259 #endif
260 #ifdef HAVE_LIBREADLINE
261 "\n"
262 "Interactive mode is used when input is from a terminal.\n"
263 #endif
265 exit (status);
268 static gpg_error_t
269 inquire_cb (void *user, const char *keyword, gpg_error_t rc,
270 char **data, size_t * size)
272 struct inquire_s *inq = user;
273 int is_password = 0;
274 int is_newpassword = 0;
276 *data = NULL;
277 *size = 0;
279 if (rc)
280 return rc;
282 if (!strcmp (keyword, "PASSPHRASE"))
283 is_password = 1;
284 else if (!strcmp (keyword, "NEW_PASSPHRASE"))
285 is_newpassword = 1;
286 #ifdef HAVE_LIBREADLINE
287 else if (!strcmp (keyword, "KEYPARAM") && !interactive)
289 #else
290 else if (!strcmp (keyword, "KEYPARAM"))
292 #endif
293 if (!keyparams || !*keyparams)
294 return gpg_error (GPG_ERR_INV_PARAMETER);
296 *data = keyparams;
297 *size = strlen (keyparams);
298 return gpg_error (GPG_ERR_EOF);
301 if ((is_newpassword && new_keyfile) || (is_password && keyfile))
303 int fd = open (is_password ? keyfile : new_keyfile, O_RDONLY);
305 if (fd == -1)
307 fprintf (stderr, "%s: %s\n", is_newpassword ? new_keyfile : keyfile,
308 strerror (errno));
309 return gpg_error_from_syserror ();
312 rc = set_inquire (fd, NULL, &inq);
313 if (rc)
315 close (fd);
316 return rc;
319 if (!quiet)
320 fprintf (stderr, N_("Using keyfile '%s' as %s.\n"),
321 is_newpassword ? new_keyfile : keyfile, keyword);
323 if (!new_keyfile || is_newpassword)
325 pwmd_socket_t t;
327 pwmd_socket_type (pwm, &t);
328 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
329 if (!no_pinentry && t == PWMD_SOCKET_LOCAL)
330 pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 0);
333 else if ((is_password && !keyfile) || (is_newpassword && !new_keyfile))
335 char *tmp;
337 rc = pwmd_password (pwm, keyword, &tmp, &inq->len);
338 if (rc && gpg_err_code (rc) != GPG_ERR_EOF)
339 return rc;
341 pwmd_free (inq->line);
342 inq->line = tmp;
343 *data = inq->line;
344 *size = inq->len;
345 return gpg_error (GPG_ERR_EOF);
347 #ifdef HAVE_LIBREADLINE
348 else if (!inq->header && interactive)
350 fprintf (stderr,
352 ("Press CTRL-D to send the current line. Press twice to end. %s:\n"),
353 keyword);
354 inq->header = 1;
356 #endif
358 /* The first part of the command data. */
359 if (inq->len)
361 *data = inq->line;
362 *size = inq->len;
363 inq->len = 0;
364 return inq->fd == -1 ? gpg_error (GPG_ERR_EOF) : 0;
367 *size = read (inq->fd, inq->line, ASSUAN_LINELENGTH);
368 if (*size == -1)
370 *size = 0;
371 return gpg_error (gpg_error_from_syserror ());
373 else if (*size)
374 *data = inq->line;
375 else if (inq->fd != STDIN_FILENO && (is_newpassword || is_password))
377 *inq->line = 0;
378 inq->size = 1;
379 *data = inq->line;
380 *size = 1;
383 if (((is_newpassword && new_keyfile) || (is_password && keyfile))
384 && *size == inq->size)
385 return gpg_error (GPG_ERR_EOF);
387 return *size ? 0 : gpg_error (GPG_ERR_EOF);
390 static int
391 status_msg_cb (void *data, const char *line)
393 char *p = strchr (line, ' ');
395 if (!strcmp (line, "KEEPALIVE"))
396 return 0;
398 if (*line != '#' && p && strchr (p, ' ') && *++p)
400 char *p1 = strchr (p, ' ');
401 int a = strtol (p, NULL, 10);
403 if (isdigit (*p) && p1)
405 int b = strtol (p1, NULL, 10);
406 char l[64] = { 0 };
407 int t = a && b ? a * 100 / b : 0;
409 strncpy (l, line, strlen (line) - strlen (p) - 1);
410 fprintf (stderr, "\r%s %i/%i %i%%%s", l, a, b, t,
411 a == b ? "\n" : "");
412 fflush (stderr);
413 return 0;
417 fprintf (stderr, "%s\n", line);
418 fflush (stderr);
419 #ifdef HAVE_LIBREADLINE
420 rl_on_new_line ();
421 #endif
422 return 0;
425 static gpg_error_t
426 process_cmd ()
428 return pwmd_process (pwm);
431 #ifdef WITH_SSH
432 static gpg_error_t
433 get_password (char **result, pwmd_pinentry_t w, int echo)
435 char buf[LINE_MAX] = { 0 }, *p;
436 struct termios told, tnew;
437 char *key = NULL;
439 *result = NULL;
441 if (!isatty (STDIN_FILENO))
443 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
444 return GPG_ERR_ENOTTY;
447 if (!echo)
449 if (tcgetattr (STDIN_FILENO, &told) == -1)
450 return gpg_error_from_syserror ();
452 memcpy (&tnew, &told, sizeof (struct termios));
453 tnew.c_lflag &= ~(ECHO);
454 tnew.c_lflag |= ICANON | ECHONL;
456 if (tcsetattr (STDIN_FILENO, TCSANOW, &tnew) == -1)
458 int n = errno;
460 tcsetattr (STDIN_FILENO, TCSANOW, &told);
461 return gpg_error_from_errno (n);
465 switch (w)
467 case PWMD_PINENTRY_OPEN:
468 fprintf (stderr, N_("Password for %s: "), filename);
469 break;
470 case PWMD_PINENTRY_OPEN_FAILED:
471 fprintf (stderr, N_("Invalid password. Password for %s: "), filename);
472 break;
473 case PWMD_PINENTRY_SAVE:
474 fprintf (stderr, N_("New password for %s: "), filename);
475 break;
476 case PWMD_PINENTRY_SAVE_CONFIRM:
477 fprintf (stderr, N_("Confirm password: "));
478 break;
479 default:
480 break;
483 if ((p = fgets (buf, sizeof (buf), stdin)) == NULL)
485 tcsetattr (STDIN_FILENO, TCSANOW, &told);
486 return 0;
489 if (!echo)
490 tcsetattr (STDIN_FILENO, TCSANOW, &told);
492 if (feof (stdin))
494 clearerr (stdin);
495 return GPG_ERR_CANCELED;
498 p[strlen (p) - 1] = 0;
500 if (buf[0])
502 key = pwmd_strdup_printf ("%s", p);
503 memset (&buf, 0, sizeof (buf));
505 if (!key)
506 return GPG_ERR_ENOMEM;
509 *result = key;
510 return 0;
513 static gpg_error_t
514 knownhost_cb (void *data, const char *host, const char *key, size_t len)
516 gpg_error_t rc;
517 char *buf =
518 pwmd_strdup_printf (N_
519 ("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?"),
520 (char *) data, host, host);
522 if (no_pinentry && !isatty (STDIN_FILENO))
524 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
525 pwmd_free (buf);
526 return GPG_ERR_ENOTTY;
528 else if (no_pinentry)
530 for (char *p = buf, len = 0; *p; p++, len++)
532 if (*p == '\n')
533 len = 0;
535 if (len == 78)
537 char *t = p;
539 while (!isspace (*(--p)));
540 *p = '\n';
541 p = t;
542 len = 0;
546 fprintf (stderr, "%s\n\n", buf);
547 pwmd_free (buf);
551 char *result;
553 fprintf (stderr, N_("Trust this connection [y/N]: "));
554 fflush (stderr);
555 rc = get_password (&result, PWMD_PINENTRY_CONFIRM, 1);
557 if (rc)
558 return rc;
560 if (!result || !*result || *result == 'n' || *result == 'N')
562 if (result && *result)
563 pwmd_free (result);
565 return GPG_ERR_NOT_CONFIRMED;
568 if ((*result == 'y' || *result == 'Y') && *(result + 1) == 0)
570 pwmd_free (result);
571 return 0;
574 while (1);
577 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, buf);
578 pwmd_free (buf);
580 if (rc)
581 return rc;
583 return pwmd_getpin (pwm, NULL, NULL, NULL, PWMD_PINENTRY_CONFIRM);
585 #endif
587 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
588 static pwmd_socket_t
589 is_remote_url (const char *str)
591 if (!str)
592 return PWMD_SOCKET_LOCAL;
594 #ifdef WITH_SSH
595 if (strstr (str, "ssh://") || strstr (str, "ssh4://")
596 || strstr (str, "ssh6://"))
597 return PWMD_SOCKET_SSH;
598 #endif
600 #ifdef WITH_GNUTLS
601 if (strstr (str, "tls://") || strstr (str, "tls4://")
602 || strstr (str, "tls6://"))
603 return PWMD_SOCKET_TLS;
604 #endif
606 return PWMD_SOCKET_LOCAL;
608 #endif
610 static char *
611 escape (const char *str)
613 const char *p;
614 char *buf = pwmd_malloc (ASSUAN_LINELENGTH + 1), *b = buf;
615 size_t len = 0;
617 for (p = str; *p; p++, len++)
619 if (len == ASSUAN_LINELENGTH)
620 break;
622 if (*p == '\\')
624 switch (*++p)
626 case 't':
627 *b++ = '\t';
628 break;
629 case 'n':
630 *b++ = '\n';
631 break;
632 case 'v':
633 *b++ = '\v';
634 break;
635 case 'b':
636 *b++ = '\b';
637 break;
638 case 'f':
639 *b++ = '\f';
640 break;
641 case 'r':
642 *b++ = '\r';
643 break;
644 default:
645 *b++ = *p;
646 break;
649 if (!*p)
650 break;
652 continue;
655 *b++ = *p;
658 *b = 0;
659 return buf;
662 static void
663 free_inquire (struct inquire_s *inq)
665 if (!inq)
666 return;
668 pwmd_free (inq->line);
670 if (inq->fd != -1 && inq->fd != STDIN_FILENO)
671 close (inq->fd);
673 pwmd_free (inq);
676 /* When *result is not NULL it is updated to the new values and not
677 * reallocated. */
678 static gpg_error_t
679 set_inquire (int fd, const char *line, struct inquire_s **result)
681 struct inquire_s inq = { 0 };
682 struct stat st = { 0 };
683 gpg_error_t rc;
685 if (fd != -1)
687 if (fstat (fd, &st) == -1)
688 return gpg_error_from_syserror ();
690 inq.size = st.st_size;
693 inq.fd = fd;
694 inq.line = pwmd_calloc (1, ASSUAN_LINELENGTH);
695 if (!inq.line)
696 return GPG_ERR_ENOMEM;
698 if (line)
700 char *s = escape (line);
702 if (!s)
704 pwmd_free (inq.line);
705 return GPG_ERR_ENOMEM;
708 if (strlen (s) >= ASSUAN_LINELENGTH)
710 pwmd_free (inq.line);
711 pwmd_free (s);
712 return GPG_ERR_LINE_TOO_LONG;
715 strncpy (inq.line, s, ASSUAN_LINELENGTH - 1);
716 inq.len = strlen (s);
717 pwmd_free (s);
720 rc = pwmd_setopt (pwm, PWMD_OPTION_INQUIRE_TOTAL,
721 st.st_size ? st.st_size + strlen (inq.line) : 0);
722 if (rc)
724 pwmd_free (inq.line);
725 return rc;
728 if (*result == NULL)
729 *result = pwmd_malloc (sizeof (struct inquire_s));
730 else
732 if ((*result)->fd != -1 && (*result)->fd != STDIN_FILENO)
733 close ((*result)->fd);
735 pwmd_free ((*result)->line);
736 (*result)->line = NULL;
737 (*result)->fd = -1;
738 (*result)->len = 0;
741 memcpy (*result, &inq, sizeof (struct inquire_s));
742 memset (&inq, 0, sizeof (struct inquire_s));
743 return rc;
746 #ifdef HAVE_LIBREADLINE
747 static int
748 interactive_hook (void)
750 interactive_error = process_cmd ();
752 if (interactive_error)
753 rl_event_hook = NULL;
755 return 0;
758 static void
759 print_help ()
761 fprintf (stderr,
763 ("------------------------------------------------------------------------------\n"
764 "Elements are TAB delimited. Press CTRL-V then TAB to insert from the prompt.\n"
765 "\n"
766 "Type HELP for protocol commands. Type .help for pwmc commands. Press CTRL-D\n"
767 "to quit.\n"
768 "------------------------------------------------------------------------------\n"));
770 #endif
772 static char *
773 parse_arg (const char *src, char *dst, size_t len)
775 char *p = dst;
776 const char *s = src;
777 size_t n = 0;
779 for (; s && *s && *s != ' ' && n < len; s++, n++)
780 *p++ = *s;
782 *p = 0;
783 return dst;
786 static char *
787 parse_opt (char **line, const char *opt, gpg_error_t * rc)
789 static char result[ASSUAN_LINELENGTH] = { 0 }, *r = result;
790 char *s = strstr (*line, opt);
792 *rc = 0;
793 result[0] = 0;
794 r = result;
796 if (s)
798 size_t len = 0;
799 int quote = 0;
800 size_t rlen = strlen (opt);
801 char *p = s + rlen;
802 int lastc = 0;
804 while (*p && *p == ' ')
806 rlen++;
807 p++;
810 for (; *p && len < sizeof (result) - 1; p++, rlen++)
812 if (isspace (*p) && !quote)
813 break;
815 if (*p == '\"' && lastc != '\\')
817 quote = !quote;
818 lastc = *p;
819 continue;
822 *r++ = lastc = *p;
823 len++;
826 *r = 0;
828 if (len >= sizeof (result) - 1)
829 *rc = GPG_ERR_LINE_TOO_LONG;
830 else
832 p = s + rlen;
834 while (*p && *p == ' ')
835 p++;
837 *line = p;
841 return result;
844 static gpg_error_t
845 read_command (const char *line, char **result, size_t * len)
847 int fd;
848 gpg_error_t rc = 0;
849 char *filename = NULL;
850 struct inquire_s *inq = NULL;
851 char *p = (char *) line;
852 const char *prefix = parse_opt (&p, "--prefix", &rc);
854 if (rc)
855 return rc;
857 rc = GPG_ERR_SYNTAX;
859 if (p && *p)
861 char filebuf[ASSUAN_LINELENGTH];
863 while (*p && isspace (*p))
864 p++;
866 filename = parse_arg (p, filebuf, sizeof (filebuf));
867 if (filename && *filename)
869 p += strlen (filename) + 1;
871 while (*p && isspace (*p))
872 p++;
874 if (*p)
875 rc = 0;
879 if (rc)
881 fprintf (stderr,
883 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
884 fprintf (stderr,
886 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\" = \")\n"));
887 return rc;
890 fd = open (filename, O_RDONLY);
891 if (fd == -1)
892 return gpg_error_from_syserror ();
894 rc = set_inquire (fd, prefix && *prefix ? prefix : NULL, &inq);
895 if (rc)
897 close (fd);
898 return rc;
901 inq->header = 1;
902 rc = pwmd_command (pwm, result, len, inquire_cb, inq, p);
903 free_inquire (inq);
904 return rc;
907 static gpg_error_t
908 redir_command (const char *line)
910 const char *p = line;
911 int fd;
912 gpg_error_t rc = GPG_ERR_SYNTAX;
913 char *filename = NULL;
914 struct inquire_s *inq = NULL;
915 char *result = NULL;
916 size_t len = 0;
918 if (p && *p && *++p)
920 char filebuf[ASSUAN_LINELENGTH];
922 filename = parse_arg (p, filebuf, sizeof (filebuf));
923 if (filename && *filename)
925 p += strlen (filename) + 1;
927 while (*p && isspace (*p))
928 p++;
930 if (*p)
931 rc = 0;
935 if (rc)
937 fprintf (stderr, N_("Usage: .redir <filename> <command> [args]\n"));
938 return rc;
941 fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
942 if (fd == -1)
943 return gpg_error_from_syserror ();
945 #ifdef HAVE_LIBREADLINE
946 rc = set_inquire (interactive ? STDIN_FILENO : inquirefd, NULL, &inq);
947 #else
948 rc = set_inquire (inquirefd, NULL, &inq);
949 #endif
950 if (rc)
952 close (fd);
953 return rc;
956 rc = parse_dotcommand (p, &result, &len, inq);
957 if (!rc && result && len--)
958 { // null byte which is always appended
959 if (write (fd, result, len) != len)
960 rc = GPG_ERR_TOO_SHORT;
961 pwmd_free (result);
964 free_inquire (inq);
965 close (fd);
966 return rc;
969 static gpg_error_t
970 help_command (const char *line)
972 fprintf (stderr,
973 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
974 " .redir <filename> <command>\n"
975 " redirect the output of a command to the specified file\n"
976 "\n"
977 " .open <filename>\n"
978 " open the specified filename losing any changes to the current one\n"
979 "\n"
980 " .read [--prefix <string>] <filename> <command> [args]\n"
981 " obtain data from the specified filename for an inquire command\n"
982 "\n"
983 " .set help | <name> [<value>]\n"
984 " set option <name> to <value>\n"
985 "\n"
986 " .save [args]\n"
987 " write changes of the file to disk\n"
988 "\n"
989 " .passwd [args]\n"
990 " change the passphrase of a data file\n"
991 "\n"
992 " .help\n"
993 " this help text\n"));
994 return 0;
997 static gpg_error_t
998 open_command (const char *line)
1000 struct inquire_s *inq = NULL;
1001 const char *filename = line;
1002 gpg_error_t rc;
1004 while (filename && isspace (*filename))
1005 filename++;
1007 if (!filename || !*filename)
1009 fprintf (stderr, N_("Usage: .open <filename>\n"));
1010 return GPG_ERR_SYNTAX;
1013 #ifdef HAVE_LIBREADLINE
1014 if (interactive || !quiet)
1015 #else
1016 if (!quiet)
1017 #endif
1018 fprintf (stderr, N_("Opening data file \"%s\" ...\n"), filename);
1020 #ifdef HAVE_LIBREADLINE
1021 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1022 #else
1023 rc = set_inquire (-1, NULL, &inq);
1024 #endif
1025 if (rc)
1026 return rc;
1028 if (keyfile)
1029 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1031 rc = pwmd_open (pwm, filename, inquire_cb, inq);
1032 free_inquire (inq);
1033 return rc;
1036 static gpg_error_t
1037 set_command (const char *line)
1039 gpg_error_t rc = 0;
1040 char name[256] = { 0 };
1041 char value[512] = { 0 };
1042 char *namep;
1043 char *valuep;
1044 const char *p = line;
1046 while (p && *p && isspace (*p))
1047 p++;
1049 namep = parse_arg (p, name, sizeof (name));
1050 if (!namep || !*namep)
1052 fprintf (stderr, N_("Usage: .set help | <name> [<value>]\n"));
1053 return GPG_ERR_SYNTAX;
1056 p += strlen (namep);
1057 while (p && *p && isspace (*p))
1058 p++;
1060 valuep = parse_arg (p, value, sizeof (value));
1062 if (!strcmp (name, "keyfile") || !strcmp (name, "new-keyfile"))
1064 int is_newkeyfile = 1;
1065 int is_pkcs = 1;
1067 if (!strcmp (name, "keyfile"))
1068 is_newkeyfile = 0;
1070 if (is_newkeyfile)
1072 pwmd_free (new_keyfile);
1073 new_keyfile = NULL;
1075 else
1077 pwmd_free (keyfile);
1078 keyfile = NULL;
1081 p += strlen (valuep);
1082 while (p && *p && isspace (*p))
1083 p++;
1085 valuep = (char *) p;
1086 if (*valuep)
1088 char datafile[256];
1090 memcpy (datafile, value, sizeof (datafile));
1091 valuep = parse_arg (p, value, sizeof (value));
1092 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "KEYGRIP %s",
1093 datafile);
1094 if (gpg_err_code (rc) == GPG_ERR_NOT_SUPPORTED
1095 || (gpg_err_source (rc) == GPG_ERR_SOURCE_USER_1
1096 && gpg_err_code (rc) == GPG_ERR_ENOENT))
1098 rc = 0;
1099 is_pkcs = 0;
1101 else if (!rc)
1102 is_pkcs = 1;
1105 if (!rc && *valuep)
1107 if (is_newkeyfile)
1108 new_keyfile = pwmd_strdup (value);
1109 else
1110 keyfile = pwmd_strdup (value);
1112 if (!is_pkcs)
1113 rc = 0;
1114 else
1115 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1116 "AGENT option pinentry-mode=loopback");
1118 if (!rc)
1120 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 1);
1121 if (!rc)
1122 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1125 else if (!local_pin && !no_pinentry)
1127 pwmd_socket_t t;
1129 pwmd_socket_type (pwm, &t);
1130 if (t == PWMD_SOCKET_LOCAL)
1132 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 0);
1133 if (!rc)
1134 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1138 else if (!strcmp(name, "pinentry-timeout"))
1140 char *e = NULL;
1141 int n = strtol(valuep, &e, 10);
1143 if (e && *e)
1144 return gpg_error (GPG_ERR_INV_VALUE);
1146 if (!valuep || !*valuep)
1147 n = DEFAULT_PIN_TIMEOUT;
1149 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, n);
1151 else if (!strcmp (name, "help"))
1153 fprintf (stderr,
1155 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1156 "delimited. When no value is specified the option is unset.\n\n"
1157 "keyfile <datafile> [<filename>]\n"
1158 " set or unset the keyfile to be used when a passphrase is required (*)\n"
1159 "\n"
1160 "new-keyfile <datafile> [<filename>]\n"
1161 " set or unset the keyfile to be used when a new passphrase is required (*)\n"
1162 "\n"
1163 "pinentry-timeout <seconds>\n"
1164 " the amount of seconds before pinentry gives up waiting for input\n"
1165 "\n"
1166 "* = the next protocol command will unset this value\n"
1169 else
1170 rc = GPG_ERR_UNKNOWN_OPTION;
1172 return rc;
1175 static gpg_error_t
1176 save_command (const char *line)
1178 struct inquire_s *inq = NULL;
1179 gpg_error_t rc;
1181 #ifdef HAVE_LIBREADLINE
1182 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1183 #else
1184 rc = set_inquire (-1, NULL, &inq);
1185 #endif
1186 if (rc)
1187 return rc;
1189 if (new_keyfile || keyfile)
1190 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1192 rc = pwmd_save (pwm, line, inquire_cb, inq);
1193 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1194 free_inquire (inq);
1195 return rc;
1198 static gpg_error_t
1199 do_save_passwd_command (const char *line, int save)
1201 struct inquire_s *inq = NULL;
1202 gpg_error_t rc;
1204 #ifdef HAVE_LIBREADLINE
1205 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1206 #else
1207 rc = set_inquire (-1, NULL, &inq);
1208 #endif
1209 if (rc)
1210 return rc;
1212 if (new_keyfile || keyfile)
1213 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1215 if (save)
1216 rc = pwmd_save (pwm, line, inquire_cb, inq);
1217 else
1218 rc = pwmd_passwd (pwm, line, inquire_cb, inq);
1220 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1221 free_inquire (inq);
1222 return rc;
1225 static gpg_error_t
1226 parse_dotcommand (const char *line, char **result,
1227 size_t * len, struct inquire_s *inq)
1229 const char *p = line;
1230 gpg_error_t rc = 0;
1232 if (!strncmp (p, ".read", 5))
1233 rc = read_command (p + 5, result, len);
1234 else if (!strncmp (p, ".redir", 6))
1235 rc = redir_command (p + 6);
1236 else if (!strncmp (p, ".help", 5))
1237 rc = help_command (p + 5);
1238 else if (!strncmp (p, ".open", 5))
1239 rc = open_command (p + 5);
1240 else if (!strncmp (p, ".set", 4))
1241 rc = set_command (p + 4);
1242 else if (!strncmp (p, ".save", 5))
1243 rc = do_save_passwd_command (p + 5, 1);
1244 else if (!strncmp (p, ".passwd", 7))
1245 rc = do_save_passwd_command (p + 7, 0);
1246 else
1248 rc = pwmd_command (pwm, result, len, inquire_cb, inq, line);
1249 #ifdef HAVE_LIBREADLINE
1250 if (interactive)
1252 #endif
1253 pwmd_free (keyfile);
1254 pwmd_free (new_keyfile);
1255 keyfile = new_keyfile = NULL;
1256 #ifdef HAVE_LIBREADLINE
1258 #endif
1261 return FINISH (rc);
1264 #ifdef HAVE_LIBREADLINE
1265 static gpg_error_t
1266 do_interactive ()
1268 gpg_error_t rc;
1269 struct inquire_s *inq = NULL;
1271 rl_initialize ();
1272 rc = process_cmd ();
1273 if (rc)
1274 return rc;
1276 rc = set_inquire (STDIN_FILENO, NULL, &inq);
1277 if (rc)
1278 return rc;
1280 fprintf (stderr,
1281 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1282 print_help ();
1283 rl_event_hook = &interactive_hook;
1284 rl_set_keyboard_input_timeout (100000);
1286 for (;;)
1288 char *line;
1289 char *result = NULL;
1290 size_t len;
1292 rc = 0;
1293 line = readline ("pwm> ");
1294 if (interactive_error)
1296 rc = interactive_error;
1297 break;
1300 if (!line)
1302 rc = finalize ();
1303 if (!rc)
1304 break;
1306 if (gpg_err_code (rc) != GPG_ERR_CANCELED &&
1307 gpg_err_code (rc) != GPG_ERR_EOF)
1308 fprintf (stderr, "ERR %i: %s\n", rc, gpg_strerror (rc));
1310 continue;
1312 else if (!*line)
1314 free (line);
1315 continue;
1318 #ifdef HAVE_READLINE_HISTORY
1319 add_history (line);
1320 #endif
1321 inq->header = 0;
1322 rc = parse_dotcommand (line, &result, &len, inq);
1323 free (line);
1324 if (rc)
1326 char *tmp = NULL;
1328 if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
1329 (void) pwmd_command (pwm, &tmp, NULL, NULL, NULL,
1330 "GETINFO last_error");
1332 show_error (rc, tmp);
1333 pwmd_free (tmp);
1335 else if (result && len)
1336 printf ("%s%s", result, result[len - 1] != '\n' ? "\n" : "");
1338 pwmd_free (result);
1341 free_inquire (inq);
1342 return rc;
1344 #endif
1346 static char *
1347 itoa (long long int n)
1349 static char buf[64];
1351 snprintf (buf, sizeof (buf), "%lli", n);
1352 return buf;
1355 static gpg_error_t
1356 finalize ()
1358 gpg_error_t rc = 0;
1359 #ifdef HAVE_LIBREADLINE
1360 int quit = 0;
1362 if (!force_save && interactive)
1364 int finished = 0;
1366 fprintf (stderr, "\n");
1370 char *p, buf[16];
1372 fprintf (stderr,
1374 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1375 p = fgets (buf, sizeof (buf), stdin);
1377 if (feof (stdin))
1379 clearerr (stdin);
1380 return GPG_ERR_EOF;
1383 switch (*p)
1385 case 'h':
1386 print_help ();
1387 break;
1388 case 'c':
1389 return GPG_ERR_CANCELED;
1390 case 'Q':
1391 return 0;
1392 case 'f':
1393 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1394 "CLEARCACHE %s", filename);
1395 if (rc)
1396 return rc;
1398 interactive_hook ();
1399 break;
1400 case 'S':
1401 quit = 1;
1402 case 's':
1403 save = 1;
1404 finished = 1;
1405 break;
1406 default:
1407 break;
1410 while (!finished);
1412 #endif
1414 if (save && !filename)
1416 fprintf (stderr,
1418 ("No filename was specified on the command line. Aborting.\n"));
1419 return GPG_ERR_CANCELED;
1422 if (save && filename)
1424 char *args =
1425 pwmd_strdup_printf ("%s%s %s%s %s %s%s %s%s %s %s %s --s2k-count=%lu",
1426 keygrip ? "--keygrip=" : "",
1427 keygrip ? keygrip : "",
1428 sign_keygrip ? "--sign-keygrip=" : "",
1429 sign_keygrip ? sign_keygrip : "",
1430 no_passphrase ? "--no-passphrase" : "",
1431 cipher ? "--cipher=" : "", cipher ? cipher : "",
1432 iterations_arg ? "--cipher-iterations=" : "",
1433 iterations_arg ? itoa (iterations) : "",
1434 no_gpg_agent ? "--no-agent" : "",
1435 keyparams ? "--inquire-keyparam" : "",
1436 force_save ? "--reset" : "", s2k_count);
1438 #ifdef HAVE_LIBREADLINE
1439 if (!quiet || interactive)
1441 #else
1442 if (!quiet)
1444 #endif
1445 fprintf (stderr, "\n");
1446 fprintf (stderr, N_("Saving changes ...\n"));
1449 rc = save_command (args);
1450 pwmd_free (args);
1451 if (!rc)
1452 no_passphrase = 0; // reset to avoid usage error on the next SAVE
1455 #ifdef HAVE_LIBREADLINE
1456 if (interactive)
1457 return rc ? rc : quit ? 0 : GPG_ERR_CANCELED;
1458 #endif
1460 return rc;
1464 main (int argc, char *argv[])
1466 int connected = 0;
1467 gpg_error_t rc;
1468 int opt;
1469 char command[ASSUAN_LINELENGTH], *p = NULL;
1470 char *result = NULL;
1471 size_t len = 0;
1472 char *pinentry_path = NULL;
1473 char *display = NULL, *tty = NULL, *ttytype = NULL;
1474 char *lcctype = NULL, *lcmessages = NULL;
1475 int outfd = STDOUT_FILENO;
1476 FILE *outfp = stdout;
1477 FILE *inquirefp = stdin;
1478 int show_status = 1;
1479 char *clientname = "pwmc";
1480 char *inquire = NULL;
1481 char *inquire_line = NULL;
1482 int timeout = 0;
1483 #ifdef WITH_SSH
1484 int use_ssh_agent = 1;
1485 char *knownhosts = NULL;
1486 char *identity = NULL;
1487 #endif
1488 #ifdef WITH_GNUTLS
1489 char *cacert = NULL;
1490 char *clientcert = NULL;
1491 char *clientkey = NULL;
1492 char *prio = NULL;
1493 int tls_verify = 0;
1494 char *tls_fingerprint = NULL;
1495 #endif
1496 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1497 pwmd_socket_t socktype;
1498 long socket_timeout = 300;
1499 int connect_timeout = 120;
1500 #endif
1501 int lock_on_open = 1;
1502 long lock_timeout = 50;
1503 char *url = NULL;
1504 /* The order is important. */
1505 enum
1507 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1508 OPT_SOCKET_TIMEOUT, OPT_CONNECT_TIMEOUT,
1509 #endif
1510 #ifdef WITH_SSH
1511 OPT_USE_SSH_AGENT, OPT_IDENTITY, OPT_KNOWNHOSTS,
1512 #endif
1513 #ifdef WITH_GNUTLS
1514 OPT_CACERT, OPT_CLIENTCERT, OPT_CLIENTKEY, OPT_PRIORITY, OPT_VERIFY,
1515 OPT_SERVER_FP,
1516 #endif
1517 OPT_URL, OPT_LOCAL, OPT_FORCE_SAVE, OPT_TTYNAME, OPT_TTYTYPE,
1518 OPT_DISPLAY, OPT_LC_CTYPE, OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES,
1519 OPT_PINENTRY, OPT_KEYFILE, OPT_NEW_KEYFILE, OPT_NOLOCK,
1520 OPT_LOCK_TIMEOUT, OPT_SAVE, OPT_OUTPUT_FD, OPT_INQUIRE,
1521 OPT_INQUIRE_FD, OPT_INQUIRE_FILE, OPT_INQUIRE_LINE, OPT_NO_STATUS,
1522 OPT_NAME, OPT_VERSION, OPT_HELP, OPT_KEYGRIP, OPT_SIGN_KEYGRIP,
1523 OPT_NOPASSPHRASE, OPT_CIPHER, OPT_KEYPARAMS, OPT_NO_PINENTRY,
1524 OPT_S2K_COUNT, OPT_ITERATIONS, OPT_QUIET, OPT_NO_GPG_AGENT,
1525 #ifdef HAVE_LIBREADLINE
1526 OPT_INTERACTIVE,
1527 #endif
1529 const struct option long_opts[] = {
1530 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1531 {"socket-timeout", 1, 0, 0},
1532 {"connect-timeout", 1, 0, 0},
1533 #endif
1535 #ifdef WITH_SSH
1536 {"no-ssh-agent", 0, 0, 0},
1537 {"identity", 1, 0, 'i'},
1538 {"knownhosts", 1, 0, 'k'},
1539 #endif
1540 #ifdef WITH_GNUTLS
1541 {"ca-cert", 1, 0, 0},
1542 {"client-cert", 1, 0, 0},
1543 {"client-key", 1, 0, 0},
1544 {"tls-priority", 1, 0, 0},
1545 {"tls-verify", 0, 0, 0},
1546 {"tls-fingerprint", 1, 0, 0},
1547 #endif
1548 {"url", 1, 0, 0},
1549 {"local-pinentry", 0, 0},
1550 {"force-save", 0, 0},
1551 {"ttyname", 1, 0, 'y'},
1552 {"ttytype", 1, 0, 't'},
1553 {"display", 1, 0, 'd'},
1554 {"lc-ctype", 1, 0, 0},
1555 {"lc-messages", 1, 0, 0},
1556 {"timeout", 1, 0, 0},
1557 {"tries", 1, 0, 0},
1558 {"pinentry", 1, 0, 0},
1559 {"key-file", 1, 0, 0},
1560 {"new-key-file", 1, 0, 0},
1561 {"no-lock", 0, 0, 0},
1562 {"lock-timeout", 1, 0, 0},
1563 {"save", 0, 0, 'S'},
1564 {"output-fd", 1, 0, 0},
1565 {"inquire", 1, 0, 0},
1566 {"inquire-fd", 1, 0, 0},
1567 {"inquire-file", 1, 0, 0},
1568 {"inquire-line", 1, 0, 'L'},
1569 {"no-status", 0, 0, 0},
1570 {"name", 1, 0, 'n'},
1571 {"version", 0, 0, 0},
1572 {"help", 0, 0, 0},
1573 {"keygrip", 1, 0, 0},
1574 {"sign-keygrip", 1, 0, 0},
1575 {"no-passphrase", 0, 0, 0},
1576 {"cipher", 1, 0, 0},
1577 {"key-params", 1, 0, 0},
1578 {"no-pinentry", 0, 0, 0},
1579 {"s2k-count", 1, 0, 0},
1580 {"cipher-iterations", 1, 0, 0},
1581 {"quiet", 0, 0, 0},
1582 {"no-gpg-agent", 0, 0, 0},
1583 #ifdef HAVE_LIBREADLINE
1584 {"interactive", 0, 0},
1585 #endif
1586 {0, 0, 0, 0}
1588 #ifdef WITH_SSH
1589 const char *optstring = "L:y:t:d:P:I:Sn:i:k:";
1590 #else
1591 const char *optstring = "L:y:t:d:P:I:Sn:";
1592 #endif
1593 int opt_index = 0;
1595 #ifdef ENABLE_NLS
1596 setlocale (LC_ALL, "");
1597 bindtextdomain ("libpwmd", LOCALEDIR);
1598 #endif
1600 tries = DEFAULT_PIN_TRIES;
1601 inquirefd = STDIN_FILENO;
1603 while ((opt =
1604 getopt_long (argc, argv, optstring, long_opts, &opt_index)) != -1)
1606 switch (opt)
1608 /* Handle long options without a short option part. */
1609 case 0:
1610 switch (opt_index)
1612 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1613 case OPT_SOCKET_TIMEOUT:
1614 socket_timeout = strtol (optarg, &p, 10);
1615 break;
1616 case OPT_CONNECT_TIMEOUT:
1617 connect_timeout = strtol (optarg, &p, 10);
1618 break;
1619 #endif
1620 #ifdef WITH_SSH
1621 case OPT_USE_SSH_AGENT:
1622 use_ssh_agent = 0;
1623 break;
1624 #endif
1625 #ifdef WITH_GNUTLS
1626 case OPT_CACERT:
1627 cacert = optarg;
1628 break;
1629 case OPT_CLIENTCERT:
1630 clientcert = optarg;
1631 break;
1632 case OPT_CLIENTKEY:
1633 clientkey = optarg;
1634 break;
1635 case OPT_PRIORITY:
1636 prio = optarg;
1637 break;
1638 case OPT_VERIFY:
1639 tls_verify = 1;
1640 break;
1641 case OPT_SERVER_FP:
1642 tls_fingerprint = optarg;
1643 break;
1644 #endif
1645 case OPT_NO_GPG_AGENT:
1646 no_gpg_agent = 1;
1647 break;
1648 case OPT_KEYPARAMS:
1649 keyparams = optarg;
1650 break;
1651 case OPT_KEYFILE:
1652 keyfile = pwmd_strdup (optarg);
1653 break;
1654 case OPT_NEW_KEYFILE:
1655 new_keyfile = pwmd_strdup (optarg);
1656 break;
1657 case OPT_NOLOCK:
1658 lock_on_open = 0;
1659 break;
1660 case OPT_LOCK_TIMEOUT:
1661 lock_timeout = strtol (optarg, &p, 10);
1662 break;
1663 case OPT_URL:
1664 url = optarg;
1665 break;
1666 case OPT_LOCAL:
1667 local_pin = 1;
1668 break;
1669 case OPT_FORCE_SAVE:
1670 save = force_save = 1;
1671 break;
1672 case OPT_LC_CTYPE:
1673 lcctype = pwmd_strdup (optarg);
1674 break;
1675 case OPT_LC_MESSAGES:
1676 lcmessages = pwmd_strdup (optarg);
1677 break;
1678 case OPT_TIMEOUT:
1679 timeout = strtol (optarg, &p, 10);
1680 break;
1681 case OPT_TRIES:
1682 tries = strtol (optarg, &p, 10);
1683 break;
1684 case OPT_INQUIRE:
1685 inquire = escape (optarg);
1686 break;
1687 case OPT_INQUIRE_FD:
1688 inquirefd = strtol (optarg, &p, 10);
1689 if (!p)
1691 inquirefp = fdopen (inquirefd, "r");
1692 if (!inquirefp)
1693 err (EXIT_FAILURE, "%i", inquirefd);
1695 break;
1696 case OPT_INQUIRE_FILE:
1697 inquirefd = open (optarg, O_RDONLY);
1698 if (inquirefd == -1)
1699 err (EXIT_FAILURE, "%s", optarg);
1700 inquirefp = fdopen (inquirefd, "r");
1701 break;
1702 case OPT_OUTPUT_FD:
1703 outfd = strtol (optarg, &p, 10);
1704 if (!p)
1706 outfp = fdopen (outfd, "w");
1707 if (!outfp)
1708 err (EXIT_FAILURE, "%i", outfd);
1710 break;
1711 case OPT_NO_STATUS:
1712 show_status = 0;
1713 break;
1714 case OPT_VERSION:
1715 printf ("%s (pwmc)\n\n"
1716 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014\n"
1717 "%s\n"
1718 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1719 "Compile-time features:\n"
1720 #ifdef HAVE_LIBREADLINE
1721 "+INTERACTIVE "
1722 #else
1723 "-INTERACTIVE "
1724 #endif
1725 #ifdef WITH_SSH
1726 "+SSH "
1727 #else
1728 "-SSH "
1729 #endif
1730 #ifdef WITH_GNUTLS
1731 "+GNUTLS "
1732 #else
1733 "-GNUTLS "
1734 #endif
1735 #ifdef WITH_PINENTRY
1736 "+PINENTRY "
1737 #else
1738 "-PINENTRY "
1739 #endif
1740 #ifdef WITH_QUALITY
1741 "+CRACK "
1742 #else
1743 "-CRACK "
1744 #endif
1745 #ifdef MEM_DEBUG
1746 "+MEM_DEBUG "
1747 #else
1748 "-MEM_DEBUG "
1749 #endif
1750 "\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1751 exit (EXIT_SUCCESS);
1752 case OPT_PINENTRY:
1753 pinentry_path = optarg;
1754 break;
1755 case OPT_HELP:
1756 usage (argv[0], EXIT_SUCCESS);
1757 case OPT_KEYGRIP:
1758 keygrip = optarg;
1759 break;
1760 case OPT_SIGN_KEYGRIP:
1761 sign_keygrip = optarg;
1762 break;
1763 case OPT_S2K_COUNT:
1764 s2k_count = strtoul (optarg, &p, 10);
1765 break;
1766 case OPT_ITERATIONS:
1767 iterations = strtoull (optarg, &p, 10);
1768 iterations_arg = 1;
1769 break;
1770 case OPT_QUIET:
1771 quiet = 1;
1772 show_status = 0;
1773 break;
1774 case OPT_NOPASSPHRASE:
1775 no_passphrase = 1;
1776 break;
1777 case OPT_CIPHER:
1778 cipher = optarg;
1779 break;
1780 case OPT_NO_PINENTRY:
1781 no_pinentry = 1;
1782 break;
1783 #ifdef HAVE_LIBREADLINE
1784 case OPT_INTERACTIVE:
1785 interactive = 1;
1786 break;
1787 #endif
1788 default:
1789 usage (argv[0], EXIT_FAILURE);
1792 if (p && *p)
1794 fprintf (stderr, N_("%s: invalid argument for option '--%s'\n"),
1795 argv[0], long_opts[opt_index].name);
1796 usage (argv[0], EXIT_FAILURE);
1799 break;
1800 #ifdef WITH_SSH
1801 case 'i':
1802 identity = optarg;
1803 break;
1804 case 'k':
1805 knownhosts = optarg;
1806 break;
1807 #endif
1808 case 'L':
1809 inquire_line = optarg;
1810 break;
1811 case 'y':
1812 tty = optarg;
1813 break;
1814 case 't':
1815 ttytype = optarg;
1816 break;
1817 case 'd':
1818 display = optarg;
1819 break;
1820 case 'S':
1821 save = 1;
1822 break;
1823 case 'n':
1824 clientname = optarg;
1825 break;
1826 default:
1827 usage (argv[0], EXIT_FAILURE);
1831 #ifdef HAVE_LIBREADLINE
1832 if (interactive && !isatty (STDIN_FILENO))
1833 usage (argv[0], EXIT_FAILURE);
1834 else if (isatty (STDIN_FILENO) && !inquire && !inquire_line)
1835 interactive = 1;
1836 #endif
1838 filename = argv[optind];
1839 #ifdef WITH_GNUTLS
1840 gnutls_global_set_mem_functions (pwmd_malloc, pwmd_malloc, NULL,
1841 pwmd_realloc, pwmd_free);
1842 #endif
1843 pwmd_init ();
1844 rc = pwmd_new (clientname, &pwm);
1845 if (rc)
1846 goto done;
1848 pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
1849 if (!quiet)
1850 fprintf (stderr, N_("Connecting ...\n"));
1852 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1853 socktype = is_remote_url (url);
1854 if (socktype != PWMD_SOCKET_LOCAL)
1856 local_pin = 1;
1857 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1858 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, connect_timeout);
1859 if (rc)
1860 goto done;
1861 #endif
1863 if (socktype == PWMD_SOCKET_SSH)
1865 #ifdef WITH_SSH
1866 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_CB, knownhost_cb);
1867 if (rc)
1868 goto done;
1870 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_DATA, clientname);
1871 if (rc)
1872 goto done;
1874 if (!getenv ("SSH_AUTH_SOCK") || identity)
1875 use_ssh_agent = 0;
1877 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_AGENT, use_ssh_agent);
1878 if (rc)
1879 goto done;
1881 rc = pwmd_connect (pwm, url, identity, knownhosts);
1882 #endif
1884 #ifdef WITH_GNUTLS
1885 else
1887 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_VERIFY, tls_verify);
1888 if (rc)
1889 goto done;
1891 rc = pwmd_connect (pwm, url, clientcert, clientkey, cacert, prio,
1892 tls_fingerprint);
1894 #endif
1896 else
1897 rc = pwmd_connect (pwm, url);
1898 #else
1899 rc = pwmd_connect (pwm, url);
1900 #endif
1901 if (rc)
1902 goto done;
1904 if (!quiet)
1905 fprintf (stderr, N_("Connected.\n"));
1907 connected = 1;
1908 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1909 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, socket_timeout);
1910 if (rc)
1911 goto done;
1912 #endif
1914 if (lock_timeout)
1916 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1917 "OPTION LOCK-TIMEOUT=%li", lock_timeout);
1918 if (rc)
1919 goto done;
1922 if (lock_on_open)
1924 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCK_ON_OPEN, 1);
1925 if (rc)
1926 goto done;
1929 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, NULL, NULL);
1930 if (rc)
1931 goto done;
1933 if (timeout > 0)
1935 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
1936 if (rc)
1937 goto done;
1940 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1941 if (rc)
1942 goto done;
1944 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY,
1945 (local_pin || keyfile || new_keyfile));
1946 if (rc)
1947 goto done;
1949 if (pinentry_path)
1951 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
1952 if (rc)
1953 goto done;
1956 if (display)
1958 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
1959 if (rc)
1960 goto done;
1963 if (tty)
1965 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, tty);
1966 if (rc)
1967 goto done;
1970 if (ttytype)
1972 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
1973 if (rc)
1974 goto done;
1977 if (lcctype)
1979 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
1980 if (rc)
1981 goto done;
1984 if (lcmessages)
1986 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES, lcmessages);
1987 if (rc)
1988 goto done;
1991 if (show_status)
1993 rc = pwmd_setopt (pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
1994 if (rc)
1995 goto done;
1998 if (filename)
2000 rc = open_command (filename);
2001 if (rc)
2002 goto done;
2005 #ifdef HAVE_LIBREADLINE
2006 if (interactive)
2008 if (!force_save)
2009 save = 0;
2011 rc = do_interactive ();
2012 result = NULL;
2013 goto do_exit;
2015 #endif
2017 if (inquire)
2019 struct inquire_s *inq = NULL;
2021 rc = set_inquire (inquirefd, inquire_line, &inq);
2022 if (!rc)
2023 rc = pwmd_command (pwm, &result, &len, inquire_cb, inq, inquire);
2025 free_inquire (inq);
2026 goto done;
2029 fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK);
2030 ssize_t n;
2032 for (;;)
2034 rc = process_cmd ();
2036 if (rc)
2037 goto done;
2039 n = read (STDIN_FILENO, command, sizeof (command));
2040 if (n == -1)
2042 if (errno == EAGAIN)
2044 usleep (100000);
2045 continue;
2048 rc = gpg_error_from_errno (errno);
2049 goto done;
2051 else if (!n)
2052 goto done;
2054 p = command;
2055 command[n] = 0;
2056 break;
2059 if (!p || !*p || !strcasecmp (p, "BYE"))
2060 goto done;
2063 struct inquire_s *inq = NULL;
2064 rc = set_inquire (inquirefd, inquire_line, &inq);
2065 if (!rc)
2067 rc = parse_dotcommand (command, &result, &len, inq);
2068 free_inquire (inq);
2071 if (rc)
2072 goto done;
2074 done:
2075 if (result)
2077 fwrite (result, 1, result[len - 1] == 0 ? len - 1 : len, outfp);
2078 fflush (outfp);
2079 pwmd_free (result);
2082 result = NULL;
2083 if (!rc)
2084 rc = finalize ();
2085 else if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
2086 (void) pwmd_command (pwm, &result, NULL, NULL, NULL,
2087 "GETINFO last_error");
2089 #ifdef HAVE_LIBREADLINE
2090 do_exit:
2091 #endif
2092 memset (command, 0, sizeof (command));
2093 pwmd_close (pwm);
2094 pwmd_free (keyfile);
2095 pwmd_free (new_keyfile);
2096 pwmd_deinit ();
2098 if (rc && !quiet)
2099 show_error (rc, result);
2101 pwmd_free (result);
2102 if (connected && !quiet)
2103 fprintf (stderr, N_("Connection closed.\n"));
2105 exit (rc ? EXIT_FAILURE : EXIT_SUCCESS);