pwmc: keyfile fixes.
[libpwmd.git] / src / pwmc.c
blob83f84451d36626d21bf1392e9485e852197b2bb8
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015
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 WITH_GNUTLS
43 #include <gnutls/gnutls.h>
44 #endif
46 #ifdef HAVE_LOCALE_H
47 #include <locale.h>
48 #endif
50 #ifdef HAVE_GETOPT_LONG
51 #ifdef HAVE_GETOPT_H
52 #include <getopt.h>
53 #endif
54 #else
55 #include "getopt_long.h"
56 #endif
58 #ifdef HAVE_LIBREADLINE
59 #if defined(HAVE_READLINE_READLINE_H)
60 #include <readline/readline.h>
61 #elif defined(HAVE_READLINE_H)
62 #include <readline.h>
63 #endif /* !defined(HAVE_READLINE_H) */
64 static int interactive_error;
65 static int interactive;
66 #endif /* HAVE_LIBREADLINE */
68 #ifdef HAVE_READLINE_HISTORY
69 #if defined(HAVE_READLINE_HISTORY_H)
70 #include <readline/history.h>
71 #elif defined(HAVE_HISTORY_H)
72 #include <history.h>
73 #endif
74 #endif /* HAVE_READLINE_HISTORY */
76 #ifndef LINE_MAX
77 #define LINE_MAX 2048
78 #endif
80 #include "gettext.h"
81 #define N_(msgid) gettext(msgid)
83 #include "mem.h"
86 #define DEFAULT_STATUS_IGNORE "KEEPALIVE,STATE,GPGME,PASSPHRASE_INFO,PASSPHRASE_HINT"
87 #define DEFAULT_PIN_TIMEOUT 30
88 #define DEFAULT_PIN_TRIES 3
89 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
90 ? gpg_error(rc) : rc
92 static int no_pinentry;
93 static pwm_t *pwm;
94 static char *filename;
95 static int save;
96 static char *keyid;
97 static char *sign_keyid;
98 static char *keyparams;
99 static char *keyfile;
100 static char *new_keyfile;
101 static int tries;
102 static int local_pin;
103 static int inquirefd;
104 static int statusfd;
105 FILE *statusfp;
106 static int quiet;
107 static char **status_ignore;
109 struct inquire_s
111 int fd;
112 char *line;
113 size_t len;
114 size_t size; // from stat(2).
115 char *last_keyword;
118 static gpg_error_t finalize ();
119 static gpg_error_t set_inquire (int fd, const char *line,
120 struct inquire_s **result);
121 static gpg_error_t parse_dotcommand (const char *line, char **result,
122 size_t * len, struct inquire_s *inq);
123 static gpg_error_t open_command (const char *line);
124 #ifdef WITH_SSH
125 static gpg_error_t get_password (char **result, pwmd_pinentry_t w, int echo);
126 #endif
128 static void
129 show_error (pwm_t *pwm, gpg_error_t rc, const char *str)
131 #ifdef WITH_GNUTLS
132 if (pwmd_tls_error (pwm))
133 fprintf(stderr, "TLS: %s\n", gnutls_strerror(pwmd_tls_error(pwm)));
134 #endif
135 fprintf (stderr, "ERR %i: %s%s%s%s", rc, gpg_strerror (rc),
136 str ? ": " : "", str ? str : "", str ? "" : "\n");
139 static void
140 reset_keyfiles ()
142 pwmd_free (keyfile);
143 pwmd_free (new_keyfile);
144 keyfile = new_keyfile = NULL;
147 static void
148 usage (const char *pn, int status)
150 fprintf (status == EXIT_FAILURE ? stderr : stdout,
151 N_("Usage: pwmc [options] [file]\n"
152 " --url <string>\n"
153 " a url string to connect to (%s, see below)\n"
154 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
155 " --connect-timeout <seconds>\n"
156 " seconds before connecting to a remote host fails (0=disabled, 120)\n"
157 " --socket-timeout <seconds>\n"
158 " seconds before a remote command fails (0=disabled, 300)\n"
159 #endif
160 #ifdef WITH_GNUTLS
161 " --ca-cert <filename>\n"
162 " certificate authority (CA) used to sign the server cert\n"
163 " --client-cert <filename>\n"
164 " client certificate to use for authentication\n"
165 " --client-key <filename>\n"
166 " key file used to protect the client certificate\n"
167 " --tls-priority <string>\n"
168 " compression, cipher and hash algorithm string\n"
169 " (SECURE256:SECURE192:SECURE128:-VERS-SSL3.0)\n"
170 " --tls-verify\n"
171 " verify the hostname against the server certificate\n"
172 " --tls-fingerprint <string>\n"
173 " a SHA-256 hash of the server fingerprint to verify against\n"
174 #endif
175 #ifdef WITH_SSH
176 " --no-ssh-agent\n"
177 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
178 " --identity, -i <filename>\n"
179 " the ssh identity file to use for authentication\n"
180 " --knownhosts, -k <filename>\n"
181 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
182 #endif
183 " --no-lock\n"
184 " do not lock the data file upon opening it\n"
185 " --lock-timeout <N>\n"
186 " time in tenths of a second to wait for a locked data file (50)\n"
187 " --name, -n <string>\n"
188 " set the client name\n"
189 " --pinentry <path>\n"
190 " the full path to the pinentry binary\n"
191 " --local-pinentry\n"
192 " force using a local pinentry\n"
193 " --no-pinentry\n"
194 " disable pinentry both remotely and locally\n"
195 " --ttyname, -y <path>\n"
196 " tty that pinentry will use\n"
197 " --ttytype, -t <string>\n"
198 " pinentry terminal type (default is $TERM)\n"
199 " --display, -d\n"
200 " pinentry display (default is $DISPLAY)\n"
201 " --lc-ctype <string>\n"
202 " locale setting for pinentry\n"
203 " --lc-messages <string>\n"
204 " locale setting for pinentry\n"
205 " --tries <N>\n"
206 " number of pinentry tries before failing (3)\n"
207 " --timeout <seconds>\n"
208 " pinentry timeout\n"
209 " --inquire <COMMAND>\n"
210 " the specified command (with any options) uses a server inquire while\n"
211 " command data is read via the inquire file descriptor (stdin)\n"
212 " --inquire-line, -L <STRING>\n"
213 " the initial line to send (i.e., element path) before the inquire data\n"
214 " --inquire-fd <FD>\n"
215 " read inquire data from the specified file descriptor (stdin)\n"
216 " --inquire-file <filename>\n"
217 " read inquire data from the specified filename\n"
218 " --output-fd <FD>\n"
219 " redirect command output to the specified file descriptor\n"
220 " --save, -S\n"
221 " send the SAVE command before exiting\n"
222 " --key-file <filename>\n"
223 " obtain the passphrase from the specified filename\n"
224 " --new-key-file <filename>\n"
225 " obtain the passphrase to save with from the specified filename\n"
226 " --key-params <string>\n"
227 " the key parameters to use when saving a new file (pwmd default)\n"
228 " --keyid <recipient>[,<recipient>]\n"
229 " the public key ID to u\n"
230 " --sign-keyid <string>\n"
231 " the key ID to sign the data file with\n"
232 " --no-status\n"
233 " disable showing of status messages from the server\n"
234 " --status-ignore <string[,...]>\n"
235 " prevent parsing of the specified status message keywords\n"
236 " --quiet\n"
237 " disable showing of extra messages (implies --no-status)\n"
238 " --status-fd <FD>\n"
239 " redirect status messages to the specified file descriptor\n"
240 #ifdef HAVE_LIBREADLINE
241 " --interactive\n"
242 " use a shell like interface to pwmd (allows more than one command)\n"
243 #endif
244 " --version\n"
245 " --help\n"),
246 #ifdef DEFAULT_PWMD_SOCKET
247 DEFAULT_PWMD_SOCKET
248 #else
249 "~/.pwmd/socket"
250 #endif
252 fprintf (status == EXIT_FAILURE ? stderr : stdout,
253 N_("\n"
254 "An optional url may be in the form of:\n"
255 " --url /path/to/socket\n"
256 " --url file://[path/to/socket]\n"
257 #ifdef WITH_SSH
258 " or\n"
259 " --url ssh[46]://[username@]hostname[:port]\n"
260 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
261 #endif
262 #ifdef WITH_GNUTLS
263 " or\n"
264 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
265 " --client-key filename\n"
266 #endif
267 #ifdef HAVE_LIBREADLINE
268 "\n"
269 "Interactive mode is used when input is from a terminal.\n"
270 #endif
272 exit (status);
275 static gpg_error_t
276 inquire_cb (void *user, const char *keyword, gpg_error_t rc,
277 char **data, size_t * size)
279 struct inquire_s *inq = user;
280 int is_password = 0;
281 int is_newpassword = 0;
283 *data = NULL;
284 *size = 0;
286 if (rc)
287 return rc;
289 if (!strcmp (keyword, "PASSPHRASE"))
290 is_password = 1;
291 else if (!strcmp (keyword, "NEW_PASSPHRASE"))
292 is_newpassword = 1;
293 #ifdef HAVE_LIBREADLINE
294 else if (!strcmp (keyword, "KEYPARAM") && !interactive)
296 #else
297 else if (!strcmp (keyword, "KEYPARAM"))
299 #endif
300 if (!keyparams || !*keyparams)
301 return gpg_error (GPG_ERR_INV_PARAMETER);
303 *data = keyparams;
304 *size = strlen (keyparams);
305 return gpg_error (GPG_ERR_EOF);
308 if ((is_newpassword && new_keyfile) || (is_password && keyfile))
310 int fd = open (is_password ? keyfile : new_keyfile, O_RDONLY);
312 if (fd == -1)
314 fprintf (stderr, "%s: %s\n", is_newpassword ? new_keyfile : keyfile,
315 strerror (errno));
316 return gpg_error_from_syserror ();
319 rc = set_inquire (fd, NULL, &inq);
320 if (rc)
322 close (fd);
323 return rc;
326 if (!quiet)
327 fprintf (stderr, N_("Using keyfile '%s' as %s.\n"),
328 is_newpassword ? new_keyfile : keyfile, keyword);
330 else if ((is_password && !keyfile) || (is_newpassword && !new_keyfile))
332 char *tmp;
334 rc = pwmd_password (pwm, keyword, &tmp, &inq->len);
335 if (rc && gpg_err_code (rc) != GPG_ERR_EOF)
336 return rc;
338 pwmd_free (inq->line);
339 inq->line = tmp;
340 *data = inq->line;
341 *size = inq->len;
342 return gpg_error (GPG_ERR_EOF);
344 #ifdef HAVE_LIBREADLINE
345 else if ((!inq->last_keyword || strcmp (keyword, inq->last_keyword))
346 && interactive)
348 fprintf (stderr,
350 ("%sPress CTRL-D to send the current line. Press twice to end. %s:\n"),
351 inq->last_keyword ? "\n" : "", keyword);
352 pwmd_free (inq->last_keyword);
353 inq->last_keyword = pwmd_strdup (keyword);
355 #endif
357 /* The first part of the command data. */
358 if (inq->len)
360 *data = inq->line;
361 *size = inq->len;
362 inq->len = 0;
363 return inq->fd == -1 ? gpg_error (GPG_ERR_EOF) : 0;
366 *size = read (inq->fd, inq->line, ASSUAN_LINELENGTH);
367 if (*size == -1)
369 *size = 0;
370 return gpg_error (gpg_error_from_syserror ());
372 else if (*size)
373 *data = inq->line;
374 else if (inq->fd != STDIN_FILENO && (is_newpassword || is_password))
376 *inq->line = 0;
377 inq->size = 1;
378 *data = inq->line;
379 *size = 1;
382 if (((is_newpassword && new_keyfile) || (is_password && keyfile))
383 && *size == inq->size)
384 return gpg_error (GPG_ERR_EOF);
386 return *size ? 0 : gpg_error (GPG_ERR_EOF);
389 static int
390 status_msg_cb (void *data, const char *line)
392 char *p = strchr (line, ' ');
393 char **s;
395 /* Ignore status messages specified by the client via --status-ignore. */
396 for (s = status_ignore; s && *s; s++)
398 char *tmp = strchr (line, ' ');
399 size_t len = tmp ? strlen (line) - strlen (tmp) : strlen (line);
401 if (!strncmp (line, *s, len) && len == strlen (*s))
402 return 0;
405 if (statusfd != STDERR_FILENO && strncmp (line, "STATE ", 6) && *line != '#'
406 && p && strchr (p, ' ') && *++p)
408 char *p1 = strchr (p, ' ');
409 int a = strtol (p, NULL, 10);
411 if (isdigit (*p) && p1)
413 int b = strtol (p1, NULL, 10);
414 char l[64] = { 0 };
415 int t = a && b ? a * 100 / b : 0;
417 strncpy (l, line, strlen (line) - strlen (p) - 1);
418 fprintf (statusfp, "\r%s %i/%i %i%%%s", l, a, b, t,
419 a == b ? "\n" : "");
420 fflush (statusfp);
421 return 0;
425 fprintf (statusfp, "%s\n", line);
426 fflush (statusfp);
427 #ifdef HAVE_LIBREADLINE
428 rl_on_new_line ();
429 #endif
430 return 0;
433 static gpg_error_t
434 process_cmd ()
436 return pwmd_process (pwm);
439 #ifdef WITH_SSH
440 static gpg_error_t
441 get_password (char **result, pwmd_pinentry_t w, int echo)
443 char buf[LINE_MAX] = { 0 }, *p;
444 struct termios told, tnew;
445 char *key = NULL;
447 *result = NULL;
449 if (!isatty (STDIN_FILENO))
451 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
452 return GPG_ERR_ENOTTY;
455 if (!echo)
457 if (tcgetattr (STDIN_FILENO, &told) == -1)
458 return gpg_error_from_syserror ();
460 memcpy (&tnew, &told, sizeof (struct termios));
461 tnew.c_lflag &= ~(ECHO);
462 tnew.c_lflag |= ICANON | ECHONL;
464 if (tcsetattr (STDIN_FILENO, TCSANOW, &tnew) == -1)
466 int n = errno;
468 tcsetattr (STDIN_FILENO, TCSANOW, &told);
469 return gpg_error_from_errno (n);
473 switch (w)
475 case PWMD_PINENTRY_OPEN:
476 fprintf (stderr, N_("Password for %s: "), filename);
477 break;
478 case PWMD_PINENTRY_OPEN_FAILED:
479 fprintf (stderr, N_("Invalid password. Password for %s: "), filename);
480 break;
481 case PWMD_PINENTRY_SAVE:
482 fprintf (stderr, N_("New password for %s: "), filename);
483 break;
484 case PWMD_PINENTRY_SAVE_CONFIRM:
485 fprintf (stderr, N_("Confirm password: "));
486 break;
487 default:
488 break;
491 if ((p = fgets (buf, sizeof (buf), stdin)) == NULL)
493 if (!echo)
494 tcsetattr (STDIN_FILENO, TCSANOW, &told);
496 return 0;
499 if (!echo)
500 tcsetattr (STDIN_FILENO, TCSANOW, &told);
502 if (feof (stdin))
504 clearerr (stdin);
505 return GPG_ERR_CANCELED;
508 p[strlen (p) - 1] = 0;
510 if (buf[0])
512 key = pwmd_strdup_printf ("%s", p);
513 memset (&buf, 0, sizeof (buf));
515 if (!key)
516 return GPG_ERR_ENOMEM;
519 *result = key;
520 return 0;
523 static gpg_error_t
524 knownhost_cb (void *data, const char *host, const char *key, size_t len)
526 gpg_error_t rc;
527 char *buf =
528 pwmd_strdup_printf (N_
529 ("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?"),
530 (char *) data, host, host);
532 if (no_pinentry && !isatty (STDIN_FILENO))
534 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
535 pwmd_free (buf);
536 return GPG_ERR_ENOTTY;
538 else if (no_pinentry)
540 for (char *p = buf, len = 0; *p; p++, len++)
542 if (*p == '\n')
543 len = 0;
545 if (len == 78)
547 char *t = p;
549 while (!isspace (*(--p)));
550 *p = '\n';
551 p = t;
552 len = 0;
556 fprintf (stderr, "%s\n\n", buf);
557 pwmd_free (buf);
561 char *result;
563 fprintf (stderr, N_("Trust this connection [y/N]: "));
564 fflush (stderr);
565 rc = get_password (&result, PWMD_PINENTRY_CONFIRM, 1);
567 if (rc)
568 return rc;
570 if (!result || !*result || *result == 'n' || *result == 'N')
572 if (result && *result)
573 pwmd_free (result);
575 return GPG_ERR_NOT_CONFIRMED;
578 if ((*result == 'y' || *result == 'Y') && *(result + 1) == 0)
580 pwmd_free (result);
581 return 0;
584 while (1);
587 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, buf);
588 pwmd_free (buf);
590 if (rc)
591 return rc;
593 return pwmd_getpin (pwm, NULL, NULL, NULL, PWMD_PINENTRY_CONFIRM);
595 #endif
597 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
598 static pwmd_socket_t
599 is_remote_url (const char *str)
601 if (!str)
602 return PWMD_SOCKET_LOCAL;
604 #ifdef WITH_SSH
605 if (strstr (str, "ssh://") || strstr (str, "ssh4://")
606 || strstr (str, "ssh6://"))
607 return PWMD_SOCKET_SSH;
608 #endif
610 #ifdef WITH_GNUTLS
611 if (strstr (str, "tls://") || strstr (str, "tls4://")
612 || strstr (str, "tls6://"))
613 return PWMD_SOCKET_TLS;
614 #endif
616 return PWMD_SOCKET_LOCAL;
618 #endif
620 static char *
621 escape (const char *str)
623 const char *p;
624 char *buf = pwmd_malloc (ASSUAN_LINELENGTH + 1), *b = buf;
625 size_t len = 0;
627 for (p = str; *p; p++, len++)
629 if (len == ASSUAN_LINELENGTH)
630 break;
632 if (*p == '\\')
634 switch (*++p)
636 case 't':
637 *b++ = '\t';
638 break;
639 case 'n':
640 *b++ = '\n';
641 break;
642 case 'v':
643 *b++ = '\v';
644 break;
645 case 'b':
646 *b++ = '\b';
647 break;
648 case 'f':
649 *b++ = '\f';
650 break;
651 case 'r':
652 *b++ = '\r';
653 break;
654 default:
655 *b++ = *p;
656 break;
659 if (!*p)
660 break;
662 continue;
665 *b++ = *p;
668 *b = 0;
669 return buf;
672 static void
673 free_inquire (struct inquire_s *inq)
675 if (!inq)
676 return;
678 pwmd_free (inq->line);
680 if (inq->fd != -1 && inq->fd != STDIN_FILENO)
681 close (inq->fd);
683 pwmd_free (inq->last_keyword);
684 pwmd_free (inq);
687 /* When *result is not NULL it is updated to the new values and not
688 * reallocated. */
689 static gpg_error_t
690 set_inquire (int fd, const char *line, struct inquire_s **result)
692 struct inquire_s inq = { 0 };
693 struct stat st = { 0 };
694 gpg_error_t rc;
696 if (fd != -1)
698 if (fstat (fd, &st) == -1)
699 return gpg_error_from_syserror ();
701 inq.size = st.st_size;
704 inq.fd = fd;
705 inq.line = pwmd_calloc (1, ASSUAN_LINELENGTH);
706 if (!inq.line)
707 return GPG_ERR_ENOMEM;
709 if (line)
711 char *s = escape (line);
713 if (!s)
715 pwmd_free (inq.line);
716 return GPG_ERR_ENOMEM;
719 if (strlen (s) >= ASSUAN_LINELENGTH)
721 pwmd_free (inq.line);
722 pwmd_free (s);
723 return GPG_ERR_LINE_TOO_LONG;
726 strncpy (inq.line, s, ASSUAN_LINELENGTH - 1);
727 inq.len = strlen (s);
728 pwmd_free (s);
731 rc = pwmd_setopt (pwm, PWMD_OPTION_INQUIRE_TOTAL,
732 st.st_size ? st.st_size + strlen (inq.line) : 0);
733 if (rc)
735 pwmd_free (inq.line);
736 return rc;
739 if (*result == NULL)
740 *result = pwmd_malloc (sizeof (struct inquire_s));
741 else
743 if ((*result)->fd != -1 && (*result)->fd != STDIN_FILENO)
744 close ((*result)->fd);
746 pwmd_free ((*result)->line);
747 (*result)->line = NULL;
748 (*result)->fd = -1;
749 (*result)->len = 0;
752 memcpy (*result, &inq, sizeof (struct inquire_s));
753 memset (&inq, 0, sizeof (struct inquire_s));
754 return rc;
757 #ifdef HAVE_LIBREADLINE
758 static int
759 interactive_hook (void)
761 interactive_error = process_cmd ();
763 if (interactive_error)
764 rl_event_hook = NULL;
766 return 0;
769 static void
770 print_help ()
772 fprintf (stderr,
774 ("------------------------------------------------------------------------------\n"
775 "Elements are TAB delimited. Press CTRL-V then TAB to insert from the prompt.\n"
776 "\n"
777 "Type HELP for protocol commands. Type .help for pwmc commands. Press CTRL-D\n"
778 "to quit.\n"
779 "------------------------------------------------------------------------------\n"));
781 #endif
783 static char *
784 parse_arg (const char *src, char *dst, size_t len)
786 char *p = dst;
787 const char *s = src;
788 size_t n = 0;
790 for (; s && *s && *s != ' ' && n < len; s++, n++)
791 *p++ = *s;
793 *p = 0;
794 return dst;
797 static char *
798 parse_opt (char **line, const char *opt, gpg_error_t * rc)
800 static char result[ASSUAN_LINELENGTH] = { 0 }, *r = result;
801 char *s = strstr (*line, opt);
803 *rc = 0;
804 result[0] = 0;
805 r = result;
807 if (s)
809 size_t len = 0;
810 int quote = 0;
811 size_t rlen = strlen (opt);
812 char *p = s + rlen;
813 int lastc = 0;
815 while (*p && *p == ' ')
817 rlen++;
818 p++;
821 for (; *p && len < sizeof (result) - 1; p++, rlen++)
823 if (isspace (*p) && !quote)
824 break;
826 if (*p == '\"' && lastc != '\\')
828 quote = !quote;
829 lastc = *p;
830 continue;
833 *r++ = lastc = *p;
834 len++;
837 *r = 0;
839 if (len >= sizeof (result) - 1)
840 *rc = GPG_ERR_LINE_TOO_LONG;
841 else
843 p = s + rlen;
845 while (*p && *p == ' ')
846 p++;
848 *line = p;
852 return result;
855 static gpg_error_t
856 read_command (const char *line, char **result, size_t * len)
858 int fd;
859 gpg_error_t rc = 0;
860 char *filename = NULL;
861 struct inquire_s *inq = NULL;
862 char *p = (char *) line;
863 const char *prefix = parse_opt (&p, "--prefix", &rc);
864 char filebuf[ASSUAN_LINELENGTH];
866 if (rc)
867 return rc;
869 rc = GPG_ERR_SYNTAX;
871 if (p && *p)
873 while (*p && isspace (*p))
874 p++;
876 filename = parse_arg (p, filebuf, sizeof (filebuf));
877 if (filename && *filename)
879 p += strlen (filename) + 1;
881 while (*p && isspace (*p))
882 p++;
884 if (*p)
885 rc = 0;
889 if (rc)
891 fprintf (stderr,
893 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
894 fprintf (stderr,
896 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\" = \")\n"));
897 return rc;
900 fd = open (filename, O_RDONLY);
901 if (fd == -1)
902 return gpg_error_from_syserror ();
904 rc = set_inquire (fd, prefix && *prefix ? prefix : NULL, &inq);
905 if (rc)
907 close (fd);
908 return rc;
911 rc = pwmd_command (pwm, result, len, inquire_cb, inq, "%s", p);
912 free_inquire (inq);
913 return rc;
916 static gpg_error_t
917 redir_command (const char *line)
919 const char *p = line;
920 int fd;
921 gpg_error_t rc = GPG_ERR_SYNTAX;
922 char *filename = NULL;
923 struct inquire_s *inq = NULL;
924 char *result = NULL;
925 size_t len = 0;
926 char filebuf[ASSUAN_LINELENGTH];
928 if (p && *p && *++p)
930 filename = parse_arg (p, filebuf, sizeof (filebuf));
931 if (filename && *filename)
933 p += strlen (filename) + 1;
935 while (*p && isspace (*p))
936 p++;
938 if (*p)
939 rc = 0;
943 if (rc)
945 fprintf (stderr, N_("Usage: .redir <filename> <command> [args]\n"));
946 return rc;
949 fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
950 if (fd == -1)
951 return gpg_error_from_syserror ();
953 #ifdef HAVE_LIBREADLINE
954 rc = set_inquire (interactive ? STDIN_FILENO : inquirefd, NULL, &inq);
955 #else
956 rc = set_inquire (inquirefd, NULL, &inq);
957 #endif
958 if (rc)
960 close (fd);
961 return rc;
964 rc = parse_dotcommand (p, &result, &len, inq);
965 if (!rc && result && len--)
966 { // null byte which is always appended
967 if (write (fd, result, len) != len)
968 rc = GPG_ERR_TOO_SHORT;
969 pwmd_free (result);
972 free_inquire (inq);
973 close (fd);
974 return rc;
977 static gpg_error_t
978 help_command (const char *line)
980 fprintf (stderr,
981 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
982 " .redir <filename> <command>\n"
983 " redirect the output of a command to the specified file\n"
984 "\n"
985 " .open <filename>\n"
986 " open the specified filename losing any changes to the current one\n"
987 "\n"
988 " .read [--prefix <string>] <filename> <command> [args]\n"
989 " obtain data from the specified filename for an inquire command\n"
990 "\n"
991 " .set help | <name> [<value>]\n"
992 " set option <name> to <value>\n"
993 "\n"
994 " .save [args]\n"
995 " write changes of the file to disk\n"
996 "\n"
997 " .passwd [args]\n"
998 " change the passphrase of a data file\n"
999 "\n"
1000 " .help\n"
1001 " this help text\n"));
1002 return 0;
1005 static gpg_error_t
1006 open_command (const char *line)
1008 struct inquire_s *inq = NULL;
1009 const char *filename = line;
1010 gpg_error_t rc;
1012 while (filename && isspace (*filename))
1013 filename++;
1015 if (!filename || !*filename)
1017 fprintf (stderr, N_("Usage: .open <filename>\n"));
1018 return GPG_ERR_SYNTAX;
1021 #ifdef HAVE_LIBREADLINE
1022 if (interactive || !quiet)
1023 #else
1024 if (!quiet)
1025 #endif
1026 fprintf (stderr, N_("Opening data file \"%s\" ...\n"), filename);
1028 #ifdef HAVE_LIBREADLINE
1029 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1030 #else
1031 rc = set_inquire (-1, NULL, &inq);
1032 #endif
1033 if (rc)
1034 return rc;
1036 if (keyfile)
1038 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1039 if (!rc)
1040 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 1);
1042 else
1044 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1045 if (!rc)
1046 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1049 if (!rc)
1050 rc = pwmd_open (pwm, filename, inquire_cb, inq);
1052 reset_keyfiles ();
1053 free_inquire (inq);
1054 return rc;
1057 static gpg_error_t
1058 set_command (const char *line)
1060 gpg_error_t rc = 0;
1061 char name[256] = { 0 };
1062 char value[512] = { 0 };
1063 char *namep;
1064 char *valuep;
1065 const char *p = line;
1067 while (p && *p && isspace (*p))
1068 p++;
1070 namep = parse_arg (p, name, sizeof (name));
1071 if (!namep || !*namep)
1073 fprintf (stderr, N_("Usage: .set help | <name> [<value>]\n"));
1074 return GPG_ERR_SYNTAX;
1077 p += strlen (namep);
1078 while (p && *p && isspace (*p))
1079 p++;
1081 valuep = parse_arg (p, value, sizeof (value));
1083 if (!strcmp (name, "keyfile") || !strcmp (name, "new-keyfile"))
1085 int is_newkeyfile = 1;
1087 if (!strcmp (name, "keyfile"))
1088 is_newkeyfile = 0;
1090 if (is_newkeyfile)
1092 pwmd_free (new_keyfile);
1093 new_keyfile = NULL;
1095 else
1097 pwmd_free (keyfile);
1098 keyfile = NULL;
1101 p += strlen (valuep);
1102 while (p && *p && isspace (*p))
1103 p++;
1105 valuep = (char *) p;
1106 if (!rc && *valuep)
1108 if (is_newkeyfile)
1109 new_keyfile = pwmd_strdup (value);
1110 else
1111 keyfile = pwmd_strdup (value);
1113 if (!rc)
1115 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 1);
1116 if (!rc)
1117 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1120 else if (!local_pin && !no_pinentry)
1122 pwmd_socket_t t;
1124 pwmd_socket_type (pwm, &t);
1125 if (t == PWMD_SOCKET_LOCAL)
1127 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 0);
1128 if (!rc)
1129 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1133 else if (!strcmp(name, "pinentry-timeout"))
1135 char *e = NULL;
1136 int n = strtol(valuep, &e, 10);
1138 if (e && *e)
1139 return gpg_error (GPG_ERR_INV_VALUE);
1141 if (!*valuep)
1142 n = DEFAULT_PIN_TIMEOUT;
1144 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, n);
1146 else if (!strcmp (name, "help"))
1148 fprintf (stderr,
1150 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1151 "delimited. When no value is specified the option is unset.\n\n"
1152 "keyfile <datafile> [<filename>]\n"
1153 " set or unset the keyfile to be used when a passphrase is required (*)\n"
1154 "\n"
1155 "new-keyfile <datafile> [<filename>]\n"
1156 " set or unset the keyfile to be used when a new passphrase is required (*)\n"
1157 "\n"
1158 "pinentry-timeout <seconds>\n"
1159 " the amount of seconds before pinentry gives up waiting for input\n"
1160 "\n"
1161 "* = the next protocol command will unset this value\n"
1164 else
1165 rc = GPG_ERR_UNKNOWN_OPTION;
1167 return rc;
1170 static gpg_error_t
1171 save_command (const char *line)
1173 struct inquire_s *inq = NULL;
1174 gpg_error_t rc;
1176 #ifdef HAVE_LIBREADLINE
1177 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1178 #else
1179 rc = set_inquire (-1, NULL, &inq);
1180 #endif
1181 if (rc)
1182 return rc;
1184 if (new_keyfile || keyfile)
1186 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1187 if (!rc)
1188 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 1);
1190 else
1192 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1193 if (!rc)
1194 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1197 if (!rc)
1198 rc = pwmd_save (pwm, line, inquire_cb, inq);
1200 reset_keyfiles ();
1201 free_inquire (inq);
1202 return rc;
1205 static gpg_error_t
1206 do_save_passwd_command (const char *line, int save)
1208 struct inquire_s *inq = NULL;
1209 gpg_error_t rc;
1211 #ifdef HAVE_LIBREADLINE
1212 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1213 #else
1214 rc = set_inquire (-1, NULL, &inq);
1215 #endif
1216 if (rc)
1217 return rc;
1219 if (new_keyfile || keyfile)
1221 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1222 if (!rc)
1223 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 1);
1225 else
1227 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1228 if (!rc)
1229 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1232 if (!rc)
1234 if (save)
1235 rc = pwmd_save (pwm, line, inquire_cb, inq);
1236 else
1237 rc = pwmd_passwd (pwm, line, inquire_cb, inq);
1240 reset_keyfiles ();
1241 free_inquire (inq);
1242 return rc;
1245 static gpg_error_t
1246 parse_dotcommand (const char *line, char **result,
1247 size_t * len, struct inquire_s *inq)
1249 const char *p = line;
1250 gpg_error_t rc = 0;
1252 if (!strncmp (p, ".read", 5))
1253 rc = read_command (p + 5, result, len);
1254 else if (!strncmp (p, ".redir", 6))
1255 rc = redir_command (p + 6);
1256 else if (!strncmp (p, ".help", 5))
1257 rc = help_command (p + 5);
1258 else if (!strncmp (p, ".open", 5))
1259 rc = open_command (p + 5);
1260 else if (!strncmp (p, ".set", 4))
1261 rc = set_command (p + 4);
1262 else if (!strncmp (p, ".save", 5))
1263 rc = do_save_passwd_command (p + 5, 1);
1264 else if (!strncmp (p, ".passwd", 7))
1265 rc = do_save_passwd_command (p + 7, 0);
1266 else
1268 rc = pwmd_command (pwm, result, len, inquire_cb, inq, "%s", line);
1269 #ifdef HAVE_LIBREADLINE
1270 if (interactive)
1272 #endif
1273 reset_keyfiles ();
1274 #ifdef HAVE_LIBREADLINE
1276 #endif
1279 return FINISH (rc);
1282 #ifdef HAVE_LIBREADLINE
1283 static gpg_error_t
1284 do_interactive ()
1286 gpg_error_t rc;
1287 struct inquire_s *inq = NULL;
1289 rl_initialize ();
1290 rc = process_cmd ();
1291 if (rc)
1292 return rc;
1294 rc = set_inquire (STDIN_FILENO, NULL, &inq);
1295 if (rc)
1296 return rc;
1298 fprintf (stderr,
1299 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1300 print_help ();
1301 rl_event_hook = &interactive_hook;
1302 rl_set_keyboard_input_timeout (100000);
1304 for (;;)
1306 char *line;
1307 char *result = NULL;
1308 size_t len;
1310 rc = 0;
1311 line = readline ("pwm> ");
1312 if (interactive_error)
1314 free (line);
1315 rc = interactive_error;
1316 break;
1319 if (!line)
1321 rc = finalize ();
1322 if (!rc)
1323 break;
1325 if (gpg_err_code (rc) != GPG_ERR_CANCELED &&
1326 gpg_err_code (rc) != GPG_ERR_EOF)
1327 fprintf (stderr, "ERR %i: %s\n", rc, gpg_strerror (rc));
1329 continue;
1331 else if (!*line)
1333 free (line);
1334 continue;
1337 #ifdef HAVE_READLINE_HISTORY
1338 add_history (line);
1339 #endif
1340 rc = parse_dotcommand (line, &result, &len, inq);
1341 free (line);
1342 if (rc)
1344 char *tmp = NULL;
1346 if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
1347 (void) pwmd_command (pwm, &tmp, NULL, NULL, NULL,
1348 "GETINFO last_error");
1350 show_error (pwm, rc, tmp);
1351 pwmd_free (tmp);
1353 else if (result && len)
1354 printf ("%s%s", result, result[len - 1] != '\n' ? "\n" : "");
1356 pwmd_free (result);
1359 free_inquire (inq);
1360 return rc;
1362 #endif
1364 static gpg_error_t
1365 finalize ()
1367 gpg_error_t rc = 0;
1368 #ifdef HAVE_LIBREADLINE
1369 int quit = 0;
1371 if (interactive)
1373 int finished = 0;
1375 fprintf (stderr, "\n");
1379 char *p, buf[16];
1381 fprintf (stderr,
1383 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1384 p = fgets (buf, sizeof (buf), stdin);
1386 if (feof (stdin))
1388 clearerr (stdin);
1389 return GPG_ERR_EOF;
1392 switch (*p)
1394 case 'h':
1395 print_help ();
1396 break;
1397 case 'c':
1398 return GPG_ERR_CANCELED;
1399 case 'Q':
1400 return 0;
1401 case 'f':
1402 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1403 "CLEARCACHE %s", filename);
1404 if (rc)
1405 return rc;
1407 interactive_hook ();
1408 break;
1409 case 'S':
1410 quit = 1;
1411 case 's':
1412 save = 1;
1413 finished = 1;
1414 break;
1415 default:
1416 break;
1419 while (!finished);
1421 #endif
1423 if (save && !filename)
1425 fprintf (stderr,
1427 ("No filename was specified on the command line. Aborting.\n"));
1428 return GPG_ERR_CANCELED;
1431 if (save && filename)
1433 char *args =
1434 pwmd_strdup_printf ("%s%s %s%s %s",
1435 keyid ? "--keyid=" : "",
1436 keyid ? keyid : "",
1437 sign_keyid ? "--sign-keyid=" : "",
1438 sign_keyid ? sign_keyid : "",
1439 keyparams ? "--inquire-keyparam" : "");
1441 #ifdef HAVE_LIBREADLINE
1442 if (!quiet || interactive)
1444 #else
1445 if (!quiet)
1447 #endif
1448 fprintf (stderr, "\n");
1449 fprintf (stderr, N_("Saving changes ...\n"));
1452 rc = save_command (args);
1453 pwmd_free (args);
1456 #ifdef HAVE_LIBREADLINE
1457 if (interactive)
1458 return rc ? rc : quit ? 0 : GPG_ERR_CANCELED;
1459 #endif
1461 return rc;
1464 static void
1465 parse_status_ignore (char *str)
1467 size_t n = 0;
1468 char **p, *s;
1470 for (p = status_ignore; p && *p; p++)
1471 pwmd_free (*p);
1473 pwmd_free (status_ignore);
1474 status_ignore = NULL;
1475 if (!str || !*str)
1476 return;
1478 while ((s = strsep (&str, ",")))
1480 p = pwmd_realloc (status_ignore, (n + 2) * sizeof (char *));
1481 p[n++] = pwmd_strdup (s);
1482 p[n] = NULL;
1483 status_ignore = p;
1488 main (int argc, char *argv[])
1490 int connected = 0;
1491 gpg_error_t rc;
1492 int opt;
1493 char command[ASSUAN_LINELENGTH], *p = NULL;
1494 char *result = NULL;
1495 size_t len = 0;
1496 char *pinentry_path = NULL;
1497 char *display = NULL, *tty = NULL, *ttytype = NULL;
1498 char *lcctype = NULL, *lcmessages = NULL;
1499 int outfd = STDOUT_FILENO;
1500 FILE *outfp = stdout;
1501 FILE *inquirefp = stdin;
1502 int show_status = 1;
1503 char *clientname = "pwmc";
1504 char *inquire = NULL;
1505 char *inquire_line = NULL;
1506 int timeout = 0;
1507 #ifdef WITH_SSH
1508 int use_ssh_agent = 1;
1509 char *knownhosts = NULL;
1510 char *identity = NULL;
1511 #endif
1512 #ifdef WITH_GNUTLS
1513 char *cacert = NULL;
1514 char *clientcert = NULL;
1515 char *clientkey = NULL;
1516 char *prio = NULL;
1517 int tls_verify = 0;
1518 char *tls_fingerprint = NULL;
1519 #endif
1520 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1521 pwmd_socket_t socktype;
1522 long socket_timeout = 300;
1523 int connect_timeout = 120;
1524 #endif
1525 int lock_on_open = 1;
1526 long lock_timeout = 50;
1527 char *url = NULL;
1528 char *tmp = NULL;
1529 /* The order is important. */
1530 enum
1532 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1533 OPT_SOCKET_TIMEOUT, OPT_CONNECT_TIMEOUT,
1534 #endif
1535 #ifdef WITH_SSH
1536 OPT_USE_SSH_AGENT, OPT_IDENTITY, OPT_KNOWNHOSTS,
1537 #endif
1538 #ifdef WITH_GNUTLS
1539 OPT_CACERT, OPT_CLIENTCERT, OPT_CLIENTKEY, OPT_PRIORITY, OPT_VERIFY,
1540 OPT_SERVER_FP,
1541 #endif
1542 OPT_URL, OPT_LOCAL, OPT_TTYNAME, OPT_TTYTYPE,
1543 OPT_DISPLAY, OPT_LC_CTYPE, OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES,
1544 OPT_PINENTRY, OPT_KEYFILE, OPT_NEW_KEYFILE, OPT_NOLOCK,
1545 OPT_LOCK_TIMEOUT, OPT_SAVE, OPT_OUTPUT_FD, OPT_INQUIRE,
1546 OPT_INQUIRE_FD, OPT_INQUIRE_FILE, OPT_INQUIRE_LINE, OPT_NO_STATUS,
1547 OPT_STATUS_IGNORE,
1548 OPT_STATUSFD, OPT_NAME, OPT_VERSION, OPT_HELP, OPT_KEYID, OPT_SIGN_KEYID,
1549 OPT_KEYPARAMS, OPT_NO_PINENTRY, OPT_QUIET,
1550 #ifdef HAVE_LIBREADLINE
1551 OPT_INTERACTIVE,
1552 #endif
1554 const struct option long_opts[] = {
1555 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1556 {"socket-timeout", 1, 0, 0},
1557 {"connect-timeout", 1, 0, 0},
1558 #endif
1560 #ifdef WITH_SSH
1561 {"no-ssh-agent", 0, 0, 0},
1562 {"identity", 1, 0, 'i'},
1563 {"knownhosts", 1, 0, 'k'},
1564 #endif
1565 #ifdef WITH_GNUTLS
1566 {"ca-cert", 1, 0, 0},
1567 {"client-cert", 1, 0, 0},
1568 {"client-key", 1, 0, 0},
1569 {"tls-priority", 1, 0, 0},
1570 {"tls-verify", 0, 0, 0},
1571 {"tls-fingerprint", 1, 0, 0},
1572 #endif
1573 {"url", 1, 0, 0},
1574 {"local-pinentry", 0, 0},
1575 {"ttyname", 1, 0, 'y'},
1576 {"ttytype", 1, 0, 't'},
1577 {"display", 1, 0, 'd'},
1578 {"lc-ctype", 1, 0, 0},
1579 {"lc-messages", 1, 0, 0},
1580 {"timeout", 1, 0, 0},
1581 {"tries", 1, 0, 0},
1582 {"pinentry", 1, 0, 0},
1583 {"key-file", 1, 0, 0},
1584 {"new-key-file", 1, 0, 0},
1585 {"no-lock", 0, 0, 0},
1586 {"lock-timeout", 1, 0, 0},
1587 {"save", 0, 0, 'S'},
1588 {"output-fd", 1, 0, 0},
1589 {"inquire", 1, 0, 0},
1590 {"inquire-fd", 1, 0, 0},
1591 {"inquire-file", 1, 0, 0},
1592 {"inquire-line", 1, 0, 'L'},
1593 {"no-status", 0, 0, 0},
1594 {"status-ignore", 1, 0, 0},
1595 {"status-fd", 1, 0, 0},
1596 {"name", 1, 0, 'n'},
1597 {"version", 0, 0, 0},
1598 {"help", 0, 0, 0},
1599 {"keyid", 1, 0, 0},
1600 {"sign-keyid", 1, 0, 0},
1601 {"key-params", 1, 0, 0},
1602 {"no-pinentry", 0, 0, 0},
1603 {"quiet", 0, 0, 0},
1604 #ifdef HAVE_LIBREADLINE
1605 {"interactive", 0, 0},
1606 #endif
1607 {0, 0, 0, 0}
1609 #ifdef WITH_SSH
1610 const char *optstring = "L:y:t:d:P:I:Sn:i:k:";
1611 #else
1612 const char *optstring = "L:y:t:d:P:I:Sn:";
1613 #endif
1614 int opt_index = 0;
1616 #ifdef ENABLE_NLS
1617 setlocale (LC_ALL, "");
1618 bindtextdomain ("libpwmd", LOCALEDIR);
1619 #endif
1621 tries = DEFAULT_PIN_TRIES;
1622 inquirefd = STDIN_FILENO;
1623 statusfd = STDERR_FILENO;
1624 statusfp = fdopen (statusfd, "w");
1625 tmp = pwmd_strdup (DEFAULT_STATUS_IGNORE);
1626 parse_status_ignore (tmp);
1627 pwmd_free (tmp);
1629 while ((opt =
1630 getopt_long (argc, argv, optstring, long_opts, &opt_index)) != -1)
1632 switch (opt)
1634 /* Handle long options without a short option part. */
1635 case 0:
1636 switch (opt_index)
1638 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1639 case OPT_SOCKET_TIMEOUT:
1640 socket_timeout = strtol (optarg, &p, 10);
1641 break;
1642 case OPT_CONNECT_TIMEOUT:
1643 connect_timeout = strtol (optarg, &p, 10);
1644 break;
1645 #endif
1646 #ifdef WITH_SSH
1647 case OPT_USE_SSH_AGENT:
1648 use_ssh_agent = 0;
1649 break;
1650 #endif
1651 #ifdef WITH_GNUTLS
1652 case OPT_CACERT:
1653 cacert = optarg;
1654 break;
1655 case OPT_CLIENTCERT:
1656 clientcert = optarg;
1657 break;
1658 case OPT_CLIENTKEY:
1659 clientkey = optarg;
1660 break;
1661 case OPT_PRIORITY:
1662 prio = optarg;
1663 break;
1664 case OPT_VERIFY:
1665 tls_verify = 1;
1666 break;
1667 case OPT_SERVER_FP:
1668 tls_fingerprint = optarg;
1669 break;
1670 #endif
1671 case OPT_KEYPARAMS:
1672 keyparams = optarg;
1673 break;
1674 case OPT_KEYFILE:
1675 keyfile = pwmd_strdup (optarg);
1676 break;
1677 case OPT_NEW_KEYFILE:
1678 new_keyfile = pwmd_strdup (optarg);
1679 break;
1680 case OPT_NOLOCK:
1681 lock_on_open = 0;
1682 break;
1683 case OPT_LOCK_TIMEOUT:
1684 lock_timeout = strtol (optarg, &p, 10);
1685 break;
1686 case OPT_URL:
1687 url = optarg;
1688 break;
1689 case OPT_LOCAL:
1690 local_pin = 1;
1691 break;
1692 case OPT_LC_CTYPE:
1693 lcctype = pwmd_strdup (optarg);
1694 break;
1695 case OPT_LC_MESSAGES:
1696 lcmessages = pwmd_strdup (optarg);
1697 break;
1698 case OPT_TIMEOUT:
1699 timeout = strtol (optarg, &p, 10);
1700 break;
1701 case OPT_TRIES:
1702 tries = strtol (optarg, &p, 10);
1703 break;
1704 case OPT_INQUIRE:
1705 inquire = escape (optarg);
1706 break;
1707 case OPT_INQUIRE_FD:
1708 inquirefd = strtol (optarg, &p, 10);
1709 if (!p)
1711 inquirefp = fdopen (inquirefd, "r");
1712 if (!inquirefp)
1713 err (EXIT_FAILURE, "%i", inquirefd);
1715 break;
1716 case OPT_INQUIRE_FILE:
1717 inquirefd = open (optarg, O_RDONLY);
1718 if (inquirefd == -1)
1719 err (EXIT_FAILURE, "%s", optarg);
1720 inquirefp = fdopen (inquirefd, "r");
1721 break;
1722 case OPT_OUTPUT_FD:
1723 outfd = strtol (optarg, &p, 10);
1724 if (!p || !*p)
1726 outfp = fdopen (outfd, "w");
1727 if (!outfp)
1728 err (EXIT_FAILURE, "%i", outfd);
1730 break;
1731 case OPT_NO_STATUS:
1732 show_status = 0;
1733 break;
1734 case OPT_STATUSFD:
1735 statusfd = strtol (optarg, &p, 10);
1736 if (!p || !*p)
1738 statusfp = fdopen (statusfd, "w");
1739 if (!statusfp)
1740 err (EXIT_FAILURE, "%i", statusfd);
1742 break;
1743 case OPT_STATUS_IGNORE:
1744 parse_status_ignore (optarg);
1745 break;
1746 case OPT_VERSION:
1747 printf ("%s (pwmc)\n\n"
1748 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015\n"
1749 "%s\n"
1750 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1751 "Compile-time features:\n"
1752 #ifdef HAVE_LIBREADLINE
1753 "+INTERACTIVE "
1754 #else
1755 "-INTERACTIVE "
1756 #endif
1757 #ifdef WITH_SSH
1758 "+SSH "
1759 #else
1760 "-SSH "
1761 #endif
1762 #ifdef WITH_GNUTLS
1763 "+GNUTLS "
1764 #else
1765 "-GNUTLS "
1766 #endif
1767 #ifdef WITH_PINENTRY
1768 "+PINENTRY "
1769 #else
1770 "-PINENTRY "
1771 #endif
1772 #ifdef WITH_QUALITY
1773 "+CRACK "
1774 #else
1775 "-CRACK "
1776 #endif
1777 #ifdef MEM_DEBUG
1778 "+MEM_DEBUG "
1779 #else
1780 "-MEM_DEBUG "
1781 #endif
1782 "\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1783 exit (EXIT_SUCCESS);
1784 case OPT_PINENTRY:
1785 pinentry_path = optarg;
1786 break;
1787 case OPT_HELP:
1788 usage (argv[0], EXIT_SUCCESS);
1789 case OPT_KEYID:
1790 keyid = optarg;
1791 break;
1792 case OPT_SIGN_KEYID:
1793 sign_keyid = optarg;
1794 break;
1795 case OPT_QUIET:
1796 quiet = 1;
1797 show_status = 0;
1798 break;
1799 case OPT_NO_PINENTRY:
1800 no_pinentry = 1;
1801 break;
1802 #ifdef HAVE_LIBREADLINE
1803 case OPT_INTERACTIVE:
1804 interactive = 1;
1805 break;
1806 #endif
1807 default:
1808 usage (argv[0], EXIT_FAILURE);
1811 if (p && *p)
1813 fprintf (stderr, N_("%s: invalid argument for option '--%s'\n"),
1814 argv[0], long_opts[opt_index].name);
1815 usage (argv[0], EXIT_FAILURE);
1818 break;
1819 #ifdef WITH_SSH
1820 case 'i':
1821 identity = optarg;
1822 break;
1823 case 'k':
1824 knownhosts = optarg;
1825 break;
1826 #endif
1827 case 'L':
1828 inquire_line = optarg;
1829 break;
1830 case 'y':
1831 tty = optarg;
1832 break;
1833 case 't':
1834 ttytype = optarg;
1835 break;
1836 case 'd':
1837 display = optarg;
1838 break;
1839 case 'S':
1840 save = 1;
1841 break;
1842 case 'n':
1843 clientname = optarg;
1844 break;
1845 default:
1846 usage (argv[0], EXIT_FAILURE);
1850 #ifdef HAVE_LIBREADLINE
1851 if (interactive && !isatty (STDIN_FILENO))
1852 usage (argv[0], EXIT_FAILURE);
1853 else if (isatty (STDIN_FILENO) && !inquire && !inquire_line)
1854 interactive = 1;
1855 #endif
1857 filename = argv[optind];
1858 #ifdef WITH_GNUTLS
1859 gnutls_global_set_mem_functions (pwmd_malloc, pwmd_malloc, NULL,
1860 pwmd_realloc, pwmd_free);
1861 #endif
1862 pwmd_init ();
1863 rc = pwmd_new (clientname, &pwm);
1864 if (rc)
1865 goto done;
1867 pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
1868 if (!quiet)
1869 fprintf (stderr, N_("Connecting ...\n"));
1871 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1872 socktype = is_remote_url (url);
1873 if (socktype != PWMD_SOCKET_LOCAL)
1875 local_pin = 1;
1876 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1877 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, connect_timeout);
1878 if (rc)
1879 goto done;
1880 #endif
1882 if (socktype == PWMD_SOCKET_SSH)
1884 #ifdef WITH_SSH
1885 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_CB, knownhost_cb);
1886 if (rc)
1887 goto done;
1889 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_DATA, clientname);
1890 if (rc)
1891 goto done;
1893 if (!getenv ("SSH_AUTH_SOCK") || identity)
1894 use_ssh_agent = 0;
1896 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_AGENT, use_ssh_agent);
1897 if (rc)
1898 goto done;
1900 rc = pwmd_connect (pwm, url, identity, knownhosts);
1901 #endif
1903 #ifdef WITH_GNUTLS
1904 else
1906 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_VERIFY, tls_verify);
1907 if (rc)
1908 goto done;
1910 rc = pwmd_connect (pwm, url, clientcert, clientkey, cacert, prio,
1911 tls_fingerprint);
1913 #endif
1915 else
1916 rc = pwmd_connect (pwm, url);
1917 #else
1918 rc = pwmd_connect (pwm, url);
1919 #endif
1920 if (rc)
1921 goto done;
1923 if (!quiet)
1924 fprintf (stderr, N_("Connected.\n"));
1926 connected = 1;
1927 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1928 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, socket_timeout);
1929 if (rc)
1930 goto done;
1931 #endif
1933 if (lock_timeout)
1935 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1936 "OPTION LOCK-TIMEOUT=%li", lock_timeout);
1937 if (rc)
1938 goto done;
1941 if (lock_on_open)
1943 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCK_ON_OPEN, 1);
1944 if (rc)
1945 goto done;
1948 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, NULL, NULL);
1949 if (rc)
1950 goto done;
1952 if (timeout > 0)
1954 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
1955 if (rc)
1956 goto done;
1959 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1960 if (rc)
1961 goto done;
1963 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY,
1964 (local_pin || keyfile || new_keyfile));
1965 if (rc)
1966 goto done;
1968 if (pinentry_path)
1970 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
1971 if (rc)
1972 goto done;
1975 if (display)
1977 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
1978 if (rc)
1979 goto done;
1982 if (tty)
1984 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, tty);
1985 if (rc)
1986 goto done;
1989 if (ttytype)
1991 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
1992 if (rc)
1993 goto done;
1996 if (lcctype)
1998 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
1999 if (rc)
2000 goto done;
2003 if (lcmessages)
2005 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES, lcmessages);
2006 if (rc)
2007 goto done;
2010 if (show_status)
2012 rc = pwmd_setopt (pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
2013 if (rc)
2014 goto done;
2017 if (filename)
2019 rc = open_command (filename);
2020 if (rc)
2021 goto done;
2024 #ifdef HAVE_LIBREADLINE
2025 if (interactive)
2027 rc = do_interactive ();
2028 result = NULL;
2029 goto do_exit;
2031 #endif
2033 if (inquire)
2035 struct inquire_s *inq = NULL;
2037 rc = set_inquire (inquirefd, inquire_line, &inq);
2038 if (!rc)
2039 rc = pwmd_command (pwm, &result, &len, inquire_cb, inq, "%s", inquire);
2041 free_inquire (inq);
2042 goto done;
2045 if (fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1)
2047 rc = gpg_error_from_errno (errno);
2048 goto done;
2051 ssize_t n;
2053 for (;;)
2055 rc = process_cmd ();
2057 if (rc)
2058 goto done;
2060 n = read (STDIN_FILENO, command, sizeof (command)-1);
2061 if (n == -1)
2063 if (errno == EAGAIN)
2065 usleep (100000);
2066 continue;
2069 rc = gpg_error_from_errno (errno);
2070 goto done;
2072 else if (!n)
2073 goto done;
2075 p = command;
2076 command[n] = 0;
2077 break;
2080 if (!p || !*p || !strcasecmp (p, "BYE"))
2081 goto done;
2084 struct inquire_s *inq = NULL;
2085 rc = set_inquire (inquirefd, inquire_line, &inq);
2086 if (!rc)
2088 rc = parse_dotcommand (command, &result, &len, inq);
2089 free_inquire (inq);
2092 if (rc)
2093 goto done;
2095 done:
2096 if (result)
2098 fwrite (result, 1, result[len - 1] == 0 ? len - 1 : len, outfp);
2099 fflush (outfp);
2100 pwmd_free (result);
2103 result = NULL;
2104 if (!rc)
2105 rc = finalize ();
2106 else if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
2107 (void) pwmd_command (pwm, &result, NULL, NULL, NULL,
2108 "GETINFO last_error");
2110 #ifdef HAVE_LIBREADLINE
2111 do_exit:
2112 #endif
2113 memset (command, 0, sizeof (command));
2115 if (rc && !quiet)
2116 show_error (pwm, rc, result);
2118 pwmd_close (pwm);
2119 reset_keyfiles ();
2120 pwmd_deinit ();
2121 pwmd_free (result);
2122 parse_status_ignore (NULL);
2123 if (connected && !quiet)
2124 fprintf (stderr, N_("Connection closed.\n"));
2126 exit (rc ? EXIT_FAILURE : EXIT_SUCCESS);