pwmc: change --key-params to use a filename.
[libpwmd.git] / src / pwmc.c
blob6ffe892e2a82c339df9532ac03d3bcc36cbfac33
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 reset_keyfiles ();
1093 free_inquire (inq);
1094 return rc;
1097 static gpg_error_t
1098 set_command (const char *line)
1100 gpg_error_t rc = 0;
1101 char name[256] = { 0 };
1102 char value[512] = { 0 };
1103 char *namep;
1104 char *valuep;
1105 const char *p = line;
1107 while (p && *p && isspace (*p))
1108 p++;
1110 namep = parse_arg (p, name, sizeof (name));
1111 if (!namep || !*namep)
1113 fprintf (stderr, N_("Usage: .set help | <name> [<value>]\n"));
1114 return GPG_ERR_SYNTAX;
1117 p += strlen (namep);
1118 while (p && *p && isspace (*p))
1119 p++;
1121 valuep = parse_arg (p, value, sizeof (value));
1123 if (!strcmp (name, "keyfile") || !strcmp (name, "new-keyfile")
1124 || !strcmp (name, "sign-keyfile"))
1126 int is_newkeyfile = 1;
1127 int sign = !strcmp (name, "sign-keyfile");
1129 if (!strcmp (name, "keyfile") || sign)
1130 is_newkeyfile = 0;
1132 if (is_newkeyfile)
1134 pwmd_free (new_keyfile);
1135 new_keyfile = NULL;
1137 else if (sign)
1139 pwmd_free (sign_keyfile);
1140 sign_keyfile = NULL;
1142 else
1144 pwmd_free (keyfile);
1145 keyfile = NULL;
1148 if (!rc && *valuep)
1150 if (is_newkeyfile)
1151 new_keyfile = pwmd_strdup (value);
1152 else if (sign)
1153 sign_keyfile = pwmd_strdup (value);
1154 else
1155 keyfile = pwmd_strdup (value);
1157 if (!rc)
1159 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 1);
1160 if (!rc)
1161 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1164 else if (!local_pin && !no_pinentry)
1166 pwmd_socket_t t;
1168 pwmd_socket_type (pwm, &t);
1169 if (t == PWMD_SOCKET_LOCAL)
1171 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 0);
1172 if (!rc)
1173 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1177 else if (!strcmp(name, "pinentry-timeout"))
1179 char *e = NULL;
1180 int n = strtol(valuep, &e, 10);
1182 if (e && *e)
1183 return gpg_error (GPG_ERR_INV_VALUE);
1185 if (!*valuep)
1186 n = DEFAULT_PIN_TIMEOUT;
1188 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, n);
1190 else if (!strcmp (name, "help"))
1192 fprintf (stderr,
1194 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1195 "delimited. When no value is specified the option is unset.\n\n"
1196 "keyfile [<filename>]\n"
1197 " set or unset the keyfile to be used when a passphrase is required (*)\n"
1198 "\n"
1199 "new-keyfile [<filename>]\n"
1200 " set or unset the keyfile to be used when a new passphrase is required (*)\n"
1201 "\n"
1202 "sign-keyfile [<filename>]\n"
1203 " set or unset the keyfile to be used when a passphrase is required for\n"
1204 " signing (symmetric) (*)\n"
1205 "\n"
1206 "pinentry-timeout <seconds>\n"
1207 " the amount of seconds before pinentry gives up waiting for input\n"
1208 "\n"
1209 "* = the next protocol command will unset this value\n"
1212 else
1213 rc = GPG_ERR_UNKNOWN_OPTION;
1215 return rc;
1218 static gpg_error_t
1219 save_command (const char *line)
1221 struct inquire_s *inq = NULL;
1222 gpg_error_t rc;
1224 #ifdef HAVE_LIBREADLINE
1225 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1226 #else
1227 rc = set_inquire (-1, NULL, &inq);
1228 #endif
1229 if (rc)
1230 return rc;
1232 if (new_keyfile || keyfile || sign_keyfile)
1234 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1235 if (!rc)
1236 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 1);
1238 else
1240 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1241 if (!rc)
1242 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1245 if (!rc)
1246 rc = pwmd_save (pwm, line, inquire_cb, inq);
1248 reset_keyfiles ();
1249 free_inquire (inq);
1250 return rc;
1253 static gpg_error_t
1254 do_save_passwd_command (const char *line, int save)
1256 struct inquire_s *inq = NULL;
1257 gpg_error_t rc;
1259 #ifdef HAVE_LIBREADLINE
1260 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1261 #else
1262 rc = set_inquire (-1, NULL, &inq);
1263 #endif
1264 if (rc)
1265 return rc;
1267 if (new_keyfile || keyfile || sign_keyfile)
1269 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1270 if (!rc)
1271 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 1);
1273 else
1275 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1276 if (!rc)
1277 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1280 if (!rc)
1282 if (save)
1283 rc = pwmd_save (pwm, line, inquire_cb, inq);
1284 else
1285 rc = pwmd_passwd (pwm, line, inquire_cb, inq);
1288 reset_keyfiles ();
1289 free_inquire (inq);
1290 return rc;
1293 static gpg_error_t
1294 parse_dotcommand (const char *line, char **result,
1295 size_t * len, struct inquire_s *inq)
1297 const char *p = line;
1298 gpg_error_t rc = 0;
1300 if (!strncmp (p, ".read", 5))
1301 rc = read_command (p + 5, result, len);
1302 else if (!strncmp (p, ".redir", 6))
1303 rc = redir_command (p + 6);
1304 else if (!strncmp (p, ".help", 5))
1305 rc = help_command (p + 5);
1306 else if (!strncmp (p, ".open", 5))
1307 rc = open_command (p + 5);
1308 else if (!strncmp (p, ".set", 4))
1309 rc = set_command (p + 4);
1310 else if (!strncmp (p, ".save", 5))
1311 rc = do_save_passwd_command (p + 5, 1);
1312 else if (!strncmp (p, ".passwd", 7))
1313 rc = do_save_passwd_command (p + 7, 0);
1314 else
1316 rc = pwmd_command (pwm, result, len, inquire_cb, inq, "%s", line);
1317 #ifdef HAVE_LIBREADLINE
1318 if (interactive)
1320 #endif
1321 reset_keyfiles ();
1322 #ifdef HAVE_LIBREADLINE
1324 #endif
1327 return FINISH (rc);
1330 #ifdef HAVE_LIBREADLINE
1331 static gpg_error_t
1332 do_interactive ()
1334 gpg_error_t rc;
1335 struct inquire_s *inq = NULL;
1337 rl_initialize ();
1338 rc = process_cmd ();
1339 if (rc)
1340 return rc;
1342 rc = set_inquire (STDIN_FILENO, NULL, &inq);
1343 if (rc)
1344 return rc;
1346 fprintf (stderr,
1347 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1348 print_help ();
1349 rl_event_hook = &interactive_hook;
1350 rl_set_keyboard_input_timeout (100000);
1352 for (;;)
1354 char *line;
1355 char *result = NULL;
1356 size_t len;
1358 rc = 0;
1359 line = readline ("pwm> ");
1360 if (interactive_error)
1362 free (line);
1363 rc = interactive_error;
1364 break;
1367 if (!line)
1369 rc = finalize ();
1370 if (!rc)
1371 break;
1373 if (gpg_err_code (rc) != GPG_ERR_CANCELED &&
1374 gpg_err_code (rc) != GPG_ERR_EOF)
1375 fprintf (stderr, "ERR %i: %s\n", rc, gpg_strerror (rc));
1377 continue;
1379 else if (!*line)
1381 free (line);
1382 continue;
1385 #ifdef HAVE_READLINE_HISTORY
1386 add_history (line);
1387 #endif
1388 rc = parse_dotcommand (line, &result, &len, inq);
1389 free (line);
1390 if (rc)
1392 char *tmp = NULL;
1394 if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
1395 (void) pwmd_command (pwm, &tmp, NULL, NULL, NULL,
1396 "GETINFO last_error");
1398 show_error (pwm, rc, tmp);
1399 pwmd_free (tmp);
1401 else if (result && len)
1402 printf ("%s%s", result, result[len - 1] != '\n' ? "\n" : "");
1404 pwmd_free (result);
1407 free_inquire (inq);
1408 return rc;
1410 #endif
1412 static gpg_error_t
1413 finalize ()
1415 gpg_error_t rc = 0;
1416 #ifdef HAVE_LIBREADLINE
1417 int quit = 0;
1419 if (interactive)
1421 int finished = 0;
1423 fprintf (stderr, "\n");
1427 char *p, buf[16];
1429 fprintf (stderr,
1431 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1432 p = fgets (buf, sizeof (buf), stdin);
1434 if (feof (stdin))
1436 clearerr (stdin);
1437 return GPG_ERR_EOF;
1440 switch (*p)
1442 case 'h':
1443 print_help ();
1444 break;
1445 case 'c':
1446 return GPG_ERR_CANCELED;
1447 case 'Q':
1448 return 0;
1449 case 'f':
1450 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1451 "CLEARCACHE %s", filename);
1452 if (rc)
1453 return rc;
1455 interactive_hook ();
1456 break;
1457 case 'S':
1458 quit = 1;
1459 case 's':
1460 save = 1;
1461 finished = 1;
1462 break;
1463 default:
1464 break;
1467 while (!finished);
1469 #endif
1471 if (save && !filename)
1473 fprintf (stderr,
1475 ("No filename was specified on the command line. Aborting.\n"));
1476 return GPG_ERR_CANCELED;
1479 if (save && filename)
1481 char *args =
1482 pwmd_strdup_printf ("%s %s%s %s%s %s",
1483 symmetric ? "--symmetric" : "",
1484 keyid ? "--keyid=" : "",
1485 keyid ? keyid : "",
1486 sign_keyid ? "--sign-keyid=" : "",
1487 sign_keyid ? sign_keyid : "",
1488 keyparams ? "--inquire-keyparam" : "");
1490 #ifdef HAVE_LIBREADLINE
1491 if (!quiet || interactive)
1493 #else
1494 if (!quiet)
1496 #endif
1497 fprintf (stderr, "\n");
1498 fprintf (stderr, N_("Saving changes ...\n"));
1501 rc = save_command (args);
1502 pwmd_free (args);
1505 #ifdef HAVE_LIBREADLINE
1506 if (interactive)
1507 return rc ? rc : quit ? 0 : GPG_ERR_CANCELED;
1508 #endif
1510 return rc;
1513 static void
1514 parse_status_ignore (char *str)
1516 size_t n = 0;
1517 char **p, *s;
1519 for (p = status_ignore; p && *p; p++)
1520 pwmd_free (*p);
1522 pwmd_free (status_ignore);
1523 status_ignore = NULL;
1524 if (!str || !*str)
1525 return;
1527 while ((s = strsep (&str, ",")))
1529 p = pwmd_realloc (status_ignore, (n + 2) * sizeof (char *));
1530 p[n++] = pwmd_strdup (s);
1531 p[n] = NULL;
1532 status_ignore = p;
1537 main (int argc, char *argv[])
1539 int connected = 0;
1540 gpg_error_t rc;
1541 int opt;
1542 char command[ASSUAN_LINELENGTH], *p = NULL;
1543 char *result = NULL;
1544 size_t len = 0;
1545 char *pinentry_path = NULL;
1546 char *display = NULL, *tty = NULL, *ttytype = NULL;
1547 char *lcctype = NULL, *lcmessages = NULL;
1548 int outfd = STDOUT_FILENO;
1549 FILE *outfp = stdout;
1550 FILE *inquirefp = stdin;
1551 int show_status = 1;
1552 char *clientname = "pwmc";
1553 char *inquire = NULL;
1554 char *inquire_line = NULL;
1555 int timeout = 0;
1556 #ifdef WITH_SSH
1557 int use_ssh_agent = 1;
1558 char *knownhosts = NULL;
1559 char *identity = NULL;
1560 #endif
1561 #ifdef WITH_GNUTLS
1562 char *cacert = NULL;
1563 char *clientcert = NULL;
1564 char *clientkey = NULL;
1565 char *prio = NULL;
1566 int tls_verify = 0;
1567 char *tls_fingerprint = NULL;
1568 #endif
1569 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1570 pwmd_socket_t socktype;
1571 long socket_timeout = 300;
1572 int connect_timeout = 120;
1573 #endif
1574 int lock_on_open = 1;
1575 long lock_timeout = 50;
1576 char *url = NULL;
1577 char *tmp = NULL;
1578 /* The order is important. */
1579 enum
1581 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1582 OPT_SOCKET_TIMEOUT, OPT_CONNECT_TIMEOUT,
1583 #endif
1584 #ifdef WITH_SSH
1585 OPT_USE_SSH_AGENT, OPT_IDENTITY, OPT_KNOWNHOSTS,
1586 #endif
1587 #ifdef WITH_GNUTLS
1588 OPT_CACERT, OPT_CLIENTCERT, OPT_CLIENTKEY, OPT_PRIORITY, OPT_VERIFY,
1589 OPT_SERVER_FP,
1590 #endif
1591 OPT_URL, OPT_LOCAL, OPT_TTYNAME, OPT_TTYTYPE,
1592 OPT_DISPLAY, OPT_LC_CTYPE, OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES,
1593 OPT_PINENTRY, OPT_KEYFILE, OPT_NEW_KEYFILE, OPT_SIGN_KEYFILE, OPT_NOLOCK,
1594 OPT_LOCK_TIMEOUT, OPT_SAVE, OPT_OUTPUT_FD, OPT_INQUIRE,
1595 OPT_INQUIRE_FD, OPT_INQUIRE_FILE, OPT_INQUIRE_LINE, OPT_NO_STATUS,
1596 OPT_STATUS_IGNORE,
1597 OPT_STATUSFD, OPT_NAME, OPT_VERSION, OPT_HELP, OPT_KEYID, OPT_SIGN_KEYID,
1598 OPT_SYMMETRIC, OPT_KEYPARAMS, OPT_NO_PINENTRY, OPT_QUIET,
1599 #ifdef HAVE_LIBREADLINE
1600 OPT_INTERACTIVE,
1601 #endif
1603 const struct option long_opts[] = {
1604 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1605 {"socket-timeout", 1, 0, 0},
1606 {"connect-timeout", 1, 0, 0},
1607 #endif
1609 #ifdef WITH_SSH
1610 {"no-ssh-agent", 0, 0, 0},
1611 {"identity", 1, 0, 'i'},
1612 {"knownhosts", 1, 0, 'k'},
1613 #endif
1614 #ifdef WITH_GNUTLS
1615 {"ca-cert", 1, 0, 0},
1616 {"client-cert", 1, 0, 0},
1617 {"client-key", 1, 0, 0},
1618 {"tls-priority", 1, 0, 0},
1619 {"tls-verify", 0, 0, 0},
1620 {"tls-fingerprint", 1, 0, 0},
1621 #endif
1622 {"url", 1, 0, 0},
1623 {"local-pinentry", 0, 0},
1624 {"ttyname", 1, 0, 'y'},
1625 {"ttytype", 1, 0, 't'},
1626 {"display", 1, 0, 'd'},
1627 {"lc-ctype", 1, 0, 0},
1628 {"lc-messages", 1, 0, 0},
1629 {"timeout", 1, 0, 0},
1630 {"tries", 1, 0, 0},
1631 {"pinentry", 1, 0, 0},
1632 {"key-file", 1, 0, 0},
1633 {"new-key-file", 1, 0, 0},
1634 {"sign-key-file", 1, 0, 0},
1635 {"no-lock", 0, 0, 0},
1636 {"lock-timeout", 1, 0, 0},
1637 {"save", 0, 0, 'S'},
1638 {"output-fd", 1, 0, 0},
1639 {"inquire", 1, 0, 0},
1640 {"inquire-fd", 1, 0, 0},
1641 {"inquire-file", 1, 0, 0},
1642 {"inquire-line", 1, 0, 'L'},
1643 {"no-status", 0, 0, 0},
1644 {"status-ignore", 1, 0, 0},
1645 {"status-fd", 1, 0, 0},
1646 {"name", 1, 0, 'n'},
1647 {"version", 0, 0, 0},
1648 {"help", 0, 0, 0},
1649 {"keyid", 1, 0, 0},
1650 {"sign-keyid", 1, 0, 0},
1651 {"symmetric", 0, 0, 0},
1652 {"key-params", 1, 0, 0},
1653 {"no-pinentry", 0, 0, 0},
1654 {"quiet", 0, 0, 0},
1655 #ifdef HAVE_LIBREADLINE
1656 {"interactive", 0, 0},
1657 #endif
1658 {0, 0, 0, 0}
1660 #ifdef WITH_SSH
1661 const char *optstring = "L:y:t:d:P:I:Sn:i:k:s";
1662 #else
1663 const char *optstring = "L:y:t:d:P:I:Sn:s";
1664 #endif
1665 int opt_index = 0;
1667 #ifdef ENABLE_NLS
1668 setlocale (LC_ALL, "");
1669 bindtextdomain ("libpwmd", LOCALEDIR);
1670 #endif
1672 tries = DEFAULT_PIN_TRIES;
1673 inquirefd = STDIN_FILENO;
1674 statusfd = STDERR_FILENO;
1675 statusfp = fdopen (statusfd, "w");
1676 tmp = pwmd_strdup (DEFAULT_STATUS_IGNORE);
1677 parse_status_ignore (tmp);
1678 pwmd_free (tmp);
1680 while ((opt =
1681 getopt_long (argc, argv, optstring, long_opts, &opt_index)) != -1)
1683 switch (opt)
1685 /* Handle long options without a short option part. */
1686 case 0:
1687 switch (opt_index)
1689 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1690 case OPT_SOCKET_TIMEOUT:
1691 socket_timeout = strtol (optarg, &p, 10);
1692 break;
1693 case OPT_CONNECT_TIMEOUT:
1694 connect_timeout = strtol (optarg, &p, 10);
1695 break;
1696 #endif
1697 #ifdef WITH_SSH
1698 case OPT_USE_SSH_AGENT:
1699 use_ssh_agent = 0;
1700 break;
1701 #endif
1702 #ifdef WITH_GNUTLS
1703 case OPT_CACERT:
1704 cacert = optarg;
1705 break;
1706 case OPT_CLIENTCERT:
1707 clientcert = optarg;
1708 break;
1709 case OPT_CLIENTKEY:
1710 clientkey = optarg;
1711 break;
1712 case OPT_PRIORITY:
1713 prio = optarg;
1714 break;
1715 case OPT_VERIFY:
1716 tls_verify = 1;
1717 break;
1718 case OPT_SERVER_FP:
1719 tls_fingerprint = optarg;
1720 break;
1721 #endif
1722 case OPT_SYMMETRIC:
1723 symmetric = 1;
1724 break;
1725 case OPT_KEYPARAMS:
1726 keyparams = optarg;
1727 break;
1728 case OPT_KEYFILE:
1729 keyfile = pwmd_strdup (optarg);
1730 break;
1731 case OPT_NEW_KEYFILE:
1732 new_keyfile = pwmd_strdup (optarg);
1733 break;
1734 case OPT_SIGN_KEYFILE:
1735 sign_keyfile = pwmd_strdup (optarg);
1736 break;
1737 case OPT_NOLOCK:
1738 lock_on_open = 0;
1739 break;
1740 case OPT_LOCK_TIMEOUT:
1741 lock_timeout = strtol (optarg, &p, 10);
1742 break;
1743 case OPT_URL:
1744 url = optarg;
1745 break;
1746 case OPT_LOCAL:
1747 local_pin = 1;
1748 break;
1749 case OPT_LC_CTYPE:
1750 lcctype = pwmd_strdup (optarg);
1751 break;
1752 case OPT_LC_MESSAGES:
1753 lcmessages = pwmd_strdup (optarg);
1754 break;
1755 case OPT_TIMEOUT:
1756 timeout = strtol (optarg, &p, 10);
1757 break;
1758 case OPT_TRIES:
1759 tries = strtol (optarg, &p, 10);
1760 break;
1761 case OPT_INQUIRE:
1762 inquire = escape (optarg);
1763 break;
1764 case OPT_INQUIRE_FD:
1765 inquirefd = strtol (optarg, &p, 10);
1766 if (!p)
1768 inquirefp = fdopen (inquirefd, "r");
1769 if (!inquirefp)
1770 err (EXIT_FAILURE, "%i", inquirefd);
1772 break;
1773 case OPT_INQUIRE_FILE:
1774 inquirefd = open (optarg, O_RDONLY);
1775 if (inquirefd == -1)
1776 err (EXIT_FAILURE, "%s", optarg);
1777 inquirefp = fdopen (inquirefd, "r");
1778 break;
1779 case OPT_OUTPUT_FD:
1780 outfd = strtol (optarg, &p, 10);
1781 if (!p || !*p)
1783 outfp = fdopen (outfd, "w");
1784 if (!outfp)
1785 err (EXIT_FAILURE, "%i", outfd);
1787 break;
1788 case OPT_NO_STATUS:
1789 show_status = 0;
1790 break;
1791 case OPT_STATUSFD:
1792 statusfd = strtol (optarg, &p, 10);
1793 if (!p || !*p)
1795 statusfp = fdopen (statusfd, "w");
1796 if (!statusfp)
1797 err (EXIT_FAILURE, "%i", statusfd);
1799 break;
1800 case OPT_STATUS_IGNORE:
1801 parse_status_ignore (optarg);
1802 break;
1803 case OPT_VERSION:
1804 printf ("%s (pwmc)\n\n"
1805 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015\n"
1806 "%s\n"
1807 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1808 "Compile-time features:\n"
1809 #ifdef HAVE_LIBREADLINE
1810 "+INTERACTIVE "
1811 #else
1812 "-INTERACTIVE "
1813 #endif
1814 #ifdef WITH_SSH
1815 "+SSH "
1816 #else
1817 "-SSH "
1818 #endif
1819 #ifdef WITH_GNUTLS
1820 "+GNUTLS "
1821 #else
1822 "-GNUTLS "
1823 #endif
1824 #ifdef WITH_PINENTRY
1825 "+PINENTRY "
1826 #else
1827 "-PINENTRY "
1828 #endif
1829 #ifdef WITH_QUALITY
1830 "+CRACK "
1831 #else
1832 "-CRACK "
1833 #endif
1834 #ifdef MEM_DEBUG
1835 "+MEM_DEBUG "
1836 #else
1837 "-MEM_DEBUG "
1838 #endif
1839 "\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1840 exit (EXIT_SUCCESS);
1841 case OPT_PINENTRY:
1842 pinentry_path = optarg;
1843 break;
1844 case OPT_HELP:
1845 usage (argv[0], EXIT_SUCCESS);
1846 case OPT_KEYID:
1847 keyid = optarg;
1848 break;
1849 case OPT_SIGN_KEYID:
1850 sign_keyid = optarg;
1851 break;
1852 case OPT_QUIET:
1853 quiet = 1;
1854 show_status = 0;
1855 break;
1856 case OPT_NO_PINENTRY:
1857 no_pinentry = 1;
1858 break;
1859 #ifdef HAVE_LIBREADLINE
1860 case OPT_INTERACTIVE:
1861 interactive = 1;
1862 break;
1863 #endif
1864 default:
1865 usage (argv[0], EXIT_FAILURE);
1868 if (p && *p)
1870 fprintf (stderr, N_("%s: invalid argument for option '--%s'\n"),
1871 argv[0], long_opts[opt_index].name);
1872 usage (argv[0], EXIT_FAILURE);
1875 break;
1876 #ifdef WITH_SSH
1877 case 'i':
1878 identity = optarg;
1879 break;
1880 case 'k':
1881 knownhosts = optarg;
1882 break;
1883 #endif
1884 case 'L':
1885 inquire_line = optarg;
1886 break;
1887 case 'y':
1888 tty = optarg;
1889 break;
1890 case 't':
1891 ttytype = optarg;
1892 break;
1893 case 'd':
1894 display = optarg;
1895 break;
1896 case 'S':
1897 save = 1;
1898 break;
1899 case 'n':
1900 clientname = optarg;
1901 break;
1902 default:
1903 usage (argv[0], EXIT_FAILURE);
1907 #ifdef HAVE_LIBREADLINE
1908 if (interactive && !isatty (STDIN_FILENO))
1909 usage (argv[0], EXIT_FAILURE);
1910 else if (isatty (STDIN_FILENO) && !inquire && !inquire_line)
1911 interactive = 1;
1912 #endif
1914 filename = argv[optind];
1915 pwmd_init ();
1916 rc = pwmd_new (clientname, &pwm);
1917 if (rc)
1918 goto done;
1920 pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
1921 if (!quiet)
1922 fprintf (stderr, N_("Connecting ...\n"));
1924 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1925 socktype = is_remote_url (url);
1926 if (socktype != PWMD_SOCKET_LOCAL)
1928 local_pin = 1;
1929 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1930 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, connect_timeout);
1931 if (rc)
1932 goto done;
1933 #endif
1935 if (socktype == PWMD_SOCKET_SSH)
1937 #ifdef WITH_SSH
1938 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_CB, knownhost_cb);
1939 if (rc)
1940 goto done;
1942 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_DATA, clientname);
1943 if (rc)
1944 goto done;
1946 if (!getenv ("SSH_AUTH_SOCK") || identity)
1947 use_ssh_agent = 0;
1949 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_AGENT, use_ssh_agent);
1950 if (rc)
1951 goto done;
1953 rc = pwmd_connect (pwm, url, identity, knownhosts);
1954 #endif
1956 #ifdef WITH_GNUTLS
1957 else
1959 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_VERIFY, tls_verify);
1960 if (rc)
1961 goto done;
1963 rc = pwmd_connect (pwm, url, clientcert, clientkey, cacert, prio,
1964 tls_fingerprint);
1966 #endif
1968 else
1969 rc = pwmd_connect (pwm, url);
1970 #else
1971 rc = pwmd_connect (pwm, url);
1972 #endif
1973 if (rc)
1974 goto done;
1976 if (!quiet)
1977 fprintf (stderr, N_("Connected.\n"));
1979 connected = 1;
1980 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1981 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, socket_timeout);
1982 if (rc)
1983 goto done;
1984 #endif
1986 if (lock_timeout)
1988 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1989 "OPTION LOCK-TIMEOUT=%li", lock_timeout);
1990 if (rc)
1991 goto done;
1994 if (lock_on_open)
1996 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCK_ON_OPEN, 1);
1997 if (rc)
1998 goto done;
2001 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, NULL, NULL);
2002 if (rc)
2003 goto done;
2005 if (timeout > 0)
2007 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
2008 if (rc)
2009 goto done;
2012 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
2013 if (rc)
2014 goto done;
2016 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY,
2017 (local_pin || keyfile || new_keyfile || sign_keyfile));
2018 if (rc)
2019 goto done;
2021 if (pinentry_path)
2023 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
2024 if (rc)
2025 goto done;
2028 if (display)
2030 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
2031 if (rc)
2032 goto done;
2035 if (tty)
2037 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, tty);
2038 if (rc)
2039 goto done;
2042 if (ttytype)
2044 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
2045 if (rc)
2046 goto done;
2049 if (lcctype)
2051 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
2052 if (rc)
2053 goto done;
2056 if (lcmessages)
2058 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES, lcmessages);
2059 if (rc)
2060 goto done;
2063 if (show_status)
2065 rc = pwmd_setopt (pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
2066 if (rc)
2067 goto done;
2070 if (filename)
2072 rc = open_command (filename);
2073 if (rc)
2074 goto done;
2077 #ifdef HAVE_LIBREADLINE
2078 if (interactive)
2080 rc = do_interactive ();
2081 result = NULL;
2082 goto do_exit;
2084 #endif
2086 if (inquire)
2088 struct inquire_s *inq = NULL;
2090 rc = set_inquire (inquirefd, inquire_line, &inq);
2091 if (!rc)
2092 rc = pwmd_command (pwm, &result, &len, inquire_cb, inq, "%s", inquire);
2094 free_inquire (inq);
2095 goto done;
2098 if (fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1)
2100 rc = gpg_error_from_errno (errno);
2101 goto done;
2104 ssize_t n;
2106 for (;;)
2108 rc = process_cmd ();
2110 if (rc)
2111 goto done;
2113 n = read (STDIN_FILENO, command, sizeof (command)-1);
2114 if (n == -1)
2116 if (errno == EAGAIN)
2118 usleep (100000);
2119 continue;
2122 rc = gpg_error_from_errno (errno);
2123 goto done;
2125 else if (!n)
2126 goto done;
2128 p = command;
2129 command[n] = 0;
2130 break;
2133 if (!p || !*p || !strcasecmp (p, "BYE"))
2134 goto done;
2137 struct inquire_s *inq = NULL;
2138 rc = set_inquire (inquirefd, inquire_line, &inq);
2139 if (!rc)
2141 rc = parse_dotcommand (command, &result, &len, inq);
2142 free_inquire (inq);
2145 if (rc)
2146 goto done;
2148 done:
2149 if (result)
2151 fwrite (result, 1, result[len - 1] == 0 ? len - 1 : len, outfp);
2152 fflush (outfp);
2153 pwmd_free (result);
2156 result = NULL;
2157 if (!rc)
2158 rc = finalize ();
2159 else if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
2160 (void) pwmd_command (pwm, &result, NULL, NULL, NULL,
2161 "GETINFO last_error");
2163 #ifdef HAVE_LIBREADLINE
2164 do_exit:
2165 #endif
2166 memset (command, 0, sizeof (command));
2168 if (rc && !quiet)
2169 show_error (pwm, rc, result);
2171 pwmd_close (pwm);
2172 reset_keyfiles ();
2173 pwmd_deinit ();
2174 pwmd_free (result);
2175 parse_status_ignore (NULL);
2176 if (connected && !quiet)
2177 fprintf (stderr, N_("Connection closed.\n"));
2179 exit (rc ? EXIT_FAILURE : EXIT_SUCCESS);