pwmc: change the "keyfile" and "new-keyfile" parameters.
[libpwmd.git] / src / pwmc.c
blob88f5a3603c281224391c1465e70ca926ab9b5d05
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 if (!rc && *valuep)
1103 if (is_newkeyfile)
1104 new_keyfile = pwmd_strdup (value);
1105 else
1106 keyfile = pwmd_strdup (value);
1108 if (!rc)
1110 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 1);
1111 if (!rc)
1112 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1115 else if (!local_pin && !no_pinentry)
1117 pwmd_socket_t t;
1119 pwmd_socket_type (pwm, &t);
1120 if (t == PWMD_SOCKET_LOCAL)
1122 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 0);
1123 if (!rc)
1124 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1128 else if (!strcmp(name, "pinentry-timeout"))
1130 char *e = NULL;
1131 int n = strtol(valuep, &e, 10);
1133 if (e && *e)
1134 return gpg_error (GPG_ERR_INV_VALUE);
1136 if (!*valuep)
1137 n = DEFAULT_PIN_TIMEOUT;
1139 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, n);
1141 else if (!strcmp (name, "help"))
1143 fprintf (stderr,
1145 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1146 "delimited. When no value is specified the option is unset.\n\n"
1147 "keyfile [<filename>]\n"
1148 " set or unset the keyfile to be used when a passphrase is required (*)\n"
1149 "\n"
1150 "new-keyfile [<filename>]\n"
1151 " set or unset the keyfile to be used when a new passphrase is required (*)\n"
1152 "\n"
1153 "pinentry-timeout <seconds>\n"
1154 " the amount of seconds before pinentry gives up waiting for input\n"
1155 "\n"
1156 "* = the next protocol command will unset this value\n"
1159 else
1160 rc = GPG_ERR_UNKNOWN_OPTION;
1162 return rc;
1165 static gpg_error_t
1166 save_command (const char *line)
1168 struct inquire_s *inq = NULL;
1169 gpg_error_t rc;
1171 #ifdef HAVE_LIBREADLINE
1172 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1173 #else
1174 rc = set_inquire (-1, NULL, &inq);
1175 #endif
1176 if (rc)
1177 return rc;
1179 if (new_keyfile || keyfile)
1181 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1182 if (!rc)
1183 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 1);
1185 else
1187 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1188 if (!rc)
1189 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1192 if (!rc)
1193 rc = pwmd_save (pwm, line, inquire_cb, inq);
1195 reset_keyfiles ();
1196 free_inquire (inq);
1197 return rc;
1200 static gpg_error_t
1201 do_save_passwd_command (const char *line, int save)
1203 struct inquire_s *inq = NULL;
1204 gpg_error_t rc;
1206 #ifdef HAVE_LIBREADLINE
1207 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1208 #else
1209 rc = set_inquire (-1, NULL, &inq);
1210 #endif
1211 if (rc)
1212 return rc;
1214 if (new_keyfile || keyfile)
1216 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1217 if (!rc)
1218 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 1);
1220 else
1222 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1223 if (!rc)
1224 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1227 if (!rc)
1229 if (save)
1230 rc = pwmd_save (pwm, line, inquire_cb, inq);
1231 else
1232 rc = pwmd_passwd (pwm, line, inquire_cb, inq);
1235 reset_keyfiles ();
1236 free_inquire (inq);
1237 return rc;
1240 static gpg_error_t
1241 parse_dotcommand (const char *line, char **result,
1242 size_t * len, struct inquire_s *inq)
1244 const char *p = line;
1245 gpg_error_t rc = 0;
1247 if (!strncmp (p, ".read", 5))
1248 rc = read_command (p + 5, result, len);
1249 else if (!strncmp (p, ".redir", 6))
1250 rc = redir_command (p + 6);
1251 else if (!strncmp (p, ".help", 5))
1252 rc = help_command (p + 5);
1253 else if (!strncmp (p, ".open", 5))
1254 rc = open_command (p + 5);
1255 else if (!strncmp (p, ".set", 4))
1256 rc = set_command (p + 4);
1257 else if (!strncmp (p, ".save", 5))
1258 rc = do_save_passwd_command (p + 5, 1);
1259 else if (!strncmp (p, ".passwd", 7))
1260 rc = do_save_passwd_command (p + 7, 0);
1261 else
1263 rc = pwmd_command (pwm, result, len, inquire_cb, inq, "%s", line);
1264 #ifdef HAVE_LIBREADLINE
1265 if (interactive)
1267 #endif
1268 reset_keyfiles ();
1269 #ifdef HAVE_LIBREADLINE
1271 #endif
1274 return FINISH (rc);
1277 #ifdef HAVE_LIBREADLINE
1278 static gpg_error_t
1279 do_interactive ()
1281 gpg_error_t rc;
1282 struct inquire_s *inq = NULL;
1284 rl_initialize ();
1285 rc = process_cmd ();
1286 if (rc)
1287 return rc;
1289 rc = set_inquire (STDIN_FILENO, NULL, &inq);
1290 if (rc)
1291 return rc;
1293 fprintf (stderr,
1294 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1295 print_help ();
1296 rl_event_hook = &interactive_hook;
1297 rl_set_keyboard_input_timeout (100000);
1299 for (;;)
1301 char *line;
1302 char *result = NULL;
1303 size_t len;
1305 rc = 0;
1306 line = readline ("pwm> ");
1307 if (interactive_error)
1309 free (line);
1310 rc = interactive_error;
1311 break;
1314 if (!line)
1316 rc = finalize ();
1317 if (!rc)
1318 break;
1320 if (gpg_err_code (rc) != GPG_ERR_CANCELED &&
1321 gpg_err_code (rc) != GPG_ERR_EOF)
1322 fprintf (stderr, "ERR %i: %s\n", rc, gpg_strerror (rc));
1324 continue;
1326 else if (!*line)
1328 free (line);
1329 continue;
1332 #ifdef HAVE_READLINE_HISTORY
1333 add_history (line);
1334 #endif
1335 rc = parse_dotcommand (line, &result, &len, inq);
1336 free (line);
1337 if (rc)
1339 char *tmp = NULL;
1341 if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
1342 (void) pwmd_command (pwm, &tmp, NULL, NULL, NULL,
1343 "GETINFO last_error");
1345 show_error (pwm, rc, tmp);
1346 pwmd_free (tmp);
1348 else if (result && len)
1349 printf ("%s%s", result, result[len - 1] != '\n' ? "\n" : "");
1351 pwmd_free (result);
1354 free_inquire (inq);
1355 return rc;
1357 #endif
1359 static gpg_error_t
1360 finalize ()
1362 gpg_error_t rc = 0;
1363 #ifdef HAVE_LIBREADLINE
1364 int quit = 0;
1366 if (interactive)
1368 int finished = 0;
1370 fprintf (stderr, "\n");
1374 char *p, buf[16];
1376 fprintf (stderr,
1378 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1379 p = fgets (buf, sizeof (buf), stdin);
1381 if (feof (stdin))
1383 clearerr (stdin);
1384 return GPG_ERR_EOF;
1387 switch (*p)
1389 case 'h':
1390 print_help ();
1391 break;
1392 case 'c':
1393 return GPG_ERR_CANCELED;
1394 case 'Q':
1395 return 0;
1396 case 'f':
1397 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1398 "CLEARCACHE %s", filename);
1399 if (rc)
1400 return rc;
1402 interactive_hook ();
1403 break;
1404 case 'S':
1405 quit = 1;
1406 case 's':
1407 save = 1;
1408 finished = 1;
1409 break;
1410 default:
1411 break;
1414 while (!finished);
1416 #endif
1418 if (save && !filename)
1420 fprintf (stderr,
1422 ("No filename was specified on the command line. Aborting.\n"));
1423 return GPG_ERR_CANCELED;
1426 if (save && filename)
1428 char *args =
1429 pwmd_strdup_printf ("%s%s %s%s %s",
1430 keyid ? "--keyid=" : "",
1431 keyid ? keyid : "",
1432 sign_keyid ? "--sign-keyid=" : "",
1433 sign_keyid ? sign_keyid : "",
1434 keyparams ? "--inquire-keyparam" : "");
1436 #ifdef HAVE_LIBREADLINE
1437 if (!quiet || interactive)
1439 #else
1440 if (!quiet)
1442 #endif
1443 fprintf (stderr, "\n");
1444 fprintf (stderr, N_("Saving changes ...\n"));
1447 rc = save_command (args);
1448 pwmd_free (args);
1451 #ifdef HAVE_LIBREADLINE
1452 if (interactive)
1453 return rc ? rc : quit ? 0 : GPG_ERR_CANCELED;
1454 #endif
1456 return rc;
1459 static void
1460 parse_status_ignore (char *str)
1462 size_t n = 0;
1463 char **p, *s;
1465 for (p = status_ignore; p && *p; p++)
1466 pwmd_free (*p);
1468 pwmd_free (status_ignore);
1469 status_ignore = NULL;
1470 if (!str || !*str)
1471 return;
1473 while ((s = strsep (&str, ",")))
1475 p = pwmd_realloc (status_ignore, (n + 2) * sizeof (char *));
1476 p[n++] = pwmd_strdup (s);
1477 p[n] = NULL;
1478 status_ignore = p;
1483 main (int argc, char *argv[])
1485 int connected = 0;
1486 gpg_error_t rc;
1487 int opt;
1488 char command[ASSUAN_LINELENGTH], *p = NULL;
1489 char *result = NULL;
1490 size_t len = 0;
1491 char *pinentry_path = NULL;
1492 char *display = NULL, *tty = NULL, *ttytype = NULL;
1493 char *lcctype = NULL, *lcmessages = NULL;
1494 int outfd = STDOUT_FILENO;
1495 FILE *outfp = stdout;
1496 FILE *inquirefp = stdin;
1497 int show_status = 1;
1498 char *clientname = "pwmc";
1499 char *inquire = NULL;
1500 char *inquire_line = NULL;
1501 int timeout = 0;
1502 #ifdef WITH_SSH
1503 int use_ssh_agent = 1;
1504 char *knownhosts = NULL;
1505 char *identity = NULL;
1506 #endif
1507 #ifdef WITH_GNUTLS
1508 char *cacert = NULL;
1509 char *clientcert = NULL;
1510 char *clientkey = NULL;
1511 char *prio = NULL;
1512 int tls_verify = 0;
1513 char *tls_fingerprint = NULL;
1514 #endif
1515 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1516 pwmd_socket_t socktype;
1517 long socket_timeout = 300;
1518 int connect_timeout = 120;
1519 #endif
1520 int lock_on_open = 1;
1521 long lock_timeout = 50;
1522 char *url = NULL;
1523 char *tmp = NULL;
1524 /* The order is important. */
1525 enum
1527 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1528 OPT_SOCKET_TIMEOUT, OPT_CONNECT_TIMEOUT,
1529 #endif
1530 #ifdef WITH_SSH
1531 OPT_USE_SSH_AGENT, OPT_IDENTITY, OPT_KNOWNHOSTS,
1532 #endif
1533 #ifdef WITH_GNUTLS
1534 OPT_CACERT, OPT_CLIENTCERT, OPT_CLIENTKEY, OPT_PRIORITY, OPT_VERIFY,
1535 OPT_SERVER_FP,
1536 #endif
1537 OPT_URL, OPT_LOCAL, OPT_TTYNAME, OPT_TTYTYPE,
1538 OPT_DISPLAY, OPT_LC_CTYPE, OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES,
1539 OPT_PINENTRY, OPT_KEYFILE, OPT_NEW_KEYFILE, OPT_NOLOCK,
1540 OPT_LOCK_TIMEOUT, OPT_SAVE, OPT_OUTPUT_FD, OPT_INQUIRE,
1541 OPT_INQUIRE_FD, OPT_INQUIRE_FILE, OPT_INQUIRE_LINE, OPT_NO_STATUS,
1542 OPT_STATUS_IGNORE,
1543 OPT_STATUSFD, OPT_NAME, OPT_VERSION, OPT_HELP, OPT_KEYID, OPT_SIGN_KEYID,
1544 OPT_KEYPARAMS, OPT_NO_PINENTRY, OPT_QUIET,
1545 #ifdef HAVE_LIBREADLINE
1546 OPT_INTERACTIVE,
1547 #endif
1549 const struct option long_opts[] = {
1550 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1551 {"socket-timeout", 1, 0, 0},
1552 {"connect-timeout", 1, 0, 0},
1553 #endif
1555 #ifdef WITH_SSH
1556 {"no-ssh-agent", 0, 0, 0},
1557 {"identity", 1, 0, 'i'},
1558 {"knownhosts", 1, 0, 'k'},
1559 #endif
1560 #ifdef WITH_GNUTLS
1561 {"ca-cert", 1, 0, 0},
1562 {"client-cert", 1, 0, 0},
1563 {"client-key", 1, 0, 0},
1564 {"tls-priority", 1, 0, 0},
1565 {"tls-verify", 0, 0, 0},
1566 {"tls-fingerprint", 1, 0, 0},
1567 #endif
1568 {"url", 1, 0, 0},
1569 {"local-pinentry", 0, 0},
1570 {"ttyname", 1, 0, 'y'},
1571 {"ttytype", 1, 0, 't'},
1572 {"display", 1, 0, 'd'},
1573 {"lc-ctype", 1, 0, 0},
1574 {"lc-messages", 1, 0, 0},
1575 {"timeout", 1, 0, 0},
1576 {"tries", 1, 0, 0},
1577 {"pinentry", 1, 0, 0},
1578 {"key-file", 1, 0, 0},
1579 {"new-key-file", 1, 0, 0},
1580 {"no-lock", 0, 0, 0},
1581 {"lock-timeout", 1, 0, 0},
1582 {"save", 0, 0, 'S'},
1583 {"output-fd", 1, 0, 0},
1584 {"inquire", 1, 0, 0},
1585 {"inquire-fd", 1, 0, 0},
1586 {"inquire-file", 1, 0, 0},
1587 {"inquire-line", 1, 0, 'L'},
1588 {"no-status", 0, 0, 0},
1589 {"status-ignore", 1, 0, 0},
1590 {"status-fd", 1, 0, 0},
1591 {"name", 1, 0, 'n'},
1592 {"version", 0, 0, 0},
1593 {"help", 0, 0, 0},
1594 {"keyid", 1, 0, 0},
1595 {"sign-keyid", 1, 0, 0},
1596 {"key-params", 1, 0, 0},
1597 {"no-pinentry", 0, 0, 0},
1598 {"quiet", 0, 0, 0},
1599 #ifdef HAVE_LIBREADLINE
1600 {"interactive", 0, 0},
1601 #endif
1602 {0, 0, 0, 0}
1604 #ifdef WITH_SSH
1605 const char *optstring = "L:y:t:d:P:I:Sn:i:k:";
1606 #else
1607 const char *optstring = "L:y:t:d:P:I:Sn:";
1608 #endif
1609 int opt_index = 0;
1611 #ifdef ENABLE_NLS
1612 setlocale (LC_ALL, "");
1613 bindtextdomain ("libpwmd", LOCALEDIR);
1614 #endif
1616 tries = DEFAULT_PIN_TRIES;
1617 inquirefd = STDIN_FILENO;
1618 statusfd = STDERR_FILENO;
1619 statusfp = fdopen (statusfd, "w");
1620 tmp = pwmd_strdup (DEFAULT_STATUS_IGNORE);
1621 parse_status_ignore (tmp);
1622 pwmd_free (tmp);
1624 while ((opt =
1625 getopt_long (argc, argv, optstring, long_opts, &opt_index)) != -1)
1627 switch (opt)
1629 /* Handle long options without a short option part. */
1630 case 0:
1631 switch (opt_index)
1633 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1634 case OPT_SOCKET_TIMEOUT:
1635 socket_timeout = strtol (optarg, &p, 10);
1636 break;
1637 case OPT_CONNECT_TIMEOUT:
1638 connect_timeout = strtol (optarg, &p, 10);
1639 break;
1640 #endif
1641 #ifdef WITH_SSH
1642 case OPT_USE_SSH_AGENT:
1643 use_ssh_agent = 0;
1644 break;
1645 #endif
1646 #ifdef WITH_GNUTLS
1647 case OPT_CACERT:
1648 cacert = optarg;
1649 break;
1650 case OPT_CLIENTCERT:
1651 clientcert = optarg;
1652 break;
1653 case OPT_CLIENTKEY:
1654 clientkey = optarg;
1655 break;
1656 case OPT_PRIORITY:
1657 prio = optarg;
1658 break;
1659 case OPT_VERIFY:
1660 tls_verify = 1;
1661 break;
1662 case OPT_SERVER_FP:
1663 tls_fingerprint = optarg;
1664 break;
1665 #endif
1666 case OPT_KEYPARAMS:
1667 keyparams = optarg;
1668 break;
1669 case OPT_KEYFILE:
1670 keyfile = pwmd_strdup (optarg);
1671 break;
1672 case OPT_NEW_KEYFILE:
1673 new_keyfile = pwmd_strdup (optarg);
1674 break;
1675 case OPT_NOLOCK:
1676 lock_on_open = 0;
1677 break;
1678 case OPT_LOCK_TIMEOUT:
1679 lock_timeout = strtol (optarg, &p, 10);
1680 break;
1681 case OPT_URL:
1682 url = optarg;
1683 break;
1684 case OPT_LOCAL:
1685 local_pin = 1;
1686 break;
1687 case OPT_LC_CTYPE:
1688 lcctype = pwmd_strdup (optarg);
1689 break;
1690 case OPT_LC_MESSAGES:
1691 lcmessages = pwmd_strdup (optarg);
1692 break;
1693 case OPT_TIMEOUT:
1694 timeout = strtol (optarg, &p, 10);
1695 break;
1696 case OPT_TRIES:
1697 tries = strtol (optarg, &p, 10);
1698 break;
1699 case OPT_INQUIRE:
1700 inquire = escape (optarg);
1701 break;
1702 case OPT_INQUIRE_FD:
1703 inquirefd = strtol (optarg, &p, 10);
1704 if (!p)
1706 inquirefp = fdopen (inquirefd, "r");
1707 if (!inquirefp)
1708 err (EXIT_FAILURE, "%i", inquirefd);
1710 break;
1711 case OPT_INQUIRE_FILE:
1712 inquirefd = open (optarg, O_RDONLY);
1713 if (inquirefd == -1)
1714 err (EXIT_FAILURE, "%s", optarg);
1715 inquirefp = fdopen (inquirefd, "r");
1716 break;
1717 case OPT_OUTPUT_FD:
1718 outfd = strtol (optarg, &p, 10);
1719 if (!p || !*p)
1721 outfp = fdopen (outfd, "w");
1722 if (!outfp)
1723 err (EXIT_FAILURE, "%i", outfd);
1725 break;
1726 case OPT_NO_STATUS:
1727 show_status = 0;
1728 break;
1729 case OPT_STATUSFD:
1730 statusfd = strtol (optarg, &p, 10);
1731 if (!p || !*p)
1733 statusfp = fdopen (statusfd, "w");
1734 if (!statusfp)
1735 err (EXIT_FAILURE, "%i", statusfd);
1737 break;
1738 case OPT_STATUS_IGNORE:
1739 parse_status_ignore (optarg);
1740 break;
1741 case OPT_VERSION:
1742 printf ("%s (pwmc)\n\n"
1743 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015\n"
1744 "%s\n"
1745 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1746 "Compile-time features:\n"
1747 #ifdef HAVE_LIBREADLINE
1748 "+INTERACTIVE "
1749 #else
1750 "-INTERACTIVE "
1751 #endif
1752 #ifdef WITH_SSH
1753 "+SSH "
1754 #else
1755 "-SSH "
1756 #endif
1757 #ifdef WITH_GNUTLS
1758 "+GNUTLS "
1759 #else
1760 "-GNUTLS "
1761 #endif
1762 #ifdef WITH_PINENTRY
1763 "+PINENTRY "
1764 #else
1765 "-PINENTRY "
1766 #endif
1767 #ifdef WITH_QUALITY
1768 "+CRACK "
1769 #else
1770 "-CRACK "
1771 #endif
1772 #ifdef MEM_DEBUG
1773 "+MEM_DEBUG "
1774 #else
1775 "-MEM_DEBUG "
1776 #endif
1777 "\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1778 exit (EXIT_SUCCESS);
1779 case OPT_PINENTRY:
1780 pinentry_path = optarg;
1781 break;
1782 case OPT_HELP:
1783 usage (argv[0], EXIT_SUCCESS);
1784 case OPT_KEYID:
1785 keyid = optarg;
1786 break;
1787 case OPT_SIGN_KEYID:
1788 sign_keyid = optarg;
1789 break;
1790 case OPT_QUIET:
1791 quiet = 1;
1792 show_status = 0;
1793 break;
1794 case OPT_NO_PINENTRY:
1795 no_pinentry = 1;
1796 break;
1797 #ifdef HAVE_LIBREADLINE
1798 case OPT_INTERACTIVE:
1799 interactive = 1;
1800 break;
1801 #endif
1802 default:
1803 usage (argv[0], EXIT_FAILURE);
1806 if (p && *p)
1808 fprintf (stderr, N_("%s: invalid argument for option '--%s'\n"),
1809 argv[0], long_opts[opt_index].name);
1810 usage (argv[0], EXIT_FAILURE);
1813 break;
1814 #ifdef WITH_SSH
1815 case 'i':
1816 identity = optarg;
1817 break;
1818 case 'k':
1819 knownhosts = optarg;
1820 break;
1821 #endif
1822 case 'L':
1823 inquire_line = optarg;
1824 break;
1825 case 'y':
1826 tty = optarg;
1827 break;
1828 case 't':
1829 ttytype = optarg;
1830 break;
1831 case 'd':
1832 display = optarg;
1833 break;
1834 case 'S':
1835 save = 1;
1836 break;
1837 case 'n':
1838 clientname = optarg;
1839 break;
1840 default:
1841 usage (argv[0], EXIT_FAILURE);
1845 #ifdef HAVE_LIBREADLINE
1846 if (interactive && !isatty (STDIN_FILENO))
1847 usage (argv[0], EXIT_FAILURE);
1848 else if (isatty (STDIN_FILENO) && !inquire && !inquire_line)
1849 interactive = 1;
1850 #endif
1852 filename = argv[optind];
1853 #ifdef WITH_GNUTLS
1854 gnutls_global_set_mem_functions (pwmd_malloc, pwmd_malloc, NULL,
1855 pwmd_realloc, pwmd_free);
1856 #endif
1857 pwmd_init ();
1858 rc = pwmd_new (clientname, &pwm);
1859 if (rc)
1860 goto done;
1862 pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
1863 if (!quiet)
1864 fprintf (stderr, N_("Connecting ...\n"));
1866 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1867 socktype = is_remote_url (url);
1868 if (socktype != PWMD_SOCKET_LOCAL)
1870 local_pin = 1;
1871 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1872 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, connect_timeout);
1873 if (rc)
1874 goto done;
1875 #endif
1877 if (socktype == PWMD_SOCKET_SSH)
1879 #ifdef WITH_SSH
1880 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_CB, knownhost_cb);
1881 if (rc)
1882 goto done;
1884 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_DATA, clientname);
1885 if (rc)
1886 goto done;
1888 if (!getenv ("SSH_AUTH_SOCK") || identity)
1889 use_ssh_agent = 0;
1891 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_AGENT, use_ssh_agent);
1892 if (rc)
1893 goto done;
1895 rc = pwmd_connect (pwm, url, identity, knownhosts);
1896 #endif
1898 #ifdef WITH_GNUTLS
1899 else
1901 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_VERIFY, tls_verify);
1902 if (rc)
1903 goto done;
1905 rc = pwmd_connect (pwm, url, clientcert, clientkey, cacert, prio,
1906 tls_fingerprint);
1908 #endif
1910 else
1911 rc = pwmd_connect (pwm, url);
1912 #else
1913 rc = pwmd_connect (pwm, url);
1914 #endif
1915 if (rc)
1916 goto done;
1918 if (!quiet)
1919 fprintf (stderr, N_("Connected.\n"));
1921 connected = 1;
1922 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1923 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, socket_timeout);
1924 if (rc)
1925 goto done;
1926 #endif
1928 if (lock_timeout)
1930 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1931 "OPTION LOCK-TIMEOUT=%li", lock_timeout);
1932 if (rc)
1933 goto done;
1936 if (lock_on_open)
1938 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCK_ON_OPEN, 1);
1939 if (rc)
1940 goto done;
1943 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, NULL, NULL);
1944 if (rc)
1945 goto done;
1947 if (timeout > 0)
1949 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
1950 if (rc)
1951 goto done;
1954 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1955 if (rc)
1956 goto done;
1958 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY,
1959 (local_pin || keyfile || new_keyfile));
1960 if (rc)
1961 goto done;
1963 if (pinentry_path)
1965 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
1966 if (rc)
1967 goto done;
1970 if (display)
1972 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
1973 if (rc)
1974 goto done;
1977 if (tty)
1979 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, tty);
1980 if (rc)
1981 goto done;
1984 if (ttytype)
1986 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
1987 if (rc)
1988 goto done;
1991 if (lcctype)
1993 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
1994 if (rc)
1995 goto done;
1998 if (lcmessages)
2000 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES, lcmessages);
2001 if (rc)
2002 goto done;
2005 if (show_status)
2007 rc = pwmd_setopt (pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
2008 if (rc)
2009 goto done;
2012 if (filename)
2014 rc = open_command (filename);
2015 if (rc)
2016 goto done;
2019 #ifdef HAVE_LIBREADLINE
2020 if (interactive)
2022 rc = do_interactive ();
2023 result = NULL;
2024 goto do_exit;
2026 #endif
2028 if (inquire)
2030 struct inquire_s *inq = NULL;
2032 rc = set_inquire (inquirefd, inquire_line, &inq);
2033 if (!rc)
2034 rc = pwmd_command (pwm, &result, &len, inquire_cb, inq, "%s", inquire);
2036 free_inquire (inq);
2037 goto done;
2040 if (fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1)
2042 rc = gpg_error_from_errno (errno);
2043 goto done;
2046 ssize_t n;
2048 for (;;)
2050 rc = process_cmd ();
2052 if (rc)
2053 goto done;
2055 n = read (STDIN_FILENO, command, sizeof (command)-1);
2056 if (n == -1)
2058 if (errno == EAGAIN)
2060 usleep (100000);
2061 continue;
2064 rc = gpg_error_from_errno (errno);
2065 goto done;
2067 else if (!n)
2068 goto done;
2070 p = command;
2071 command[n] = 0;
2072 break;
2075 if (!p || !*p || !strcasecmp (p, "BYE"))
2076 goto done;
2079 struct inquire_s *inq = NULL;
2080 rc = set_inquire (inquirefd, inquire_line, &inq);
2081 if (!rc)
2083 rc = parse_dotcommand (command, &result, &len, inq);
2084 free_inquire (inq);
2087 if (rc)
2088 goto done;
2090 done:
2091 if (result)
2093 fwrite (result, 1, result[len - 1] == 0 ? len - 1 : len, outfp);
2094 fflush (outfp);
2095 pwmd_free (result);
2098 result = NULL;
2099 if (!rc)
2100 rc = finalize ();
2101 else if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
2102 (void) pwmd_command (pwm, &result, NULL, NULL, NULL,
2103 "GETINFO last_error");
2105 #ifdef HAVE_LIBREADLINE
2106 do_exit:
2107 #endif
2108 memset (command, 0, sizeof (command));
2110 if (rc && !quiet)
2111 show_error (pwm, rc, result);
2113 pwmd_close (pwm);
2114 reset_keyfiles ();
2115 pwmd_deinit ();
2116 pwmd_free (result);
2117 parse_status_ignore (NULL);
2118 if (connected && !quiet)
2119 fprintf (stderr, N_("Connection closed.\n"));
2121 exit (rc ? EXIT_FAILURE : EXIT_SUCCESS);