Fix resetting key files for non-interactive mode.
[libpwmd.git] / src / pwmc.c
blob63d5b1aed43e6df2294811c5ee18210666a80f8c
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 int symmetric;
99 static char *keyparams;
100 static char *keyfile;
101 static char *new_keyfile;
102 static char *sign_keyfile;
103 static int tries;
104 static int local_pin;
105 static int inquirefd;
106 static int statusfd;
107 FILE *statusfp;
108 static int quiet;
109 static char **status_ignore;
111 struct inquire_s
113 int fd;
114 char *line;
115 size_t len;
116 size_t size; // from stat(2).
117 char *last_keyword;
120 static gpg_error_t finalize ();
121 static gpg_error_t set_inquire (int fd, const char *line,
122 struct inquire_s **result);
123 static gpg_error_t parse_dotcommand (const char *line, char **result,
124 size_t * len, struct inquire_s *inq);
125 static gpg_error_t open_command (const char *line);
126 #ifdef WITH_SSH
127 static gpg_error_t get_password (char **result, pwmd_pinentry_t w, int echo);
128 #endif
130 static void
131 show_error (pwm_t *pwm, gpg_error_t rc, const char *str)
133 #ifdef WITH_GNUTLS
134 if (pwmd_tls_error (pwm))
135 fprintf(stderr, "TLS: %s\n", gnutls_strerror(pwmd_tls_error(pwm)));
136 #endif
137 fprintf (stderr, "ERR %i: %s%s%s%s", rc, gpg_strerror (rc),
138 str ? ": " : "", str ? str : "", str ? "" : "\n");
141 static void
142 reset_keyfiles ()
144 pwmd_free (keyfile);
145 pwmd_free (new_keyfile);
146 pwmd_free (sign_keyfile);
147 keyfile = new_keyfile = sign_keyfile = NULL;
150 static void
151 usage (const char *pn, int status)
153 fprintf (status == EXIT_FAILURE ? stderr : stdout,
154 N_("Usage: pwmc [options] [file]\n"
155 " --url <string>\n"
156 " a url string to connect to (%s, see below)\n"
157 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
158 " --connect-timeout <seconds>\n"
159 " seconds before connecting to a remote host fails (0=disabled, 120)\n"
160 " --socket-timeout <seconds>\n"
161 " seconds before a remote command fails (0=disabled, 300)\n"
162 #endif
163 #ifdef WITH_GNUTLS
164 " --ca-cert <filename>\n"
165 " certificate authority (CA) used to sign the server cert\n"
166 " --client-cert <filename>\n"
167 " client certificate to use for authentication\n"
168 " --client-key <filename>\n"
169 " key file used to protect the client certificate\n"
170 " --tls-priority <string>\n"
171 " compression, cipher and hash algorithm string\n"
172 " (SECURE256:SECURE192:SECURE128:-VERS-SSL3.0)\n"
173 " --tls-verify\n"
174 " verify the hostname against the server certificate\n"
175 " --tls-fingerprint <string>\n"
176 " a SHA-256 hash of the server fingerprint to verify against\n"
177 #endif
178 #ifdef WITH_SSH
179 " --no-ssh-agent\n"
180 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
181 " --identity, -i <filename>\n"
182 " the ssh identity file to use for authentication\n"
183 " --knownhosts, -k <filename>\n"
184 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
185 #endif
186 " --no-lock\n"
187 " do not lock the data file upon opening it\n"
188 " --lock-timeout <N>\n"
189 " time in tenths of a second to wait for a locked data file (50)\n"
190 " --name, -n <string>\n"
191 " set the client name\n"
192 " --pinentry <path>\n"
193 " the full path to the pinentry binary\n"
194 " --local-pinentry\n"
195 " force using a local pinentry\n"
196 " --no-pinentry\n"
197 " disable pinentry both remotely and locally\n"
198 " --ttyname, -y <path>\n"
199 " tty that pinentry will use\n"
200 " --ttytype, -t <string>\n"
201 " pinentry terminal type (default is $TERM)\n"
202 " --display, -d\n"
203 " pinentry display (default is $DISPLAY)\n"
204 " --lc-ctype <string>\n"
205 " locale setting for pinentry\n"
206 " --lc-messages <string>\n"
207 " locale setting for pinentry\n"
208 " --tries <N>\n"
209 " number of pinentry tries before failing (3)\n"
210 " --timeout <seconds>\n"
211 " pinentry timeout\n"
212 " --inquire <COMMAND>\n"
213 " the specified command (with any options) uses a server inquire while\n"
214 " command data is read via the inquire file descriptor (stdin)\n"
215 " --inquire-line, -L <STRING>\n"
216 " the initial line to send (i.e., element path) before the inquire data\n"
217 " --inquire-fd <FD>\n"
218 " read inquire data from the specified file descriptor (stdin)\n"
219 " --inquire-file <filename>\n"
220 " read inquire data from the specified filename\n"
221 " --output-fd <FD>\n"
222 " redirect command output to the specified file descriptor\n"
223 " --save, -S\n"
224 " send the SAVE command before exiting\n"
225 " --key-file <filename>\n"
226 " obtain the passphrase from the specified filename\n"
227 " --new-key-file <filename>\n"
228 " obtain the passphrase to save with from the specified filename\n"
229 " --sign-key-file <filename>\n"
230 " obtain the passphrase to sign (symmetric) with from the specified filename\n"
231 " --key-params <filename>\n"
232 " key parameters to use for key generation (pwmd default)\n"
233 " --keyid <recipient>[,<recipient>]\n"
234 " the public key ID to u\n"
235 " --sign-keyid <string>\n"
236 " the key ID to sign the data file with\n"
237 " --symmetric\n"
238 " use conventional encryption with optional signer(s) for new files\n"
239 " --no-status\n"
240 " disable showing of status messages from the server\n"
241 " --status-ignore <string[,...]>\n"
242 " prevent parsing of the specified status message keywords\n"
243 " --quiet\n"
244 " disable showing of extra messages (implies --no-status)\n"
245 " --status-fd <FD>\n"
246 " redirect status messages to the specified file descriptor\n"
247 #ifdef HAVE_LIBREADLINE
248 " --interactive\n"
249 " use a shell like interface to pwmd (allows more than one command)\n"
250 #endif
251 " --version\n"
252 " --help\n"),
253 #ifdef DEFAULT_PWMD_SOCKET
254 DEFAULT_PWMD_SOCKET
255 #else
256 "~/.pwmd/socket"
257 #endif
259 fprintf (status == EXIT_FAILURE ? stderr : stdout,
260 N_("\n"
261 "An optional url may be in the form of:\n"
262 " --url /path/to/socket\n"
263 " --url file://[path/to/socket]\n"
264 #ifdef WITH_SSH
265 " or\n"
266 " --url ssh[46]://[username@]hostname[:port]\n"
267 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
268 #endif
269 #ifdef WITH_GNUTLS
270 " or\n"
271 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
272 " --client-key filename\n"
273 #endif
274 #ifdef HAVE_LIBREADLINE
275 "\n"
276 "Interactive mode is used when input is from a terminal.\n"
277 #endif
279 exit (status);
282 static gpg_error_t
283 inquire_cb (void *user, const char *keyword, gpg_error_t rc,
284 char **data, size_t * size)
286 struct inquire_s *inq = user;
287 int is_password = 0;
288 int is_newpassword = 0;
289 int sign = 0;
290 int is_keyparam = 0;
292 *data = NULL;
293 *size = 0;
295 if (rc)
296 return rc;
298 if (!strcmp (keyword, "PASSPHRASE"))
299 is_password = 1;
300 else if (!strcmp (keyword, "SIGN_PASSPHRASE"))
301 is_password = sign = 1;
302 else if (!strcmp (keyword, "NEW_PASSPHRASE"))
303 is_newpassword = 1;
304 #ifdef HAVE_LIBREADLINE
305 else if (!strcmp (keyword, "KEYPARAM") && !interactive)
307 #else
308 else if (!strcmp (keyword, "KEYPARAM"))
310 #endif
311 int fd;
312 if (!keyparams || !*keyparams)
313 return gpg_error (GPG_ERR_INV_PARAMETER);
315 fd = open (keyparams, O_RDONLY);
316 if (fd == -1)
318 fprintf (stderr, "%s: %s\n", keyparams, strerror (errno));
319 return gpg_error_from_syserror ();
322 rc = set_inquire (fd, NULL, &inq);
323 if (rc)
325 close (fd);
326 return rc;
329 if (!quiet)
330 fprintf (stderr, N_("Using file '%s' as %s.\n"), keyparams, keyword);
332 is_keyparam = 1;
335 if ((is_newpassword && new_keyfile) || (is_password && keyfile)
336 || (sign && sign_keyfile))
338 int fd;
340 if (sign)
341 fd = open (sign_keyfile, O_RDONLY);
342 else
343 fd = open (is_password ? keyfile : new_keyfile, O_RDONLY);
345 if (fd == -1)
347 if (sign)
348 fprintf (stderr, "%s: %s\n", sign_keyfile, strerror (errno));
349 else
350 fprintf (stderr, "%s: %s\n", is_newpassword ? new_keyfile
351 : keyfile, strerror (errno));
352 return gpg_error_from_syserror ();
355 rc = set_inquire (fd, NULL, &inq);
356 if (rc)
358 close (fd);
359 return rc;
362 if (!quiet)
363 fprintf (stderr, N_("Using keyfile '%s' as %s.\n"),
364 sign ? sign_keyfile : is_newpassword ? new_keyfile
365 : keyfile, keyword);
367 else if ((is_password && !keyfile) || (is_newpassword && !new_keyfile)
368 || (sign && !sign_keyfile))
370 char *tmp;
372 rc = pwmd_password (pwm, keyword, &tmp, &inq->len);
373 if (rc && gpg_err_code (rc) != GPG_ERR_EOF)
374 return rc;
376 pwmd_free (inq->line);
377 inq->line = tmp;
378 *data = inq->line;
379 *size = inq->len;
380 return gpg_error (GPG_ERR_EOF);
382 #ifdef HAVE_LIBREADLINE
383 else if ((!inq->last_keyword || strcmp (keyword, inq->last_keyword))
384 && interactive)
386 fprintf (stderr,
388 ("%sPress CTRL-D to send the current line. Press twice to end. %s:\n"),
389 inq->last_keyword ? "\n" : "", keyword);
390 pwmd_free (inq->last_keyword);
391 inq->last_keyword = pwmd_strdup (keyword);
393 #endif
395 /* The first part of the command data. */
396 if (inq->len)
398 *data = inq->line;
399 *size = inq->len;
400 inq->len = 0;
401 return inq->fd == -1 ? gpg_error (GPG_ERR_EOF) : 0;
404 *size = read (inq->fd, inq->line, ASSUAN_LINELENGTH);
405 if (*size == -1)
407 *size = 0;
408 return gpg_error (gpg_error_from_syserror ());
410 else if (*size)
411 *data = inq->line;
412 else if (inq->fd != STDIN_FILENO &&
413 (is_newpassword || is_password || is_keyparam))
415 *inq->line = 0;
416 inq->size = 1;
417 *data = inq->line;
418 *size = 1;
421 if (((is_newpassword && new_keyfile) || (is_password && keyfile)
422 || (sign && sign_keyfile) || (keyparams && is_keyparam))
423 && *size == inq->size)
424 return gpg_error (GPG_ERR_EOF);
426 return *size ? 0 : gpg_error (GPG_ERR_EOF);
429 static int
430 status_msg_cb (void *data, const char *line)
432 char *p = strchr (line, ' ');
433 char **s;
435 /* Ignore status messages specified by the client via --status-ignore. */
436 for (s = status_ignore; s && *s; s++)
438 char *tmp = strchr (line, ' ');
439 size_t len = tmp ? strlen (line) - strlen (tmp) : strlen (line);
441 if (!strncmp (line, *s, len) && len == strlen (*s))
442 return 0;
445 if (statusfd != STDERR_FILENO && strncmp (line, "STATE ", 6) && *line != '#'
446 && p && strchr (p, ' ') && *++p)
448 char *p1 = strchr (p, ' ');
449 int a = strtol (p, NULL, 10);
451 if (isdigit (*p) && p1)
453 int b = strtol (p1, NULL, 10);
454 char l[64] = { 0 };
455 int t = a && b ? a * 100 / b : 0;
457 strncpy (l, line, strlen (line) - strlen (p) - 1);
458 fprintf (statusfp, "\r%s %i/%i %i%%%s", l, a, b, t,
459 a == b ? "\n" : "");
460 fflush (statusfp);
461 return 0;
465 fprintf (statusfp, "%s\n", line);
466 fflush (statusfp);
467 #ifdef HAVE_LIBREADLINE
468 rl_on_new_line ();
469 #endif
470 return 0;
473 static gpg_error_t
474 process_cmd ()
476 return pwmd_process (pwm);
479 #ifdef WITH_SSH
480 static gpg_error_t
481 get_password (char **result, pwmd_pinentry_t w, int echo)
483 char buf[LINE_MAX] = { 0 }, *p;
484 struct termios told, tnew;
485 char *key = NULL;
487 *result = NULL;
489 if (!isatty (STDIN_FILENO))
491 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
492 return GPG_ERR_ENOTTY;
495 if (!echo)
497 if (tcgetattr (STDIN_FILENO, &told) == -1)
498 return gpg_error_from_syserror ();
500 memcpy (&tnew, &told, sizeof (struct termios));
501 tnew.c_lflag &= ~(ECHO);
502 tnew.c_lflag |= ICANON | ECHONL;
504 if (tcsetattr (STDIN_FILENO, TCSANOW, &tnew) == -1)
506 int n = errno;
508 tcsetattr (STDIN_FILENO, TCSANOW, &told);
509 return gpg_error_from_errno (n);
513 switch (w)
515 case PWMD_PINENTRY_OPEN:
516 fprintf (stderr, N_("Password for %s: "), filename);
517 break;
518 case PWMD_PINENTRY_OPEN_FAILED:
519 fprintf (stderr, N_("Invalid password. Password for %s: "), filename);
520 break;
521 case PWMD_PINENTRY_SAVE:
522 fprintf (stderr, N_("New password for %s: "), filename);
523 break;
524 case PWMD_PINENTRY_SAVE_CONFIRM:
525 fprintf (stderr, N_("Confirm password: "));
526 break;
527 default:
528 break;
531 if ((p = fgets (buf, sizeof (buf), stdin)) == NULL)
533 if (!echo)
534 tcsetattr (STDIN_FILENO, TCSANOW, &told);
536 return 0;
539 if (!echo)
540 tcsetattr (STDIN_FILENO, TCSANOW, &told);
542 if (feof (stdin))
544 clearerr (stdin);
545 return GPG_ERR_CANCELED;
548 p[strlen (p) - 1] = 0;
550 if (buf[0])
552 key = pwmd_strdup_printf ("%s", p);
553 memset (&buf, 0, sizeof (buf));
555 if (!key)
556 return GPG_ERR_ENOMEM;
559 *result = key;
560 return 0;
563 static gpg_error_t
564 knownhost_cb (void *data, const char *host, const char *key, size_t len)
566 gpg_error_t rc;
567 char *buf =
568 pwmd_strdup_printf (N_
569 ("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?"),
570 (char *) data, host, host);
572 if (no_pinentry && !isatty (STDIN_FILENO))
574 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
575 pwmd_free (buf);
576 return GPG_ERR_ENOTTY;
578 else if (no_pinentry)
580 for (char *p = buf, len = 0; *p; p++, len++)
582 if (*p == '\n')
583 len = 0;
585 if (len == 78)
587 char *t = p;
589 while (!isspace (*(--p)));
590 *p = '\n';
591 p = t;
592 len = 0;
596 fprintf (stderr, "%s\n\n", buf);
597 pwmd_free (buf);
601 char *result;
603 fprintf (stderr, N_("Trust this connection [y/N]: "));
604 fflush (stderr);
605 rc = get_password (&result, PWMD_PINENTRY_CONFIRM, 1);
607 if (rc)
608 return rc;
610 if (!result || !*result || *result == 'n' || *result == 'N')
612 if (result && *result)
613 pwmd_free (result);
615 return GPG_ERR_NOT_CONFIRMED;
618 if ((*result == 'y' || *result == 'Y') && *(result + 1) == 0)
620 pwmd_free (result);
621 return 0;
624 while (1);
627 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, buf);
628 pwmd_free (buf);
630 if (rc)
631 return rc;
633 return pwmd_getpin (pwm, NULL, NULL, NULL, PWMD_PINENTRY_CONFIRM);
635 #endif
637 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
638 static pwmd_socket_t
639 is_remote_url (const char *str)
641 if (!str)
642 return PWMD_SOCKET_LOCAL;
644 #ifdef WITH_SSH
645 if (strstr (str, "ssh://") || strstr (str, "ssh4://")
646 || strstr (str, "ssh6://"))
647 return PWMD_SOCKET_SSH;
648 #endif
650 #ifdef WITH_GNUTLS
651 if (strstr (str, "tls://") || strstr (str, "tls4://")
652 || strstr (str, "tls6://"))
653 return PWMD_SOCKET_TLS;
654 #endif
656 return PWMD_SOCKET_LOCAL;
658 #endif
660 static char *
661 escape (const char *str)
663 const char *p;
664 char *buf = pwmd_malloc (ASSUAN_LINELENGTH + 1), *b = buf;
665 size_t len = 0;
667 for (p = str; *p; p++, len++)
669 if (len == ASSUAN_LINELENGTH)
670 break;
672 if (*p == '\\')
674 switch (*++p)
676 case 't':
677 *b++ = '\t';
678 break;
679 case 'n':
680 *b++ = '\n';
681 break;
682 case 'v':
683 *b++ = '\v';
684 break;
685 case 'b':
686 *b++ = '\b';
687 break;
688 case 'f':
689 *b++ = '\f';
690 break;
691 case 'r':
692 *b++ = '\r';
693 break;
694 default:
695 *b++ = *p;
696 break;
699 if (!*p)
700 break;
702 continue;
705 *b++ = *p;
708 *b = 0;
709 return buf;
712 static void
713 free_inquire (struct inquire_s *inq)
715 if (!inq)
716 return;
718 pwmd_free (inq->line);
720 if (inq->fd != -1 && inq->fd != STDIN_FILENO)
721 close (inq->fd);
723 pwmd_free (inq->last_keyword);
724 pwmd_free (inq);
727 /* When *result is not NULL it is updated to the new values and not
728 * reallocated. */
729 static gpg_error_t
730 set_inquire (int fd, const char *line, struct inquire_s **result)
732 struct inquire_s inq = { 0 };
733 struct stat st = { 0 };
734 gpg_error_t rc;
736 if (fd != -1)
738 if (fstat (fd, &st) == -1)
739 return gpg_error_from_syserror ();
741 inq.size = st.st_size;
744 inq.fd = fd;
745 inq.line = pwmd_calloc (1, ASSUAN_LINELENGTH);
746 if (!inq.line)
747 return GPG_ERR_ENOMEM;
749 if (line)
751 char *s = escape (line);
753 if (!s)
755 pwmd_free (inq.line);
756 return GPG_ERR_ENOMEM;
759 if (strlen (s) >= ASSUAN_LINELENGTH)
761 pwmd_free (inq.line);
762 pwmd_free (s);
763 return GPG_ERR_LINE_TOO_LONG;
766 strncpy (inq.line, s, ASSUAN_LINELENGTH - 1);
767 inq.len = strlen (s);
768 pwmd_free (s);
771 rc = pwmd_setopt (pwm, PWMD_OPTION_INQUIRE_TOTAL,
772 st.st_size ? st.st_size + strlen (inq.line) : 0);
773 if (rc)
775 pwmd_free (inq.line);
776 return rc;
779 if (*result == NULL)
780 *result = pwmd_malloc (sizeof (struct inquire_s));
781 else
783 if ((*result)->fd != -1 && (*result)->fd != STDIN_FILENO)
784 close ((*result)->fd);
786 pwmd_free ((*result)->line);
787 (*result)->line = NULL;
788 (*result)->fd = -1;
789 (*result)->len = 0;
792 memcpy (*result, &inq, sizeof (struct inquire_s));
793 memset (&inq, 0, sizeof (struct inquire_s));
794 return rc;
797 #ifdef HAVE_LIBREADLINE
798 static int
799 interactive_hook (void)
801 interactive_error = process_cmd ();
803 if (interactive_error)
804 rl_event_hook = NULL;
806 return 0;
809 static void
810 print_help ()
812 fprintf (stderr,
814 ("------------------------------------------------------------------------------\n"
815 "Elements are TAB delimited. Press CTRL-V then TAB to insert from the prompt.\n"
816 "\n"
817 "Type HELP for protocol commands. Type .help for pwmc commands. Press CTRL-D\n"
818 "to quit.\n"
819 "------------------------------------------------------------------------------\n"));
821 #endif
823 static char *
824 parse_arg (const char *src, char *dst, size_t len)
826 char *p = dst;
827 const char *s = src;
828 size_t n = 0;
830 for (; s && *s && *s != ' ' && n < len; s++, n++)
831 *p++ = *s;
833 *p = 0;
834 return dst;
837 static char *
838 parse_opt (char **line, const char *opt, gpg_error_t * rc)
840 static char result[ASSUAN_LINELENGTH] = { 0 }, *r = result;
841 char *s = strstr (*line, opt);
843 *rc = 0;
844 result[0] = 0;
845 r = result;
847 if (s)
849 size_t len = 0;
850 int quote = 0;
851 size_t rlen = strlen (opt);
852 char *p = s + rlen;
853 int lastc = 0;
855 while (*p && *p == ' ')
857 rlen++;
858 p++;
861 for (; *p && len < sizeof (result) - 1; p++, rlen++)
863 if (isspace (*p) && !quote)
864 break;
866 if (*p == '\"' && lastc != '\\')
868 quote = !quote;
869 lastc = *p;
870 continue;
873 *r++ = lastc = *p;
874 len++;
877 *r = 0;
879 if (len >= sizeof (result) - 1)
880 *rc = GPG_ERR_LINE_TOO_LONG;
881 else
883 p = s + rlen;
885 while (*p && *p == ' ')
886 p++;
888 *line = p;
892 return result;
895 static gpg_error_t
896 read_command (const char *line, char **result, size_t * len)
898 int fd;
899 gpg_error_t rc = 0;
900 char *filename = NULL;
901 struct inquire_s *inq = NULL;
902 char *p = (char *) line;
903 const char *prefix = parse_opt (&p, "--prefix", &rc);
904 char filebuf[ASSUAN_LINELENGTH];
906 if (rc)
907 return rc;
909 rc = GPG_ERR_SYNTAX;
911 if (p && *p)
913 while (*p && isspace (*p))
914 p++;
916 filename = parse_arg (p, filebuf, sizeof (filebuf));
917 if (filename && *filename)
919 p += strlen (filename) + 1;
921 while (*p && isspace (*p))
922 p++;
924 if (*p)
925 rc = 0;
929 if (rc)
931 fprintf (stderr,
933 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
934 fprintf (stderr,
936 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\" = \")\n"));
937 return rc;
940 fd = open (filename, O_RDONLY);
941 if (fd == -1)
942 return gpg_error_from_syserror ();
944 rc = set_inquire (fd, prefix && *prefix ? prefix : NULL, &inq);
945 if (rc)
947 close (fd);
948 return rc;
951 rc = pwmd_command (pwm, result, len, inquire_cb, inq, "%s", p);
952 free_inquire (inq);
953 return rc;
956 static gpg_error_t
957 redir_command (const char *line)
959 const char *p = line;
960 int fd;
961 gpg_error_t rc = GPG_ERR_SYNTAX;
962 char *filename = NULL;
963 struct inquire_s *inq = NULL;
964 char *result = NULL;
965 size_t len = 0;
966 char filebuf[ASSUAN_LINELENGTH];
968 if (p && *p && *++p)
970 filename = parse_arg (p, filebuf, sizeof (filebuf));
971 if (filename && *filename)
973 p += strlen (filename) + 1;
975 while (*p && isspace (*p))
976 p++;
978 if (*p)
979 rc = 0;
983 if (rc)
985 fprintf (stderr, N_("Usage: .redir <filename> <command> [args]\n"));
986 return rc;
989 fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
990 if (fd == -1)
991 return gpg_error_from_syserror ();
993 #ifdef HAVE_LIBREADLINE
994 rc = set_inquire (interactive ? STDIN_FILENO : inquirefd, NULL, &inq);
995 #else
996 rc = set_inquire (inquirefd, NULL, &inq);
997 #endif
998 if (rc)
1000 close (fd);
1001 return rc;
1004 rc = parse_dotcommand (p, &result, &len, inq);
1005 if (!rc && result && len--)
1006 { // null byte which is always appended
1007 if (write (fd, result, len) != len)
1008 rc = GPG_ERR_TOO_SHORT;
1009 pwmd_free (result);
1012 free_inquire (inq);
1013 close (fd);
1014 return rc;
1017 static gpg_error_t
1018 help_command (const char *line)
1020 fprintf (stderr,
1021 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
1022 " .redir <filename> <command>\n"
1023 " redirect the output of a command to the specified file\n"
1024 "\n"
1025 " .open <filename>\n"
1026 " open the specified filename losing any changes to the current one\n"
1027 "\n"
1028 " .read [--prefix <string>] <filename> <command> [args]\n"
1029 " obtain data from the specified filename for an inquire command\n"
1030 "\n"
1031 " .set help | <name> [<value>]\n"
1032 " set option <name> to <value>\n"
1033 "\n"
1034 " .save [args]\n"
1035 " write changes of the file to disk\n"
1036 "\n"
1037 " .passwd [args]\n"
1038 " change the passphrase of a data file\n"
1039 "\n"
1040 " .help\n"
1041 " this help text\n"));
1042 return 0;
1045 static gpg_error_t
1046 open_command (const char *line)
1048 struct inquire_s *inq = NULL;
1049 const char *filename = line;
1050 gpg_error_t rc;
1052 while (filename && isspace (*filename))
1053 filename++;
1055 if (!filename || !*filename)
1057 fprintf (stderr, N_("Usage: .open <filename>\n"));
1058 return GPG_ERR_SYNTAX;
1061 #ifdef HAVE_LIBREADLINE
1062 if (interactive || !quiet)
1063 #else
1064 if (!quiet)
1065 #endif
1066 fprintf (stderr, N_("Opening data file \"%s\" ...\n"), filename);
1068 #ifdef HAVE_LIBREADLINE
1069 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1070 #else
1071 rc = set_inquire (-1, NULL, &inq);
1072 #endif
1073 if (rc)
1074 return rc;
1076 if (keyfile)
1078 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1079 if (!rc)
1080 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 1);
1082 else
1084 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1085 if (!rc)
1086 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1089 if (!rc)
1090 rc = pwmd_open (pwm, filename, inquire_cb, inq);
1092 if (interactive)
1093 reset_keyfiles ();
1095 free_inquire (inq);
1096 return rc;
1099 static gpg_error_t
1100 set_command (const char *line)
1102 gpg_error_t rc = 0;
1103 char name[256] = { 0 };
1104 char value[512] = { 0 };
1105 char *namep;
1106 char *valuep;
1107 const char *p = line;
1109 while (p && *p && isspace (*p))
1110 p++;
1112 namep = parse_arg (p, name, sizeof (name));
1113 if (!namep || !*namep)
1115 fprintf (stderr, N_("Usage: .set help | <name> [<value>]\n"));
1116 return GPG_ERR_SYNTAX;
1119 p += strlen (namep);
1120 while (p && *p && isspace (*p))
1121 p++;
1123 valuep = parse_arg (p, value, sizeof (value));
1125 if (!strcmp (name, "keyfile") || !strcmp (name, "new-keyfile")
1126 || !strcmp (name, "sign-keyfile"))
1128 int is_newkeyfile = 1;
1129 int sign = !strcmp (name, "sign-keyfile");
1131 if (!strcmp (name, "keyfile") || sign)
1132 is_newkeyfile = 0;
1134 if (is_newkeyfile)
1136 pwmd_free (new_keyfile);
1137 new_keyfile = NULL;
1139 else if (sign)
1141 pwmd_free (sign_keyfile);
1142 sign_keyfile = NULL;
1144 else
1146 pwmd_free (keyfile);
1147 keyfile = NULL;
1150 if (!rc && *valuep)
1152 if (is_newkeyfile)
1153 new_keyfile = pwmd_strdup (value);
1154 else if (sign)
1155 sign_keyfile = pwmd_strdup (value);
1156 else
1157 keyfile = pwmd_strdup (value);
1159 if (!rc)
1161 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 1);
1162 if (!rc)
1163 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1166 else if (!local_pin && !no_pinentry)
1168 pwmd_socket_t t;
1170 pwmd_socket_type (pwm, &t);
1171 if (t == PWMD_SOCKET_LOCAL)
1173 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 0);
1174 if (!rc)
1175 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1179 else if (!strcmp(name, "pinentry-timeout"))
1181 char *e = NULL;
1182 int n = strtol(valuep, &e, 10);
1184 if (e && *e)
1185 return gpg_error (GPG_ERR_INV_VALUE);
1187 if (!*valuep)
1188 n = DEFAULT_PIN_TIMEOUT;
1190 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, n);
1192 else if (!strcmp (name, "help"))
1194 fprintf (stderr,
1196 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1197 "delimited. When no value is specified the option is unset.\n\n"
1198 "keyfile [<filename>]\n"
1199 " set or unset the keyfile to be used when a passphrase is required (*)\n"
1200 "\n"
1201 "new-keyfile [<filename>]\n"
1202 " set or unset the keyfile to be used when a new passphrase is required (*)\n"
1203 "\n"
1204 "sign-keyfile [<filename>]\n"
1205 " set or unset the keyfile to be used when a passphrase is required for\n"
1206 " signing (symmetric) (*)\n"
1207 "\n"
1208 "pinentry-timeout <seconds>\n"
1209 " the amount of seconds before pinentry gives up waiting for input\n"
1210 "\n"
1211 "* = the next protocol command will unset this value\n"
1214 else
1215 rc = GPG_ERR_UNKNOWN_OPTION;
1217 return rc;
1220 static gpg_error_t
1221 save_command (const char *line)
1223 struct inquire_s *inq = NULL;
1224 gpg_error_t rc;
1226 #ifdef HAVE_LIBREADLINE
1227 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1228 #else
1229 rc = set_inquire (-1, NULL, &inq);
1230 #endif
1231 if (rc)
1232 return rc;
1234 if (new_keyfile || keyfile || sign_keyfile)
1236 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1237 if (!rc)
1238 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 1);
1240 else
1242 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1243 if (!rc)
1244 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1247 if (!rc)
1248 rc = pwmd_save (pwm, line, inquire_cb, inq);
1250 if (interactive)
1251 reset_keyfiles ();
1253 free_inquire (inq);
1254 return rc;
1257 static gpg_error_t
1258 do_save_passwd_command (const char *line, int save)
1260 struct inquire_s *inq = NULL;
1261 gpg_error_t rc;
1263 #ifdef HAVE_LIBREADLINE
1264 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1265 #else
1266 rc = set_inquire (-1, NULL, &inq);
1267 #endif
1268 if (rc)
1269 return rc;
1271 if (new_keyfile || keyfile || sign_keyfile)
1273 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1274 if (!rc)
1275 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 1);
1277 else
1279 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1280 if (!rc)
1281 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1284 if (!rc)
1286 if (save)
1287 rc = pwmd_save (pwm, line, inquire_cb, inq);
1288 else
1289 rc = pwmd_passwd (pwm, line, inquire_cb, inq);
1292 if (interactive)
1293 reset_keyfiles ();
1295 free_inquire (inq);
1296 return rc;
1299 static gpg_error_t
1300 parse_dotcommand (const char *line, char **result,
1301 size_t * len, struct inquire_s *inq)
1303 const char *p = line;
1304 gpg_error_t rc = 0;
1306 if (!strncmp (p, ".read", 5))
1307 rc = read_command (p + 5, result, len);
1308 else if (!strncmp (p, ".redir", 6))
1309 rc = redir_command (p + 6);
1310 else if (!strncmp (p, ".help", 5))
1311 rc = help_command (p + 5);
1312 else if (!strncmp (p, ".open", 5))
1313 rc = open_command (p + 5);
1314 else if (!strncmp (p, ".set", 4))
1315 rc = set_command (p + 4);
1316 else if (!strncmp (p, ".save", 5))
1317 rc = do_save_passwd_command (p + 5, 1);
1318 else if (!strncmp (p, ".passwd", 7))
1319 rc = do_save_passwd_command (p + 7, 0);
1320 else
1322 rc = pwmd_command (pwm, result, len, inquire_cb, inq, "%s", line);
1323 #ifdef HAVE_LIBREADLINE
1324 if (interactive)
1326 #endif
1327 reset_keyfiles ();
1328 #ifdef HAVE_LIBREADLINE
1330 #endif
1333 return FINISH (rc);
1336 #ifdef HAVE_LIBREADLINE
1337 static gpg_error_t
1338 do_interactive ()
1340 gpg_error_t rc;
1341 struct inquire_s *inq = NULL;
1343 rl_initialize ();
1344 rc = process_cmd ();
1345 if (rc)
1346 return rc;
1348 rc = set_inquire (STDIN_FILENO, NULL, &inq);
1349 if (rc)
1350 return rc;
1352 fprintf (stderr,
1353 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1354 print_help ();
1355 rl_event_hook = &interactive_hook;
1356 rl_set_keyboard_input_timeout (100000);
1358 for (;;)
1360 char *line;
1361 char *result = NULL;
1362 size_t len;
1364 rc = 0;
1365 line = readline ("pwm> ");
1366 if (interactive_error)
1368 free (line);
1369 rc = interactive_error;
1370 break;
1373 if (!line)
1375 rc = finalize ();
1376 if (!rc)
1377 break;
1379 if (gpg_err_code (rc) != GPG_ERR_CANCELED &&
1380 gpg_err_code (rc) != GPG_ERR_EOF)
1381 fprintf (stderr, "ERR %i: %s\n", rc, gpg_strerror (rc));
1383 continue;
1385 else if (!*line)
1387 free (line);
1388 continue;
1391 #ifdef HAVE_READLINE_HISTORY
1392 add_history (line);
1393 #endif
1394 rc = parse_dotcommand (line, &result, &len, inq);
1395 free (line);
1396 if (rc)
1398 char *tmp = NULL;
1400 if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
1401 (void) pwmd_command (pwm, &tmp, NULL, NULL, NULL,
1402 "GETINFO last_error");
1404 show_error (pwm, rc, tmp);
1405 pwmd_free (tmp);
1407 else if (result && len)
1408 printf ("%s%s", result, result[len - 1] != '\n' ? "\n" : "");
1410 pwmd_free (result);
1413 free_inquire (inq);
1414 return rc;
1416 #endif
1418 static gpg_error_t
1419 finalize ()
1421 gpg_error_t rc = 0;
1422 #ifdef HAVE_LIBREADLINE
1423 int quit = 0;
1425 if (interactive)
1427 int finished = 0;
1429 fprintf (stderr, "\n");
1433 char *p, buf[16];
1435 fprintf (stderr,
1437 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1438 p = fgets (buf, sizeof (buf), stdin);
1440 if (feof (stdin))
1442 clearerr (stdin);
1443 return GPG_ERR_EOF;
1446 switch (*p)
1448 case 'h':
1449 print_help ();
1450 break;
1451 case 'c':
1452 return GPG_ERR_CANCELED;
1453 case 'Q':
1454 return 0;
1455 case 'f':
1456 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1457 "CLEARCACHE %s", filename);
1458 if (rc)
1459 return rc;
1461 interactive_hook ();
1462 break;
1463 case 'S':
1464 quit = 1;
1465 case 's':
1466 save = 1;
1467 finished = 1;
1468 break;
1469 default:
1470 break;
1473 while (!finished);
1475 #endif
1477 if (save && !filename)
1479 fprintf (stderr,
1481 ("No filename was specified on the command line. Aborting.\n"));
1482 return GPG_ERR_CANCELED;
1485 if (save && filename)
1487 char *args =
1488 pwmd_strdup_printf ("%s %s%s %s%s %s",
1489 symmetric ? "--symmetric" : "",
1490 keyid ? "--keyid=" : "",
1491 keyid ? keyid : "",
1492 sign_keyid ? "--sign-keyid=" : "",
1493 sign_keyid ? sign_keyid : "",
1494 keyparams ? "--inquire-keyparam" : "");
1496 #ifdef HAVE_LIBREADLINE
1497 if (!quiet || interactive)
1499 #else
1500 if (!quiet)
1502 #endif
1503 fprintf (stderr, "\n");
1504 fprintf (stderr, N_("Saving changes ...\n"));
1507 rc = save_command (args);
1508 pwmd_free (args);
1511 #ifdef HAVE_LIBREADLINE
1512 if (interactive)
1513 return rc ? rc : quit ? 0 : GPG_ERR_CANCELED;
1514 #endif
1516 return rc;
1519 static void
1520 parse_status_ignore (char *str)
1522 size_t n = 0;
1523 char **p, *s;
1525 for (p = status_ignore; p && *p; p++)
1526 pwmd_free (*p);
1528 pwmd_free (status_ignore);
1529 status_ignore = NULL;
1530 if (!str || !*str)
1531 return;
1533 while ((s = strsep (&str, ",")))
1535 p = pwmd_realloc (status_ignore, (n + 2) * sizeof (char *));
1536 p[n++] = pwmd_strdup (s);
1537 p[n] = NULL;
1538 status_ignore = p;
1543 main (int argc, char *argv[])
1545 int connected = 0;
1546 gpg_error_t rc;
1547 int opt;
1548 char command[ASSUAN_LINELENGTH], *p = NULL;
1549 char *result = NULL;
1550 size_t len = 0;
1551 char *pinentry_path = NULL;
1552 char *display = NULL, *tty = NULL, *ttytype = NULL;
1553 char *lcctype = NULL, *lcmessages = NULL;
1554 int outfd = STDOUT_FILENO;
1555 FILE *outfp = stdout;
1556 FILE *inquirefp = stdin;
1557 int show_status = 1;
1558 char *clientname = "pwmc";
1559 char *inquire = NULL;
1560 char *inquire_line = NULL;
1561 int timeout = 0;
1562 #ifdef WITH_SSH
1563 int use_ssh_agent = 1;
1564 char *knownhosts = NULL;
1565 char *identity = NULL;
1566 #endif
1567 #ifdef WITH_GNUTLS
1568 char *cacert = NULL;
1569 char *clientcert = NULL;
1570 char *clientkey = NULL;
1571 char *prio = NULL;
1572 int tls_verify = 0;
1573 char *tls_fingerprint = NULL;
1574 #endif
1575 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1576 pwmd_socket_t socktype;
1577 long socket_timeout = 300;
1578 int connect_timeout = 120;
1579 #endif
1580 int lock_on_open = 1;
1581 long lock_timeout = 50;
1582 char *url = NULL;
1583 char *tmp = NULL;
1584 /* The order is important. */
1585 enum
1587 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1588 OPT_SOCKET_TIMEOUT, OPT_CONNECT_TIMEOUT,
1589 #endif
1590 #ifdef WITH_SSH
1591 OPT_USE_SSH_AGENT, OPT_IDENTITY, OPT_KNOWNHOSTS,
1592 #endif
1593 #ifdef WITH_GNUTLS
1594 OPT_CACERT, OPT_CLIENTCERT, OPT_CLIENTKEY, OPT_PRIORITY, OPT_VERIFY,
1595 OPT_SERVER_FP,
1596 #endif
1597 OPT_URL, OPT_LOCAL, OPT_TTYNAME, OPT_TTYTYPE,
1598 OPT_DISPLAY, OPT_LC_CTYPE, OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES,
1599 OPT_PINENTRY, OPT_KEYFILE, OPT_NEW_KEYFILE, OPT_SIGN_KEYFILE, OPT_NOLOCK,
1600 OPT_LOCK_TIMEOUT, OPT_SAVE, OPT_OUTPUT_FD, OPT_INQUIRE,
1601 OPT_INQUIRE_FD, OPT_INQUIRE_FILE, OPT_INQUIRE_LINE, OPT_NO_STATUS,
1602 OPT_STATUS_IGNORE,
1603 OPT_STATUSFD, OPT_NAME, OPT_VERSION, OPT_HELP, OPT_KEYID, OPT_SIGN_KEYID,
1604 OPT_SYMMETRIC, OPT_KEYPARAMS, OPT_NO_PINENTRY, OPT_QUIET,
1605 #ifdef HAVE_LIBREADLINE
1606 OPT_INTERACTIVE,
1607 #endif
1609 const struct option long_opts[] = {
1610 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1611 {"socket-timeout", 1, 0, 0},
1612 {"connect-timeout", 1, 0, 0},
1613 #endif
1615 #ifdef WITH_SSH
1616 {"no-ssh-agent", 0, 0, 0},
1617 {"identity", 1, 0, 'i'},
1618 {"knownhosts", 1, 0, 'k'},
1619 #endif
1620 #ifdef WITH_GNUTLS
1621 {"ca-cert", 1, 0, 0},
1622 {"client-cert", 1, 0, 0},
1623 {"client-key", 1, 0, 0},
1624 {"tls-priority", 1, 0, 0},
1625 {"tls-verify", 0, 0, 0},
1626 {"tls-fingerprint", 1, 0, 0},
1627 #endif
1628 {"url", 1, 0, 0},
1629 {"local-pinentry", 0, 0},
1630 {"ttyname", 1, 0, 'y'},
1631 {"ttytype", 1, 0, 't'},
1632 {"display", 1, 0, 'd'},
1633 {"lc-ctype", 1, 0, 0},
1634 {"lc-messages", 1, 0, 0},
1635 {"timeout", 1, 0, 0},
1636 {"tries", 1, 0, 0},
1637 {"pinentry", 1, 0, 0},
1638 {"key-file", 1, 0, 0},
1639 {"new-key-file", 1, 0, 0},
1640 {"sign-key-file", 1, 0, 0},
1641 {"no-lock", 0, 0, 0},
1642 {"lock-timeout", 1, 0, 0},
1643 {"save", 0, 0, 'S'},
1644 {"output-fd", 1, 0, 0},
1645 {"inquire", 1, 0, 0},
1646 {"inquire-fd", 1, 0, 0},
1647 {"inquire-file", 1, 0, 0},
1648 {"inquire-line", 1, 0, 'L'},
1649 {"no-status", 0, 0, 0},
1650 {"status-ignore", 1, 0, 0},
1651 {"status-fd", 1, 0, 0},
1652 {"name", 1, 0, 'n'},
1653 {"version", 0, 0, 0},
1654 {"help", 0, 0, 0},
1655 {"keyid", 1, 0, 0},
1656 {"sign-keyid", 1, 0, 0},
1657 {"symmetric", 0, 0, 0},
1658 {"key-params", 1, 0, 0},
1659 {"no-pinentry", 0, 0, 0},
1660 {"quiet", 0, 0, 0},
1661 #ifdef HAVE_LIBREADLINE
1662 {"interactive", 0, 0},
1663 #endif
1664 {0, 0, 0, 0}
1666 #ifdef WITH_SSH
1667 const char *optstring = "L:y:t:d:P:I:Sn:i:k:s";
1668 #else
1669 const char *optstring = "L:y:t:d:P:I:Sn:s";
1670 #endif
1671 int opt_index = 0;
1673 #ifdef ENABLE_NLS
1674 setlocale (LC_ALL, "");
1675 bindtextdomain ("libpwmd", LOCALEDIR);
1676 #endif
1678 tries = DEFAULT_PIN_TRIES;
1679 inquirefd = STDIN_FILENO;
1680 statusfd = STDERR_FILENO;
1681 statusfp = fdopen (statusfd, "w");
1682 tmp = pwmd_strdup (DEFAULT_STATUS_IGNORE);
1683 parse_status_ignore (tmp);
1684 pwmd_free (tmp);
1686 while ((opt =
1687 getopt_long (argc, argv, optstring, long_opts, &opt_index)) != -1)
1689 switch (opt)
1691 /* Handle long options without a short option part. */
1692 case 0:
1693 switch (opt_index)
1695 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1696 case OPT_SOCKET_TIMEOUT:
1697 socket_timeout = strtol (optarg, &p, 10);
1698 break;
1699 case OPT_CONNECT_TIMEOUT:
1700 connect_timeout = strtol (optarg, &p, 10);
1701 break;
1702 #endif
1703 #ifdef WITH_SSH
1704 case OPT_USE_SSH_AGENT:
1705 use_ssh_agent = 0;
1706 break;
1707 #endif
1708 #ifdef WITH_GNUTLS
1709 case OPT_CACERT:
1710 cacert = optarg;
1711 break;
1712 case OPT_CLIENTCERT:
1713 clientcert = optarg;
1714 break;
1715 case OPT_CLIENTKEY:
1716 clientkey = optarg;
1717 break;
1718 case OPT_PRIORITY:
1719 prio = optarg;
1720 break;
1721 case OPT_VERIFY:
1722 tls_verify = 1;
1723 break;
1724 case OPT_SERVER_FP:
1725 tls_fingerprint = optarg;
1726 break;
1727 #endif
1728 case OPT_SYMMETRIC:
1729 symmetric = 1;
1730 break;
1731 case OPT_KEYPARAMS:
1732 keyparams = optarg;
1733 break;
1734 case OPT_KEYFILE:
1735 keyfile = pwmd_strdup (optarg);
1736 break;
1737 case OPT_NEW_KEYFILE:
1738 new_keyfile = pwmd_strdup (optarg);
1739 break;
1740 case OPT_SIGN_KEYFILE:
1741 sign_keyfile = pwmd_strdup (optarg);
1742 break;
1743 case OPT_NOLOCK:
1744 lock_on_open = 0;
1745 break;
1746 case OPT_LOCK_TIMEOUT:
1747 lock_timeout = strtol (optarg, &p, 10);
1748 break;
1749 case OPT_URL:
1750 url = optarg;
1751 break;
1752 case OPT_LOCAL:
1753 local_pin = 1;
1754 break;
1755 case OPT_LC_CTYPE:
1756 lcctype = pwmd_strdup (optarg);
1757 break;
1758 case OPT_LC_MESSAGES:
1759 lcmessages = pwmd_strdup (optarg);
1760 break;
1761 case OPT_TIMEOUT:
1762 timeout = strtol (optarg, &p, 10);
1763 break;
1764 case OPT_TRIES:
1765 tries = strtol (optarg, &p, 10);
1766 break;
1767 case OPT_INQUIRE:
1768 inquire = escape (optarg);
1769 break;
1770 case OPT_INQUIRE_FD:
1771 inquirefd = strtol (optarg, &p, 10);
1772 if (!p)
1774 inquirefp = fdopen (inquirefd, "r");
1775 if (!inquirefp)
1776 err (EXIT_FAILURE, "%i", inquirefd);
1778 break;
1779 case OPT_INQUIRE_FILE:
1780 inquirefd = open (optarg, O_RDONLY);
1781 if (inquirefd == -1)
1782 err (EXIT_FAILURE, "%s", optarg);
1783 inquirefp = fdopen (inquirefd, "r");
1784 break;
1785 case OPT_OUTPUT_FD:
1786 outfd = strtol (optarg, &p, 10);
1787 if (!p || !*p)
1789 outfp = fdopen (outfd, "w");
1790 if (!outfp)
1791 err (EXIT_FAILURE, "%i", outfd);
1793 break;
1794 case OPT_NO_STATUS:
1795 show_status = 0;
1796 break;
1797 case OPT_STATUSFD:
1798 statusfd = strtol (optarg, &p, 10);
1799 if (!p || !*p)
1801 statusfp = fdopen (statusfd, "w");
1802 if (!statusfp)
1803 err (EXIT_FAILURE, "%i", statusfd);
1805 break;
1806 case OPT_STATUS_IGNORE:
1807 parse_status_ignore (optarg);
1808 break;
1809 case OPT_VERSION:
1810 printf ("%s (pwmc)\n\n"
1811 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015\n"
1812 "%s\n"
1813 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1814 "Compile-time features:\n"
1815 #ifdef HAVE_LIBREADLINE
1816 "+INTERACTIVE "
1817 #else
1818 "-INTERACTIVE "
1819 #endif
1820 #ifdef WITH_SSH
1821 "+SSH "
1822 #else
1823 "-SSH "
1824 #endif
1825 #ifdef WITH_GNUTLS
1826 "+GNUTLS "
1827 #else
1828 "-GNUTLS "
1829 #endif
1830 #ifdef WITH_PINENTRY
1831 "+PINENTRY "
1832 #else
1833 "-PINENTRY "
1834 #endif
1835 #ifdef WITH_QUALITY
1836 "+CRACK "
1837 #else
1838 "-CRACK "
1839 #endif
1840 #ifdef MEM_DEBUG
1841 "+MEM_DEBUG "
1842 #else
1843 "-MEM_DEBUG "
1844 #endif
1845 "\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1846 exit (EXIT_SUCCESS);
1847 case OPT_PINENTRY:
1848 pinentry_path = optarg;
1849 break;
1850 case OPT_HELP:
1851 usage (argv[0], EXIT_SUCCESS);
1852 case OPT_KEYID:
1853 keyid = optarg;
1854 break;
1855 case OPT_SIGN_KEYID:
1856 sign_keyid = optarg;
1857 break;
1858 case OPT_QUIET:
1859 quiet = 1;
1860 show_status = 0;
1861 break;
1862 case OPT_NO_PINENTRY:
1863 no_pinentry = 1;
1864 break;
1865 #ifdef HAVE_LIBREADLINE
1866 case OPT_INTERACTIVE:
1867 interactive = 1;
1868 break;
1869 #endif
1870 default:
1871 usage (argv[0], EXIT_FAILURE);
1874 if (p && *p)
1876 fprintf (stderr, N_("%s: invalid argument for option '--%s'\n"),
1877 argv[0], long_opts[opt_index].name);
1878 usage (argv[0], EXIT_FAILURE);
1881 break;
1882 #ifdef WITH_SSH
1883 case 'i':
1884 identity = optarg;
1885 break;
1886 case 'k':
1887 knownhosts = optarg;
1888 break;
1889 #endif
1890 case 'L':
1891 inquire_line = optarg;
1892 break;
1893 case 'y':
1894 tty = optarg;
1895 break;
1896 case 't':
1897 ttytype = optarg;
1898 break;
1899 case 'd':
1900 display = optarg;
1901 break;
1902 case 'S':
1903 save = 1;
1904 break;
1905 case 'n':
1906 clientname = optarg;
1907 break;
1908 default:
1909 usage (argv[0], EXIT_FAILURE);
1913 #ifdef HAVE_LIBREADLINE
1914 if (interactive && !isatty (STDIN_FILENO))
1915 usage (argv[0], EXIT_FAILURE);
1916 else if (isatty (STDIN_FILENO) && !inquire && !inquire_line)
1917 interactive = 1;
1918 #endif
1920 filename = argv[optind];
1921 pwmd_init ();
1922 rc = pwmd_new (clientname, &pwm);
1923 if (rc)
1924 goto done;
1926 pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
1927 if (!quiet)
1928 fprintf (stderr, N_("Connecting ...\n"));
1930 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1931 socktype = is_remote_url (url);
1932 if (socktype != PWMD_SOCKET_LOCAL)
1934 local_pin = 1;
1935 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1936 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, connect_timeout);
1937 if (rc)
1938 goto done;
1939 #endif
1941 if (socktype == PWMD_SOCKET_SSH)
1943 #ifdef WITH_SSH
1944 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_CB, knownhost_cb);
1945 if (rc)
1946 goto done;
1948 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_DATA, clientname);
1949 if (rc)
1950 goto done;
1952 if (!getenv ("SSH_AUTH_SOCK") || identity)
1953 use_ssh_agent = 0;
1955 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_AGENT, use_ssh_agent);
1956 if (rc)
1957 goto done;
1959 rc = pwmd_connect (pwm, url, identity, knownhosts);
1960 #endif
1962 #ifdef WITH_GNUTLS
1963 else
1965 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_VERIFY, tls_verify);
1966 if (rc)
1967 goto done;
1969 rc = pwmd_connect (pwm, url, clientcert, clientkey, cacert, prio,
1970 tls_fingerprint);
1972 #endif
1974 else
1975 rc = pwmd_connect (pwm, url);
1976 #else
1977 rc = pwmd_connect (pwm, url);
1978 #endif
1979 if (rc)
1980 goto done;
1982 if (!quiet)
1983 fprintf (stderr, N_("Connected.\n"));
1985 connected = 1;
1986 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1987 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, socket_timeout);
1988 if (rc)
1989 goto done;
1990 #endif
1992 if (lock_timeout)
1994 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1995 "OPTION LOCK-TIMEOUT=%li", lock_timeout);
1996 if (rc)
1997 goto done;
2000 if (lock_on_open)
2002 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCK_ON_OPEN, 1);
2003 if (rc)
2004 goto done;
2007 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, NULL, NULL);
2008 if (rc)
2009 goto done;
2011 if (timeout > 0)
2013 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
2014 if (rc)
2015 goto done;
2018 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
2019 if (rc)
2020 goto done;
2022 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY,
2023 (local_pin || keyfile || new_keyfile || sign_keyfile));
2024 if (rc)
2025 goto done;
2027 if (pinentry_path)
2029 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
2030 if (rc)
2031 goto done;
2034 if (display)
2036 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
2037 if (rc)
2038 goto done;
2041 if (tty)
2043 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, tty);
2044 if (rc)
2045 goto done;
2048 if (ttytype)
2050 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
2051 if (rc)
2052 goto done;
2055 if (lcctype)
2057 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
2058 if (rc)
2059 goto done;
2062 if (lcmessages)
2064 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES, lcmessages);
2065 if (rc)
2066 goto done;
2069 if (show_status)
2071 rc = pwmd_setopt (pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
2072 if (rc)
2073 goto done;
2076 if (filename)
2078 rc = open_command (filename);
2079 if (rc)
2080 goto done;
2083 #ifdef HAVE_LIBREADLINE
2084 if (interactive)
2086 rc = do_interactive ();
2087 result = NULL;
2088 goto do_exit;
2090 #endif
2092 if (inquire)
2094 struct inquire_s *inq = NULL;
2096 rc = set_inquire (inquirefd, inquire_line, &inq);
2097 if (!rc)
2098 rc = pwmd_command (pwm, &result, &len, inquire_cb, inq, "%s", inquire);
2100 free_inquire (inq);
2101 goto done;
2104 if (fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1)
2106 rc = gpg_error_from_errno (errno);
2107 goto done;
2110 ssize_t n;
2112 for (;;)
2114 rc = process_cmd ();
2116 if (rc)
2117 goto done;
2119 n = read (STDIN_FILENO, command, sizeof (command)-1);
2120 if (n == -1)
2122 if (errno == EAGAIN)
2124 usleep (100000);
2125 continue;
2128 rc = gpg_error_from_errno (errno);
2129 goto done;
2131 else if (!n)
2132 goto done;
2134 p = command;
2135 command[n] = 0;
2136 break;
2139 if (!p || !*p || !strcasecmp (p, "BYE"))
2140 goto done;
2143 struct inquire_s *inq = NULL;
2144 rc = set_inquire (inquirefd, inquire_line, &inq);
2145 if (!rc)
2147 rc = parse_dotcommand (command, &result, &len, inq);
2148 free_inquire (inq);
2151 if (rc)
2152 goto done;
2154 done:
2155 if (result)
2157 fwrite (result, 1, result[len - 1] == 0 ? len - 1 : len, outfp);
2158 fflush (outfp);
2159 pwmd_free (result);
2162 result = NULL;
2163 if (!rc)
2164 rc = finalize ();
2165 else if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
2166 (void) pwmd_command (pwm, &result, NULL, NULL, NULL,
2167 "GETINFO last_error");
2169 #ifdef HAVE_LIBREADLINE
2170 do_exit:
2171 #endif
2172 memset (command, 0, sizeof (command));
2174 if (rc && !quiet)
2175 show_error (pwm, rc, result);
2177 pwmd_close (pwm);
2178 reset_keyfiles ();
2179 pwmd_deinit ();
2180 pwmd_free (result);
2181 parse_status_ignore (NULL);
2182 if (connected && !quiet)
2183 fprintf (stderr, N_("Connection closed.\n"));
2185 exit (rc ? EXIT_FAILURE : EXIT_SUCCESS);