Add PWMD_OPTION_SSH_PASSPHRASE.
[libpwmd.git] / src / pwmc.c
blob8ff603d527ce26ed00016c564f22125e7711e105
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015,
3 2016
4 Ben Kibbey <bjk@luxsci.net>
6 This file is part of libpwmd.
8 Libpwmd is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
13 Libpwmd is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Libpwmd. If not, see <http://www.gnu.org/licenses/>.
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <stdint.h>
29 #include <err.h>
30 #include <errno.h>
31 #include <string.h>
32 #include <libpwmd.h>
33 #include <assuan.h>
34 #include <sys/select.h>
35 #include <fcntl.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <libgen.h>
39 #include <termios.h>
40 #include <limits.h>
41 #include <ctype.h>
43 #ifdef WITH_GNUTLS
44 #include <gnutls/gnutls.h>
45 #endif
47 #ifdef HAVE_LOCALE_H
48 #include <locale.h>
49 #endif
51 #ifdef HAVE_GETOPT_LONG
52 #ifdef HAVE_GETOPT_H
53 #include <getopt.h>
54 #endif
55 #else
56 #include "getopt_long.h"
57 #endif
59 #ifdef HAVE_LIBREADLINE
60 #if defined(HAVE_READLINE_READLINE_H)
61 #include <readline/readline.h>
62 #elif defined(HAVE_READLINE_H)
63 #include <readline.h>
64 #endif /* !defined(HAVE_READLINE_H) */
65 static int interactive_error;
66 static int interactive;
67 #endif /* HAVE_LIBREADLINE */
69 #ifdef HAVE_READLINE_HISTORY
70 #if defined(HAVE_READLINE_HISTORY_H)
71 #include <readline/history.h>
72 #elif defined(HAVE_HISTORY_H)
73 #include <history.h>
74 #endif
75 #endif /* HAVE_READLINE_HISTORY */
77 #ifndef LINE_MAX
78 #define LINE_MAX 2048
79 #endif
81 #include "gettext.h"
82 #define N_(msgid) gettext(msgid)
84 #include "mem.h"
87 #define DEFAULT_STATUS_IGNORE "KEEPALIVE,STATE,GPGME,PASSPHRASE_INFO,PASSPHRASE_HINT"
88 #define DEFAULT_PIN_TIMEOUT 30
89 #define DEFAULT_PIN_TRIES 3
90 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
91 ? gpg_error(rc) : rc
93 static int no_pinentry;
94 static pwm_t *pwm;
95 static char *filename;
96 static int save;
97 static char *keyid;
98 static char *sign_keyid;
99 static int symmetric;
100 static char *keyparams;
101 static char *keyfile;
102 static char *new_keyfile;
103 static char *sign_keyfile;
104 static int tries;
105 static int local_pin;
106 static int inquirefd;
107 static int statusfd;
108 FILE *statusfp;
109 static int quiet;
110 static char **status_ignore;
112 struct inquire_s
114 int fd;
115 char *line;
116 size_t len;
117 size_t size; // from stat(2).
118 char *last_keyword;
121 static gpg_error_t finalize ();
122 static gpg_error_t set_inquire (int fd, const char *line,
123 struct inquire_s **result);
124 static gpg_error_t parse_dotcommand (const char *line, char **result,
125 size_t * len, struct inquire_s *inq);
126 static gpg_error_t open_command (char *line);
128 static void
129 show_error (pwm_t *pwm, gpg_error_t rc, const char *str)
131 #ifdef WITH_GNUTLS
132 const char *tlsstr;
133 int e = pwmd_gnutls_error (pwm, &tlsstr);
135 if (e)
136 fprintf(stderr, "TLS: %s\n", tlsstr);
137 #endif
138 fprintf (stderr, "ERR %i: %s%s%s%s", rc, gpg_strerror (rc),
139 str ? ": " : "", str ? str : "", str ? "" : "\n");
142 static void
143 reset_keyfiles ()
145 pwmd_free (keyfile);
146 pwmd_free (new_keyfile);
147 pwmd_free (sign_keyfile);
148 keyfile = new_keyfile = sign_keyfile = NULL;
151 static void
152 usage (const char *pn, int status)
154 fprintf (status == EXIT_FAILURE ? stderr : stdout,
155 N_("Usage: pwmc [options] [file]\n"
156 " --url <string>\n"
157 " a url string to connect to (%s, see below)\n"
158 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
159 " --connect-timeout <seconds>\n"
160 " seconds before connecting to a remote host fails (0=disabled, 120)\n"
161 " --socket-timeout <seconds>\n"
162 " seconds before a remote command fails (0=disabled, 300)\n"
163 #endif
164 #ifdef WITH_GNUTLS
165 " --ca-cert <filename>\n"
166 " certificate authority (CA) used to sign the server cert\n"
167 " --client-cert <filename>\n"
168 " client certificate to use for authentication\n"
169 " --client-key <filename>\n"
170 " key file used to protect the client certificate\n"
171 " --tls-priority <string>\n"
172 " compression, cipher and hash algorithm string\n"
173 " (SECURE256:SECURE192:SECURE128:-VERS-SSL3.0)\n"
174 " --tls-verify\n"
175 " verify the hostname against the server certificate\n"
176 " --tls-fingerprint <string>\n"
177 " a SHA-256 hash of the server fingerprint to verify against\n"
178 #endif
179 #ifdef WITH_SSH
180 " --no-ssh-agent\n"
181 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
182 " --identity, -i <filename>\n"
183 " the ssh identity file to use for authentication\n"
184 " --knownhosts, -k <filename>\n"
185 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
186 " --ssh-needs-passphrase\n"
187 " prompt for a passphrase for the SSH identity file\n"
188 #endif
189 " --no-lock\n"
190 " do not lock the data file upon opening it\n"
191 " --lock-timeout <N>\n"
192 " time in tenths of a second to wait for a locked data file (50)\n"
193 " --name, -n <string>\n"
194 " set the client name\n"
195 " --pinentry <path>\n"
196 " the full path to the pinentry binary\n"
197 " --local-pinentry\n"
198 " force using a local pinentry\n"
199 " --no-pinentry\n"
200 " disable pinentry both remotely and locally\n"
201 " --ttyname, -y <path>\n"
202 " tty that pinentry will use\n"
203 " --ttytype, -t <string>\n"
204 " pinentry terminal type (default is $TERM)\n"
205 " --display, -d\n"
206 " pinentry display (default is $DISPLAY)\n"
207 " --lc-ctype <string>\n"
208 " locale setting for pinentry\n"
209 " --lc-messages <string>\n"
210 " locale setting for pinentry\n"
211 " --tries <N>\n"
212 " number of pinentry tries before failing (3)\n"
213 " --timeout <seconds>\n"
214 " pinentry timeout\n"
215 " --inquire <COMMAND>\n"
216 " the specified command (with any options) uses a server inquire while\n"
217 " command data is read via the inquire file descriptor (stdin)\n"
218 " --inquire-line, -L <STRING>\n"
219 " the initial line to send (i.e., element path) before the inquire data\n"
220 " --inquire-fd <FD>\n"
221 " read inquire data from the specified file descriptor (stdin)\n"
222 " --inquire-file <filename>\n"
223 " read inquire data from the specified filename\n"
224 " --output-fd <FD>\n"
225 " redirect command output to the specified file descriptor\n"
226 " --save, -S\n"
227 " send the SAVE command before exiting\n"
228 " --passphrase-file <filename>\n"
229 " obtain the passphrase from the specified filename\n"
230 " --new-passphrase-file <filename>\n"
231 " obtain the passphrase to save with from the specified filename\n"
232 " --sign-passphrase-file <filename>\n"
233 " obtain the passphrase to sign with (symmetric) from the specified filename\n"
234 " --key-params <filename>\n"
235 " key parameters to use for key generation (pwmd default)\n"
236 " --keyid <recipient>[,<recipient>]\n"
237 " the public key ID to u\n"
238 " --sign-keyid <string>\n"
239 " the key ID to sign the data file with\n"
240 " --symmetric\n"
241 " use conventional encryption with optional signer(s) for new files\n"
242 " --no-status\n"
243 " disable showing of status messages from the server\n"
244 " --status-fd <FD>\n"
245 " redirect status messages to the specified file descriptor\n"
246 " --status-ignore <string[,...]>\n"
247 " prevent parsing of the specified status message keywords\n"
248 " --quiet\n"
249 " disable showing of extra messages (implies --no-status)\n"
250 #ifdef HAVE_LIBREADLINE
251 " --interactive\n"
252 " use a shell like interface to pwmd (allows more than one command)\n"
253 #endif
254 " --version\n"
255 " --help\n"),
256 #ifdef DEFAULT_PWMD_SOCKET
257 DEFAULT_PWMD_SOCKET
258 #else
259 "~/.pwmd/socket"
260 #endif
262 fprintf (status == EXIT_FAILURE ? stderr : stdout,
263 N_("\n"
264 "An optional url may be in the form of:\n"
265 " --url /path/to/socket\n"
266 " --url file://[path/to/socket]\n"
267 #ifdef WITH_SSH
268 " or\n"
269 " --url ssh[46]://[username@]hostname[:port]\n"
270 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
271 #endif
272 #ifdef WITH_GNUTLS
273 " or\n"
274 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
275 " --client-key filename\n"
276 #endif
277 #ifdef HAVE_LIBREADLINE
278 "\n"
279 "Interactive mode is used when input is from a terminal.\n"
280 #endif
282 exit (status);
285 static gpg_error_t
286 inquire_cb (void *user, const char *keyword, gpg_error_t rc,
287 char **data, size_t * size)
289 struct inquire_s *inq = user;
290 int is_password = 0;
291 int is_newpassword = 0;
292 int sign = 0;
293 int is_keyparam = 0;
295 *data = NULL;
296 *size = 0;
298 if (rc)
299 return rc;
301 if (!strcmp (keyword, "PASSPHRASE"))
302 is_password = 1;
303 else if (!strcmp (keyword, "SIGN_PASSPHRASE"))
304 sign = 1;
305 else if (!strcmp (keyword, "NEW_PASSPHRASE"))
306 is_newpassword = 1;
307 #ifdef HAVE_LIBREADLINE
308 else if (!strcmp (keyword, "KEYPARAM") && !interactive)
310 #else
311 else if (!strcmp (keyword, "KEYPARAM"))
313 #endif
314 int fd;
315 if (!keyparams || !*keyparams)
316 return gpg_error (GPG_ERR_INV_PARAMETER);
318 fd = open (keyparams, O_RDONLY);
319 if (fd == -1)
321 fprintf (stderr, "%s: %s\n", keyparams, strerror (errno));
322 return gpg_error_from_syserror ();
325 rc = set_inquire (fd, NULL, &inq);
326 if (rc)
328 close (fd);
329 return rc;
332 if (!quiet)
333 fprintf (stderr, N_("Using file '%s' as %s.\n"), keyparams, keyword);
335 is_keyparam = 1;
338 if ((is_password && !keyfile) || (is_newpassword && !new_keyfile)
339 || (sign && !sign_keyfile))
341 char *tmp;
342 int local;
344 /* Try to use the local pinentry between inquires (new/sign/passphrase).
345 * If --no-pinentry was specified then the passphrase is read from the
346 * terminal as usual. */
347 pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local);
348 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, 1);
349 rc = pwmd_password (pwm, keyword, &tmp, &inq->len);
350 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local);
351 if (rc && gpg_err_code (rc) != GPG_ERR_EOF)
352 return rc;
354 pwmd_free (inq->line);
355 inq->line = tmp;
356 *data = inq->line;
357 *size = inq->len;
358 return gpg_error (GPG_ERR_EOF);
360 else if ((is_newpassword && new_keyfile) || (is_password && keyfile)
361 || (sign && sign_keyfile))
363 int fd;
365 if (sign)
366 fd = open (sign_keyfile, O_RDONLY);
367 else
368 fd = open (is_password || sign ? keyfile : new_keyfile, O_RDONLY);
370 if (fd == -1)
372 if (sign)
373 fprintf (stderr, "%s: %s\n", sign_keyfile, strerror (errno));
374 else
375 fprintf (stderr, "%s: %s\n", is_newpassword ? new_keyfile
376 : keyfile, strerror (errno));
377 return gpg_error_from_syserror ();
380 rc = set_inquire (fd, NULL, &inq);
381 if (rc)
383 close (fd);
384 return rc;
387 if (!quiet)
388 fprintf (stderr, N_("Using keyfile '%s' as %s.\n"),
389 sign ? sign_keyfile : is_newpassword ? new_keyfile
390 : keyfile, keyword);
392 #ifdef HAVE_LIBREADLINE
393 else if ((!inq->last_keyword || strcmp (keyword, inq->last_keyword))
394 && interactive && inq->fd == STDIN_FILENO)
396 fprintf (stderr,
398 ("%sPress CTRL-D to send the current line. Press twice to end. %s:\n"),
399 inq->last_keyword ? "\n" : "", keyword);
400 pwmd_free (inq->last_keyword);
401 inq->last_keyword = pwmd_strdup (keyword);
403 #endif
405 /* The first part of the command data. */
406 if (inq->len)
408 *data = inq->line;
409 *size = inq->len;
410 inq->len = 0;
411 return inq->fd == -1 ? gpg_error (GPG_ERR_EOF) : 0;
414 *size = read (inq->fd, inq->line, ASSUAN_LINELENGTH);
415 if (*size == -1)
417 *size = 0;
418 return gpg_error (gpg_error_from_syserror ());
420 else if (*size)
421 *data = inq->line;
422 else if (inq->fd != STDIN_FILENO &&
423 (is_newpassword || is_password || sign || is_keyparam))
425 *inq->line = 0;
426 inq->size = 1;
427 *data = inq->line;
428 *size = 1;
431 if (((is_newpassword && new_keyfile) || (is_password && keyfile)
432 || (sign && sign_keyfile) || (keyparams && is_keyparam))
433 && *size == inq->size)
434 return gpg_error (GPG_ERR_EOF);
436 return *size ? 0 : gpg_error (GPG_ERR_EOF);
439 static int
440 status_msg_cb (void *data, const char *line)
442 char *p = strchr (line, ' ');
443 char **s;
445 /* Ignore status messages specified by the client via --status-ignore. */
446 for (s = status_ignore; s && *s; s++)
448 char *tmp = strchr (line, ' ');
449 size_t len = tmp ? strlen (line) - strlen (tmp) : strlen (line);
451 if (!strncmp (line, *s, len) && len == strlen (*s))
452 return 0;
455 #ifdef HAVE_LIBREADLINE
456 if (interactive && !strncmp (line, "XFER ", 5)
457 #else
458 if (!strncmp (line, "XFER ", 5)
459 #endif
460 && *line != '#' && p && strchr (p, ' ') && *++p)
462 char *p1 = strchr (p, ' ');
463 int a = strtol (p, NULL, 10);
465 if (isdigit (*p) && p1)
467 int b = strtol (p1, NULL, 10);
468 char l[64] = { 0 };
469 int t = a && b ? a * 100 / b : 0;
471 strncpy (l, line, strlen (line) - strlen (p) - 1);
472 fprintf (statusfp, "\rS:%s %i/%i %i%%%s", l, a, b, t,
473 a == b ? "\n" : "");
474 fflush (statusfp);
475 return 0;
479 fprintf (statusfp, "S:%s\n", line);
480 fflush (statusfp);
481 #ifdef HAVE_LIBREADLINE
482 rl_on_new_line ();
483 #endif
484 return 0;
487 static gpg_error_t
488 process_cmd ()
490 return pwmd_process (pwm);
493 #ifdef WITH_SSH
494 static gpg_error_t
495 knownhost_cb (void *data, const char *host, const char *key, size_t len)
497 gpg_error_t rc = 0;
498 char *buf =
499 pwmd_strdup_printf (N_
500 ("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?\n"),
501 (char *) data, host, host);
503 if (no_pinentry && !isatty (STDIN_FILENO))
505 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
506 pwmd_free (buf);
507 return GPG_ERR_ENOTTY;
509 else if (no_pinentry)
511 for (char *p = buf, len = 0; *p; p++, len++)
513 if (*p == '\n')
514 len = 0;
516 if (len == 78)
518 char *t = p;
520 while (len && !isspace (*(--p)))
521 len--;
523 if (len)
524 *p = '\n';
525 len = 78 - len;
526 p = t;
529 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_PROMPT, N_("Accept [y/N]:"));
532 if (!rc)
533 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, buf);
535 pwmd_free (buf);
536 if (rc)
537 return rc;
539 return pwmd_getpin (pwm, NULL, NULL, NULL, PWMD_PINENTRY_CONFIRM);
541 #endif
543 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
544 static pwmd_socket_t
545 is_remote_url (const char *str)
547 if (!str)
548 return PWMD_SOCKET_LOCAL;
550 #ifdef WITH_SSH
551 if (strstr (str, "ssh://") || strstr (str, "ssh4://")
552 || strstr (str, "ssh6://"))
553 return PWMD_SOCKET_SSH;
554 #endif
556 #ifdef WITH_GNUTLS
557 if (strstr (str, "tls://") || strstr (str, "tls4://")
558 || strstr (str, "tls6://"))
559 return PWMD_SOCKET_TLS;
560 #endif
562 return PWMD_SOCKET_LOCAL;
564 #endif
566 static char *
567 escape (const char *str)
569 const char *p;
570 char *buf = pwmd_malloc (ASSUAN_LINELENGTH + 1), *b = buf;
571 size_t len = 0;
573 for (p = str; *p; p++, len++)
575 if (len == ASSUAN_LINELENGTH)
576 break;
578 if (*p == '\\')
580 switch (*++p)
582 case 't':
583 *b++ = '\t';
584 break;
585 case 'n':
586 *b++ = '\n';
587 break;
588 case 'v':
589 *b++ = '\v';
590 break;
591 case 'b':
592 *b++ = '\b';
593 break;
594 case 'f':
595 *b++ = '\f';
596 break;
597 case 'r':
598 *b++ = '\r';
599 break;
600 default:
601 *b++ = *p;
602 break;
605 if (!*p)
606 break;
608 continue;
611 *b++ = *p;
614 *b = 0;
615 return buf;
618 static void
619 free_inquire (struct inquire_s *inq)
621 if (!inq)
622 return;
624 pwmd_free (inq->line);
626 if (inq->fd != -1 && inq->fd != STDIN_FILENO)
627 close (inq->fd);
629 pwmd_free (inq->last_keyword);
630 pwmd_free (inq);
633 /* When *result is not NULL it is updated to the new values and not
634 * reallocated. */
635 static gpg_error_t
636 set_inquire (int fd, const char *line, struct inquire_s **result)
638 struct inquire_s inq = { 0 };
639 struct stat st = { 0 };
640 gpg_error_t rc;
642 if (fd != -1)
644 if (fstat (fd, &st) == -1)
645 return gpg_error_from_syserror ();
647 inq.size = st.st_size;
650 inq.fd = fd;
651 inq.line = pwmd_calloc (1, ASSUAN_LINELENGTH);
652 if (!inq.line)
653 return GPG_ERR_ENOMEM;
655 if (line)
657 char *s = escape (line);
659 if (!s)
661 pwmd_free (inq.line);
662 return GPG_ERR_ENOMEM;
665 if (strlen (s) >= ASSUAN_LINELENGTH)
667 pwmd_free (inq.line);
668 pwmd_free (s);
669 return GPG_ERR_LINE_TOO_LONG;
672 strncpy (inq.line, s, ASSUAN_LINELENGTH - 1);
673 inq.len = strlen (s);
674 pwmd_free (s);
677 rc = pwmd_setopt (pwm, PWMD_OPTION_INQUIRE_TOTAL,
678 st.st_size ? st.st_size + strlen (inq.line) : 0);
679 if (rc)
681 pwmd_free (inq.line);
682 return rc;
685 if (*result == NULL)
686 *result = pwmd_malloc (sizeof (struct inquire_s));
687 else
689 if ((*result)->fd != -1 && (*result)->fd != STDIN_FILENO)
690 close ((*result)->fd);
692 pwmd_free ((*result)->line);
693 (*result)->line = NULL;
694 (*result)->fd = -1;
695 (*result)->len = 0;
698 memcpy (*result, &inq, sizeof (struct inquire_s));
699 memset (&inq, 0, sizeof (struct inquire_s));
700 return rc;
703 #ifdef HAVE_LIBREADLINE
704 static int
705 interactive_hook (void)
707 interactive_error = process_cmd ();
709 if (interactive_error)
710 rl_event_hook = NULL;
712 return 0;
715 static int
716 get_readline_char (FILE *fp)
718 if (rl_line_buffer
719 && (!strncmp (rl_line_buffer, ".set passphrase-file ", 16)
720 || !strncmp (rl_line_buffer, ".set new-passphrase-file ", 20)
721 || !strncmp (rl_line_buffer, ".set sign-passphrase-file ", 21)))
722 rl_inhibit_completion = 0;
723 else if (rl_line_buffer
724 && !strncmp (rl_line_buffer, ".redir ", 7))
726 char *p = strchr (rl_line_buffer, ' ');
728 if (strchr (++p, ' '))
729 rl_inhibit_completion = 1;
730 else
731 rl_inhibit_completion = 0;
733 else if (rl_line_buffer
734 && !strncmp (rl_line_buffer, ".read ", 6))
736 char *p = rl_line_buffer + 6;
738 if (strstr (p, "--prefix "))
740 p = strstr (p, "--prefix ");
741 p += 9;
742 p = strchr (p, ' ');
743 if (p)
744 p++;
747 if (!p || strchr (p, ' '))
748 rl_inhibit_completion = 1;
749 else
750 rl_inhibit_completion = 0;
752 else
753 rl_inhibit_completion = 1;
755 return fgetc (fp);
758 static void
759 print_help ()
761 fprintf (stderr,
763 ("------------------------------------------------------------\n"
764 "Elements are TAB delimited. Type HELP for protocol commands.\n"
765 "Type .help for pwmc commands. Press CTRL-D to quit.\n"
766 "------------------------------------------------------------\n"));
768 #endif
770 static char *
771 parse_arg (const char *src, char *dst, size_t len)
773 char *p = dst;
774 const char *s = src;
775 size_t n = 0;
777 for (; s && *s && *s != ' ' && n < len; s++, n++)
778 *p++ = *s;
780 *p = 0;
781 return dst;
784 static char *
785 parse_opt (char **line, const char *opt, gpg_error_t * rc)
787 static char result[ASSUAN_LINELENGTH] = { 0 }, *r = result;
788 char *s = strstr (*line, opt);
790 *rc = 0;
791 result[0] = 0;
792 r = result;
794 if (s)
796 size_t len = 0;
797 int quote = 0;
798 size_t rlen = strlen (opt);
799 char *p = s + rlen;
800 int lastc = 0;
802 while (*p && *p == ' ')
804 rlen++;
805 p++;
808 for (; *p && len < sizeof (result) - 1; p++, rlen++)
810 if (isspace (*p) && !quote)
811 break;
813 if (*p == '\"' && lastc != '\\')
815 quote = !quote;
816 lastc = *p;
817 continue;
820 *r++ = lastc = *p;
821 len++;
824 *r = 0;
826 if (len >= sizeof (result) - 1)
827 *rc = GPG_ERR_LINE_TOO_LONG;
828 else
830 p = s + rlen;
832 while (*p && *p == ' ')
833 p++;
835 *line = p;
839 return result;
842 static gpg_error_t
843 read_command (const char *line, char **result, size_t * len)
845 int fd;
846 gpg_error_t rc = 0;
847 char *file = NULL;
848 struct inquire_s *inq = NULL;
849 char *p = (char *) line;
850 const char *prefix = parse_opt (&p, "--prefix", &rc);
851 char filebuf[ASSUAN_LINELENGTH];
853 if (rc)
854 return rc;
856 rc = GPG_ERR_SYNTAX;
858 if (p && *p)
860 while (*p && isspace (*p))
861 p++;
863 file = parse_arg (p, filebuf, sizeof (filebuf));
864 if (file && *file)
866 p += strlen (file) + 1;
868 while (*p && isspace (*p))
869 p++;
871 if (*p)
872 rc = 0;
876 if (rc)
878 fprintf (stderr,
880 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
881 fprintf (stderr,
883 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\\ = \\)\n"));
884 return rc;
887 fd = open (file, O_RDONLY);
888 if (fd == -1)
889 return gpg_error_from_syserror ();
891 rc = set_inquire (fd, prefix && *prefix ? prefix : NULL, &inq);
892 if (rc)
894 close (fd);
895 return rc;
898 rc = pwmd_command (pwm, result, len, inquire_cb, inq, "%s", p);
899 free_inquire (inq);
900 return rc;
903 static gpg_error_t
904 redir_command (const char *line)
906 const char *p = line;
907 int fd;
908 gpg_error_t rc = GPG_ERR_SYNTAX;
909 char *file = NULL;
910 struct inquire_s *inq = NULL;
911 char *result = NULL;
912 size_t len = 0;
913 char filebuf[ASSUAN_LINELENGTH];
915 if (p && *p && *++p)
917 file = parse_arg (p, filebuf, sizeof (filebuf));
918 if (file && *file)
920 p += strlen (file) + 1;
922 while (*p && isspace (*p))
923 p++;
925 if (*p)
926 rc = 0;
930 if (rc)
932 fprintf (stderr, N_("Usage: .redir <filename> <command> [args]\n"));
933 return rc;
936 fd = open (file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
937 if (fd == -1)
938 return gpg_error_from_syserror ();
940 #ifdef HAVE_LIBREADLINE
941 rc = set_inquire (interactive ? STDIN_FILENO : inquirefd, NULL, &inq);
942 #else
943 rc = set_inquire (inquirefd, NULL, &inq);
944 #endif
945 if (rc)
947 close (fd);
948 return rc;
951 rc = parse_dotcommand (p, &result, &len, inq);
952 if (!rc && result && len--)
953 { // null byte which is always appended
954 if (write (fd, result, len) != len)
955 rc = GPG_ERR_TOO_SHORT;
956 pwmd_free (result);
959 free_inquire (inq);
960 close (fd);
961 return rc;
964 static gpg_error_t
965 help_command (const char *line)
967 fprintf (stderr,
968 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
969 " .redir <filename> <command>\n"
970 " redirect the output of a command to the specified file\n"
971 "\n"
972 " .open <filename>\n"
973 " open the specified filename losing any changes to the current one\n"
974 "\n"
975 " .read [--prefix <string>] <filename> <command> [args]\n"
976 " obtain data from the specified filename for an inquire command\n"
977 "\n"
978 " .set help | <name> [<value>]\n"
979 " set option <name> to <value>\n"
980 "\n"
981 " .save [args]\n"
982 " write changes of the file to disk\n"
983 "\n"
984 " .passwd [args]\n"
985 " change the passphrase of a data file\n"
986 "\n"
987 " .help\n"
988 " this help text\n"));
989 return 0;
992 static gpg_error_t
993 open_command (char *line)
995 struct inquire_s *inq = NULL;
996 const char *file = line;
997 gpg_error_t rc;
998 int local;
1000 while (file && isspace (*file))
1001 file++;
1003 if (!file || !*file)
1005 fprintf (stderr, N_("Usage: .open <filename>\n"));
1006 return GPG_ERR_SYNTAX;
1009 #ifdef HAVE_LIBREADLINE
1010 if (interactive || !quiet)
1011 #else
1012 if (!quiet)
1013 #endif
1014 fprintf (stderr, N_("Opening data file \"%s\" ...\n"), file);
1016 #ifdef HAVE_LIBREADLINE
1017 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1018 #else
1019 rc = set_inquire (-1, NULL, &inq);
1020 #endif
1021 if (rc)
1022 return rc;
1024 pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local);
1026 if (keyfile)
1028 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1029 if (!rc)
1030 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, 1);
1032 else
1033 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1035 if (!rc)
1036 rc = pwmd_open (pwm, file, inquire_cb, inq);
1038 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local);
1040 #ifdef HAVE_LIBREADLINE
1041 if (interactive)
1042 reset_keyfiles ();
1043 #endif
1045 free_inquire (inq);
1046 if (!rc && file != filename)
1048 pwmd_free (filename);
1049 filename = pwmd_strdup (file);
1052 return rc;
1055 static gpg_error_t
1056 set_command (const char *line)
1058 gpg_error_t rc = 0;
1059 char name[256] = { 0 };
1060 char value[512] = { 0 };
1061 char *namep;
1062 char *valuep;
1063 const char *p = line;
1065 while (p && *p && isspace (*p))
1066 p++;
1068 namep = parse_arg (p, name, sizeof (name));
1069 if (!namep || !*namep)
1071 fprintf (stderr, N_("Usage: .set help | <name> [<value>]\n"));
1072 return GPG_ERR_SYNTAX;
1075 p += strlen (namep);
1076 while (p && *p && isspace (*p))
1077 p++;
1079 valuep = parse_arg (p, value, sizeof (value));
1081 if (!strcmp (name, "passphrase-file") || !strcmp (name, "new-passphrase-file")
1082 || !strcmp (name, "sign-passphrase-file"))
1084 int is_newkeyfile = 1;
1085 int sign = !strcmp (name, "sign-passphrase-file");
1087 if (!strcmp (name, "passphrase-file") || sign)
1088 is_newkeyfile = 0;
1090 if (is_newkeyfile)
1092 pwmd_free (new_keyfile);
1093 new_keyfile = NULL;
1095 else if (sign)
1097 pwmd_free (sign_keyfile);
1098 sign_keyfile = NULL;
1100 else
1102 pwmd_free (keyfile);
1103 keyfile = NULL;
1106 if (!rc && *valuep)
1108 if (is_newkeyfile)
1109 new_keyfile = pwmd_strdup (value);
1110 else if (sign)
1111 sign_keyfile = pwmd_strdup (value);
1112 else
1113 keyfile = pwmd_strdup (value);
1115 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1117 else if (!local_pin && !no_pinentry)
1119 pwmd_socket_t t;
1121 pwmd_socket_type (pwm, &t);
1122 if (t == PWMD_SOCKET_LOCAL)
1123 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1126 else if (!strcmp(name, "pinentry-timeout"))
1128 char *e = NULL;
1129 int n = strtol(valuep, &e, 10);
1131 if (e && *e)
1132 return gpg_error (GPG_ERR_INV_VALUE);
1134 if (!*valuep)
1135 n = DEFAULT_PIN_TIMEOUT;
1137 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, n);
1139 else if (!strcmp (name, "help"))
1141 fprintf (stderr,
1143 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1144 "delimited. When no value is specified the option is unset.\n\n"
1145 "passphrase-file [<filename>]\n"
1146 " set or unset the file to be used when a passphrase is required (*)\n"
1147 "\n"
1148 "new-passphrase-file [<filename>]\n"
1149 " set or unset the file to be used when a new passphrase is required (*)\n"
1150 "\n"
1151 "sign-passphrase-file [<filename>]\n"
1152 " set or unset the file to be used when a passphrase is required for\n"
1153 " signing (symmetric) (*)\n"
1154 "\n"
1155 "pinentry-timeout <seconds>\n"
1156 " the amount of seconds before pinentry gives up waiting for input\n"
1157 "\n"
1158 "* = the next protocol command will unset this value\n"
1161 else
1162 rc = GPG_ERR_UNKNOWN_OPTION;
1164 return rc;
1167 static gpg_error_t
1168 do_save_passwd_command (const char *line, int save)
1170 struct inquire_s *inq = NULL;
1171 gpg_error_t rc;
1172 int local;
1174 #ifdef HAVE_LIBREADLINE
1175 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1176 #else
1177 rc = set_inquire (-1, NULL, &inq);
1178 #endif
1179 if (rc)
1180 return rc;
1182 pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local);
1184 if (new_keyfile || keyfile || sign_keyfile)
1186 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1187 if (!rc)
1188 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, 1);
1190 else
1191 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1193 if (!rc)
1195 if (save)
1196 rc = pwmd_save (pwm, line, inquire_cb, inq);
1197 else
1198 rc = pwmd_passwd (pwm, line, inquire_cb, inq);
1201 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local);
1203 #ifdef HAVE_LIBREADLINE
1204 if (interactive)
1205 reset_keyfiles ();
1206 #endif
1208 free_inquire (inq);
1209 return rc;
1212 static gpg_error_t
1213 save_command (const char *line)
1215 return do_save_passwd_command (line, 1);
1218 static gpg_error_t
1219 parse_dotcommand (const char *line, char **result,
1220 size_t * len, struct inquire_s *inq)
1222 const char *p = line;
1223 gpg_error_t rc = 0;
1225 if (!strncmp (p, ".read", 5))
1226 rc = read_command (p + 5, result, len);
1227 else if (!strncmp (p, ".redir", 6))
1228 rc = redir_command (p + 6);
1229 else if (!strncmp (p, ".help", 5))
1230 rc = help_command (p + 5);
1231 else if (!strncmp (p, ".open", 5))
1232 rc = open_command ((char *)p + 5);
1233 else if (!strncmp (p, ".set", 4))
1234 rc = set_command (p + 4);
1235 else if (!strncmp (p, ".save", 5))
1236 rc = do_save_passwd_command (p + 5, 1);
1237 else if (!strncmp (p, ".passwd", 7))
1238 rc = do_save_passwd_command (p + 7, 0);
1239 else
1241 rc = pwmd_command (pwm, result, len, inquire_cb, inq, "%s", line);
1242 #ifdef HAVE_LIBREADLINE
1243 if (interactive)
1245 #endif
1246 reset_keyfiles ();
1247 #ifdef HAVE_LIBREADLINE
1249 #endif
1252 return FINISH (rc);
1255 #ifdef HAVE_LIBREADLINE
1256 static gpg_error_t
1257 do_interactive ()
1259 gpg_error_t rc;
1260 struct inquire_s *inq = NULL;
1262 rl_initialize ();
1263 rc = process_cmd ();
1264 if (rc)
1265 return rc;
1267 rc = set_inquire (STDIN_FILENO, NULL, &inq);
1268 if (rc)
1269 return rc;
1271 fprintf (stderr,
1272 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1273 print_help ();
1274 rl_event_hook = &interactive_hook;
1275 rl_getc_function = get_readline_char;
1276 rl_set_keyboard_input_timeout (100000);
1278 for (;;)
1280 char *line;
1281 char *result = NULL;
1282 size_t len;
1284 rc = 0;
1285 line = readline ("pwmc> ");
1286 if (interactive_error)
1288 free (line);
1289 rc = interactive_error;
1290 break;
1293 if (!line)
1295 rc = finalize ();
1296 if (!rc)
1297 break;
1299 if (gpg_err_code (rc) != GPG_ERR_CANCELED &&
1300 gpg_err_code (rc) != GPG_ERR_EOF)
1301 fprintf (stderr, "ERR %i: %s\n", rc, gpg_strerror (rc));
1303 continue;
1305 else if (!*line)
1307 free (line);
1308 continue;
1311 #ifdef HAVE_READLINE_HISTORY
1312 add_history (line);
1313 #endif
1314 rc = parse_dotcommand (line, &result, &len, inq);
1315 free (line);
1316 if (rc)
1318 char *tmp = NULL;
1320 if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
1321 (void) pwmd_command (pwm, &tmp, NULL, NULL, NULL,
1322 "GETINFO last_error");
1324 show_error (pwm, rc, tmp);
1325 pwmd_free (tmp);
1327 else if (result && len)
1328 printf ("%s%s", result, result[len - 1] != '\n' ? "\n" : "");
1330 pwmd_free (result);
1333 free_inquire (inq);
1334 return rc;
1336 #endif
1338 static gpg_error_t
1339 finalize ()
1341 gpg_error_t rc = 0;
1342 #ifdef HAVE_LIBREADLINE
1343 int quit = 0;
1345 if (interactive)
1347 int finished = 0;
1349 fprintf (stderr, "\n");
1353 char *p, buf[16];
1355 fprintf (stderr,
1357 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1358 p = fgets (buf, sizeof (buf), stdin);
1360 if (feof (stdin))
1362 clearerr (stdin);
1363 return GPG_ERR_EOF;
1366 switch (*p)
1368 case 'h':
1369 print_help ();
1370 break;
1371 case 'c':
1372 return GPG_ERR_CANCELED;
1373 case 'Q':
1374 return 0;
1375 case 'f':
1376 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1377 "CLEARCACHE %s", filename);
1378 if (rc)
1379 return rc;
1381 interactive_hook ();
1382 break;
1383 case 'S':
1384 quit = 1;
1385 case 's':
1386 save = 1;
1387 finished = 1;
1388 break;
1389 default:
1390 break;
1393 while (!finished);
1395 #endif
1397 if (save && !filename)
1399 fprintf (stderr,
1401 ("No filename was specified on the command line. Aborting.\n"));
1402 return GPG_ERR_CANCELED;
1405 if (save && filename)
1407 char *args =
1408 pwmd_strdup_printf ("%s %s%s %s%s %s",
1409 symmetric ? "--symmetric" : "",
1410 keyid ? "--keyid=" : "",
1411 keyid ? keyid : "",
1412 sign_keyid ? "--sign-keyid=" : "",
1413 sign_keyid ? sign_keyid : "",
1414 keyparams ? "--inquire-keyparam" : "");
1416 #ifdef HAVE_LIBREADLINE
1417 if (!quiet || interactive)
1419 #else
1420 if (!quiet)
1422 #endif
1423 fprintf (stderr, "\n");
1424 fprintf (stderr, N_("Saving changes ...\n"));
1427 rc = save_command (args);
1428 pwmd_free (args);
1431 #ifdef HAVE_LIBREADLINE
1432 if (interactive)
1433 return rc ? rc : quit ? 0 : GPG_ERR_CANCELED;
1434 #endif
1436 return rc;
1439 static void
1440 parse_status_ignore (char *str)
1442 size_t n = 0;
1443 char **p, *s;
1445 for (p = status_ignore; p && *p; p++)
1446 pwmd_free (*p);
1448 pwmd_free (status_ignore);
1449 status_ignore = NULL;
1450 if (!str || !*str)
1451 return;
1453 while ((s = strsep (&str, ",")))
1455 p = pwmd_realloc (status_ignore, (n + 2) * sizeof (char *));
1456 p[n++] = pwmd_strdup (s);
1457 p[n] = NULL;
1458 status_ignore = p;
1463 main (int argc, char *argv[])
1465 int connected = 0;
1466 gpg_error_t rc;
1467 int opt;
1468 char command[ASSUAN_LINELENGTH], *p = NULL;
1469 char *result = NULL;
1470 size_t len = 0;
1471 char *pinentry_path = NULL;
1472 char *display = NULL, *tty = NULL, *ttytype = NULL;
1473 char *lcctype = NULL, *lcmessages = NULL;
1474 int outfd = STDOUT_FILENO;
1475 FILE *outfp = stdout;
1476 FILE *inquirefp = stdin;
1477 int show_status = 1;
1478 char *clientname = "pwmc";
1479 char *inquire = NULL;
1480 char *inquire_line = NULL;
1481 int timeout = 0;
1482 #ifdef WITH_SSH
1483 int use_ssh_agent = 1;
1484 char *knownhosts = NULL;
1485 char *identity = NULL;
1486 int needs_passphrase = 0;
1487 #endif
1488 #ifdef WITH_GNUTLS
1489 char *cacert = NULL;
1490 char *clientcert = NULL;
1491 char *clientkey = NULL;
1492 char *prio = NULL;
1493 int tls_verify = 0;
1494 char *tls_fingerprint = NULL;
1495 #endif
1496 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1497 pwmd_socket_t socktype;
1498 long socket_timeout = 300;
1499 int connect_timeout = 120;
1500 #endif
1501 int lock_on_open = 1;
1502 long lock_timeout = 50;
1503 char *url = NULL;
1504 char *tmp = NULL;
1505 /* The order is important. */
1506 enum
1508 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1509 OPT_SOCKET_TIMEOUT, OPT_CONNECT_TIMEOUT,
1510 #endif
1511 #ifdef WITH_SSH
1512 OPT_USE_SSH_AGENT, OPT_IDENTITY, OPT_KNOWNHOSTS, OPT_SSH_NEEDS_PASSPHRASE,
1513 #endif
1514 #ifdef WITH_GNUTLS
1515 OPT_CACERT, OPT_CLIENTCERT, OPT_CLIENTKEY, OPT_PRIORITY, OPT_VERIFY,
1516 OPT_SERVER_FP,
1517 #endif
1518 OPT_URL, OPT_LOCAL, OPT_TTYNAME, OPT_TTYTYPE, OPT_DISPLAY, OPT_LC_CTYPE,
1519 OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES, OPT_PINENTRY, OPT_KEYFILE,
1520 OPT_PASSPHRASE_FILE, OPT_NEW_KEYFILE, OPT_NEW_PASSPHRASE_FILE,
1521 OPT_SIGN_KEYFILE, OPT_SIGN_PASSPHRASE_FILE, OPT_NOLOCK, OPT_LOCK_TIMEOUT,
1522 OPT_SAVE, OPT_OUTPUT_FD, OPT_INQUIRE, OPT_INQUIRE_FD, OPT_INQUIRE_FILE,
1523 OPT_INQUIRE_LINE, OPT_NO_STATUS, OPT_STATUS_IGNORE, OPT_STATUSFD, OPT_NAME,
1524 OPT_VERSION, OPT_HELP, OPT_KEYID, OPT_SIGN_KEYID, OPT_SYMMETRIC,
1525 OPT_KEYPARAMS, OPT_NO_PINENTRY, OPT_QUIET,
1526 #ifdef HAVE_LIBREADLINE
1527 OPT_INTERACTIVE,
1528 #endif
1530 const struct option long_opts[] = {
1531 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1532 {"socket-timeout", 1, 0, 0},
1533 {"connect-timeout", 1, 0, 0},
1534 #endif
1536 #ifdef WITH_SSH
1537 {"no-ssh-agent", 0, 0, 0},
1538 {"identity", 1, 0, 'i'},
1539 {"knownhosts", 1, 0, 'k'},
1540 {"ssh-needs-passphrase", 0, 0, 0},
1541 #endif
1542 #ifdef WITH_GNUTLS
1543 {"ca-cert", 1, 0, 0},
1544 {"client-cert", 1, 0, 0},
1545 {"client-key", 1, 0, 0},
1546 {"tls-priority", 1, 0, 0},
1547 {"tls-verify", 0, 0, 0},
1548 {"tls-fingerprint", 1, 0, 0},
1549 #endif
1550 {"url", 1, 0, 0},
1551 {"local-pinentry", 0, 0},
1552 {"ttyname", 1, 0, 'y'},
1553 {"ttytype", 1, 0, 't'},
1554 {"display", 1, 0, 'd'},
1555 {"lc-ctype", 1, 0, 0},
1556 {"lc-messages", 1, 0, 0},
1557 {"timeout", 1, 0, 0},
1558 {"tries", 1, 0, 0},
1559 {"pinentry", 1, 0, 0},
1560 {"key-file", 1, 0, 0},
1561 {"passphrase-file", 1, 0, 0},
1562 {"new-key-file", 1, 0, 0},
1563 {"new-passphrase-file", 1, 0, 0},
1564 {"sign-key-file", 1, 0, 0},
1565 {"sign-passphrase-file", 1, 0, 0},
1566 {"no-lock", 0, 0, 0},
1567 {"lock-timeout", 1, 0, 0},
1568 {"save", 0, 0, 'S'},
1569 {"output-fd", 1, 0, 0},
1570 {"inquire", 1, 0, 0},
1571 {"inquire-fd", 1, 0, 0},
1572 {"inquire-file", 1, 0, 0},
1573 {"inquire-line", 1, 0, 'L'},
1574 {"no-status", 0, 0, 0},
1575 {"status-ignore", 1, 0, 0},
1576 {"status-fd", 1, 0, 0},
1577 {"name", 1, 0, 'n'},
1578 {"version", 0, 0, 0},
1579 {"help", 0, 0, 0},
1580 {"keyid", 1, 0, 0},
1581 {"sign-keyid", 1, 0, 0},
1582 {"symmetric", 0, 0, 0},
1583 {"key-params", 1, 0, 0},
1584 {"no-pinentry", 0, 0, 0},
1585 {"quiet", 0, 0, 0},
1586 #ifdef HAVE_LIBREADLINE
1587 {"interactive", 0, 0},
1588 #endif
1589 {0, 0, 0, 0}
1591 #ifdef WITH_SSH
1592 const char *optstring = "L:y:t:d:P:I:Sn:i:k:s";
1593 #else
1594 const char *optstring = "L:y:t:d:P:I:Sn:s";
1595 #endif
1596 int opt_index = 0;
1598 #ifdef ENABLE_NLS
1599 setlocale (LC_ALL, "");
1600 bindtextdomain ("libpwmd", LOCALEDIR);
1601 #endif
1603 tries = DEFAULT_PIN_TRIES;
1604 inquirefd = STDIN_FILENO;
1605 statusfd = STDERR_FILENO;
1606 statusfp = stderr;
1607 tmp = pwmd_strdup (DEFAULT_STATUS_IGNORE);
1608 parse_status_ignore (tmp);
1609 pwmd_free (tmp);
1611 while ((opt =
1612 getopt_long (argc, argv, optstring, long_opts, &opt_index)) != -1)
1614 switch (opt)
1616 /* Handle long options without a short option part. */
1617 case 0:
1618 switch (opt_index)
1620 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1621 case OPT_SOCKET_TIMEOUT:
1622 socket_timeout = strtol (optarg, &p, 10);
1623 break;
1624 case OPT_CONNECT_TIMEOUT:
1625 connect_timeout = strtol (optarg, &p, 10);
1626 break;
1627 #endif
1628 #ifdef WITH_SSH
1629 case OPT_USE_SSH_AGENT:
1630 use_ssh_agent = 0;
1631 break;
1632 case OPT_SSH_NEEDS_PASSPHRASE:
1633 needs_passphrase = 1;
1634 break;
1635 #endif
1636 #ifdef WITH_GNUTLS
1637 case OPT_CACERT:
1638 cacert = optarg;
1639 break;
1640 case OPT_CLIENTCERT:
1641 clientcert = optarg;
1642 break;
1643 case OPT_CLIENTKEY:
1644 clientkey = optarg;
1645 break;
1646 case OPT_PRIORITY:
1647 prio = optarg;
1648 break;
1649 case OPT_VERIFY:
1650 tls_verify = 1;
1651 break;
1652 case OPT_SERVER_FP:
1653 tls_fingerprint = optarg;
1654 break;
1655 #endif
1656 case OPT_SYMMETRIC:
1657 symmetric = 1;
1658 break;
1659 case OPT_KEYPARAMS:
1660 keyparams = optarg;
1661 break;
1662 case OPT_KEYFILE:
1663 case OPT_PASSPHRASE_FILE:
1664 keyfile = pwmd_strdup (optarg);
1665 break;
1666 case OPT_NEW_KEYFILE:
1667 case OPT_NEW_PASSPHRASE_FILE:
1668 new_keyfile = pwmd_strdup (optarg);
1669 break;
1670 case OPT_SIGN_KEYFILE:
1671 case OPT_SIGN_PASSPHRASE_FILE:
1672 sign_keyfile = pwmd_strdup (optarg);
1673 break;
1674 case OPT_NOLOCK:
1675 lock_on_open = 0;
1676 break;
1677 case OPT_LOCK_TIMEOUT:
1678 lock_timeout = strtol (optarg, &p, 10);
1679 break;
1680 case OPT_URL:
1681 url = optarg;
1682 break;
1683 case OPT_LOCAL:
1684 local_pin = 1;
1685 break;
1686 case OPT_LC_CTYPE:
1687 lcctype = pwmd_strdup (optarg);
1688 break;
1689 case OPT_LC_MESSAGES:
1690 lcmessages = pwmd_strdup (optarg);
1691 break;
1692 case OPT_TIMEOUT:
1693 timeout = strtol (optarg, &p, 10);
1694 break;
1695 case OPT_TRIES:
1696 tries = strtol (optarg, &p, 10);
1697 break;
1698 case OPT_INQUIRE:
1699 inquire = escape (optarg);
1700 break;
1701 case OPT_INQUIRE_FD:
1702 inquirefd = strtol (optarg, &p, 10);
1703 if (!p)
1705 inquirefp = fdopen (inquirefd, "r");
1706 if (!inquirefp)
1707 err (EXIT_FAILURE, "%i", inquirefd);
1709 break;
1710 case OPT_INQUIRE_FILE:
1711 inquirefd = open (optarg, O_RDONLY);
1712 if (inquirefd == -1)
1713 err (EXIT_FAILURE, "%s", optarg);
1714 inquirefp = fdopen (inquirefd, "r");
1715 break;
1716 case OPT_OUTPUT_FD:
1717 outfd = strtol (optarg, &p, 10);
1718 if (!p || !*p)
1720 outfp = fdopen (outfd, "w");
1721 if (!outfp)
1722 err (EXIT_FAILURE, "%i", outfd);
1724 break;
1725 case OPT_NO_STATUS:
1726 show_status = 0;
1727 break;
1728 case OPT_STATUSFD:
1729 statusfd = strtol (optarg, &p, 10);
1730 if (!p || !*p)
1732 statusfp = fdopen (statusfd, "w");
1733 if (!statusfp)
1734 err (EXIT_FAILURE, "%i", statusfd);
1736 break;
1737 case OPT_STATUS_IGNORE:
1738 parse_status_ignore (optarg);
1739 break;
1740 case OPT_VERSION:
1741 printf ("%s (pwmc)\n\n"
1742 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016\n"
1743 "%s\n"
1744 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1745 "Compile-time features:\n"
1746 #ifdef HAVE_LIBREADLINE
1747 "+INTERACTIVE "
1748 #else
1749 "-INTERACTIVE "
1750 #endif
1751 #ifdef WITH_SSH
1752 "+SSH "
1753 #else
1754 "-SSH "
1755 #endif
1756 #ifdef WITH_GNUTLS
1757 "+GNUTLS "
1758 #else
1759 "-GNUTLS "
1760 #endif
1761 #ifdef WITH_PINENTRY
1762 "+PINENTRY "
1763 #else
1764 "-PINENTRY "
1765 #endif
1766 #ifdef WITH_QUALITY
1767 "+QUALITY "
1768 #else
1769 "-QUALITY "
1770 #endif
1771 #ifdef MEM_DEBUG
1772 "+MEM_DEBUG "
1773 #else
1774 "-MEM_DEBUG "
1775 #endif
1776 "\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1777 exit (EXIT_SUCCESS);
1778 case OPT_PINENTRY:
1779 pinentry_path = optarg;
1780 break;
1781 case OPT_HELP:
1782 usage (argv[0], EXIT_SUCCESS);
1783 case OPT_KEYID:
1784 keyid = optarg;
1785 break;
1786 case OPT_SIGN_KEYID:
1787 sign_keyid = optarg;
1788 break;
1789 case OPT_QUIET:
1790 quiet = 1;
1791 show_status = 0;
1792 break;
1793 case OPT_NO_PINENTRY:
1794 no_pinentry = 1;
1795 break;
1796 #ifdef HAVE_LIBREADLINE
1797 case OPT_INTERACTIVE:
1798 interactive = 1;
1799 break;
1800 #endif
1801 default:
1802 usage (argv[0], EXIT_FAILURE);
1805 if (p && *p)
1807 fprintf (stderr, N_("%s: invalid argument for option '--%s'\n"),
1808 argv[0], long_opts[opt_index].name);
1809 usage (argv[0], EXIT_FAILURE);
1812 break;
1813 #ifdef WITH_SSH
1814 case 'i':
1815 identity = optarg;
1816 break;
1817 case 'k':
1818 knownhosts = optarg;
1819 break;
1820 #endif
1821 case 'L':
1822 inquire_line = optarg;
1823 break;
1824 case 'y':
1825 tty = optarg;
1826 break;
1827 case 't':
1828 ttytype = optarg;
1829 break;
1830 case 'd':
1831 display = optarg;
1832 break;
1833 case 'S':
1834 save = 1;
1835 break;
1836 case 'n':
1837 clientname = optarg;
1838 break;
1839 default:
1840 usage (argv[0], EXIT_FAILURE);
1844 #ifdef HAVE_LIBREADLINE
1845 if (interactive && !isatty (STDIN_FILENO))
1846 usage (argv[0], EXIT_FAILURE);
1847 else if (isatty (STDIN_FILENO) && !inquire && !inquire_line)
1848 interactive = 1;
1849 #endif
1851 pwmd_init ();
1852 rc = pwmd_new (clientname, &pwm);
1853 if (rc)
1854 goto done;
1856 filename = argv[optind] ? pwmd_strdup (argv[optind]) : NULL;
1857 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1858 if (rc)
1859 goto done;
1861 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local_pin);
1862 if (rc)
1863 goto done;
1865 pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
1866 if (!quiet)
1867 fprintf (stderr, N_("Connecting ...\n"));
1869 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1870 socktype = is_remote_url (url);
1871 if (socktype != PWMD_SOCKET_LOCAL)
1873 local_pin = 1;
1874 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1875 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, connect_timeout);
1876 if (rc)
1877 goto done;
1878 #endif
1880 if (socktype == PWMD_SOCKET_SSH)
1882 #ifdef WITH_SSH
1883 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_CB, knownhost_cb);
1884 if (rc)
1885 goto done;
1887 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_DATA, clientname);
1888 if (rc)
1889 goto done;
1891 if (!getenv ("SSH_AUTH_SOCK") || identity)
1892 use_ssh_agent = 0;
1894 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_AGENT, use_ssh_agent);
1895 if (rc)
1896 goto done;
1898 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_NEEDS_PASSPHRASE,
1899 needs_passphrase);
1900 if (rc)
1901 goto done;
1903 rc = pwmd_connect (pwm, url, identity, knownhosts);
1904 #endif
1906 #ifdef WITH_GNUTLS
1907 else
1909 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_VERIFY, tls_verify);
1910 if (rc)
1911 goto done;
1913 rc = pwmd_connect (pwm, url, clientcert, clientkey, cacert, prio,
1914 tls_fingerprint);
1916 #endif
1918 else
1919 rc = pwmd_connect (pwm, url);
1920 #else
1921 rc = pwmd_connect (pwm, url);
1922 #endif
1923 if (rc)
1924 goto done;
1926 if (!quiet)
1927 fprintf (stderr, N_("Connected.\n"));
1929 connected = 1;
1930 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1931 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, socket_timeout);
1932 if (rc)
1933 goto done;
1934 #endif
1936 if (lock_timeout)
1938 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1939 "OPTION LOCK-TIMEOUT=%li", lock_timeout);
1940 if (rc)
1941 goto done;
1944 if (lock_on_open)
1946 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCK_ON_OPEN, 1);
1947 if (rc)
1948 goto done;
1951 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, NULL, NULL);
1952 if (rc)
1953 goto done;
1955 if (timeout > 0)
1957 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
1958 if (rc)
1959 goto done;
1962 if (pinentry_path)
1964 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
1965 if (rc)
1966 goto done;
1969 if (display)
1971 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
1972 if (rc)
1973 goto done;
1976 if (tty)
1978 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, tty);
1979 if (rc)
1980 goto done;
1983 if (ttytype)
1985 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
1986 if (rc)
1987 goto done;
1990 if (lcctype)
1992 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
1993 if (rc)
1994 goto done;
1997 if (lcmessages)
1999 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES, lcmessages);
2000 if (rc)
2001 goto done;
2004 if (show_status)
2006 rc = pwmd_setopt (pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
2007 if (rc)
2008 goto done;
2011 if (filename)
2013 rc = open_command (filename);
2014 if (rc)
2015 goto done;
2018 #ifdef HAVE_LIBREADLINE
2019 if (interactive)
2021 rc = do_interactive ();
2022 result = NULL;
2023 goto do_exit;
2025 #endif
2027 if (inquire)
2029 struct inquire_s *inq = NULL;
2031 rc = set_inquire (inquirefd, inquire_line, &inq);
2032 if (!rc)
2033 rc = pwmd_command (pwm, &result, &len, inquire_cb, inq, "%s", inquire);
2035 free_inquire (inq);
2036 goto done;
2039 if (fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1)
2041 rc = gpg_error_from_errno (errno);
2042 goto done;
2045 ssize_t n;
2047 for (;;)
2049 rc = process_cmd ();
2051 if (rc)
2052 goto done;
2054 n = read (STDIN_FILENO, command, sizeof (command)-1);
2055 if (n == -1)
2057 if (errno == EAGAIN)
2059 usleep (100000);
2060 continue;
2063 rc = gpg_error_from_errno (errno);
2064 goto done;
2066 else if (!n)
2067 goto done;
2069 p = command;
2070 command[n] = 0;
2071 break;
2074 if (!p || !*p || !strcasecmp (p, "BYE"))
2075 goto done;
2078 struct inquire_s *inq = NULL;
2079 rc = set_inquire (inquirefd, inquire_line, &inq);
2080 if (!rc)
2082 rc = parse_dotcommand (command, &result, &len, inq);
2083 free_inquire (inq);
2086 if (rc)
2087 goto done;
2089 done:
2090 if (result)
2092 fwrite (result, 1, result[len - 1] == 0 ? len - 1 : len, outfp);
2093 fflush (outfp);
2094 pwmd_free (result);
2097 result = NULL;
2098 if (!rc)
2099 rc = finalize ();
2100 else if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
2101 (void) pwmd_command (pwm, &result, NULL, NULL, NULL,
2102 "GETINFO last_error");
2104 #ifdef HAVE_LIBREADLINE
2105 do_exit:
2106 #endif
2107 wipememory (command, 0, sizeof (command));
2109 if (rc && !quiet)
2110 show_error (pwm, rc, result);
2112 pwmd_close (pwm);
2113 reset_keyfiles ();
2114 pwmd_deinit ();
2115 pwmd_free (result);
2116 pwmd_free (filename);
2117 parse_status_ignore (NULL);
2118 if (connected && !quiet)
2119 fprintf (stderr, N_("Connection closed.\n"));
2121 exit (rc ? EXIT_FAILURE : EXIT_SUCCESS);