Disable gpg-error memory allocator callback for now.
[libpwmd.git] / src / pwmc.c
blob8e629a2a6e0065097c007f9f20b1f453e245eadf
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 " --ssh-passphrase-file <filename>\n"
189 " read the SSH private key passphrase from filename\n"
190 #endif
191 " --no-lock\n"
192 " do not lock the data file upon opening it\n"
193 " --lock-timeout <N>\n"
194 " time in tenths of a second to wait for a locked data file (50)\n"
195 " --name, -n <string>\n"
196 " set the client name\n"
197 " --pinentry <path>\n"
198 " the full path to the pinentry binary\n"
199 " --local-pinentry\n"
200 " force using a local pinentry\n"
201 " --no-pinentry\n"
202 " disable pinentry both remotely and locally\n"
203 " --ttyname, -y <path>\n"
204 " tty that pinentry will use\n"
205 " --ttytype, -t <string>\n"
206 " pinentry terminal type (default is $TERM)\n"
207 " --display, -d\n"
208 " pinentry display (default is $DISPLAY)\n"
209 " --lc-ctype <string>\n"
210 " locale setting for pinentry\n"
211 " --lc-messages <string>\n"
212 " locale setting for pinentry\n"
213 " --tries <N>\n"
214 " number of pinentry tries before failing (3)\n"
215 " --timeout <seconds>\n"
216 " pinentry timeout\n"
217 " --inquire <COMMAND>\n"
218 " the specified command (with any options) uses a server inquire while\n"
219 " command data is read via the inquire file descriptor (stdin)\n"
220 " --inquire-line, -L <STRING>\n"
221 " the initial line to send (i.e., element path) before the inquire data\n"
222 " --inquire-fd <FD>\n"
223 " read inquire data from the specified file descriptor (stdin)\n"
224 " --inquire-file <filename>\n"
225 " read inquire data from the specified filename\n"
226 " --output-fd <FD>\n"
227 " redirect command output to the specified file descriptor\n"
228 " --save, -S\n"
229 " send the SAVE command before exiting\n"
230 " --passphrase-file <filename>\n"
231 " obtain the passphrase from the specified filename\n"
232 " --new-passphrase-file <filename>\n"
233 " obtain the passphrase to save with from the specified filename\n"
234 " --sign-passphrase-file <filename>\n"
235 " obtain the passphrase to sign with (symmetric) from the specified filename\n"
236 " --key-params <filename>\n"
237 " key parameters to use for key generation (pwmd default)\n"
238 " --keyid <recipient>[,<recipient>]\n"
239 " the public key ID to u\n"
240 " --sign-keyid <string>\n"
241 " the key ID to sign the data file with\n"
242 " --symmetric\n"
243 " use conventional encryption with optional signer(s) for new files\n"
244 " --no-status\n"
245 " disable showing of status messages from the server\n"
246 " --status-fd <FD>\n"
247 " redirect status messages to the specified file descriptor\n"
248 " --status-ignore <string[,...]>\n"
249 " prevent parsing of the specified status message keywords\n"
250 " --quiet\n"
251 " disable showing of extra messages (implies --no-status)\n"
252 #ifdef HAVE_LIBREADLINE
253 " --no-interactive\n"
254 " disable interactive mode\n"
255 #endif
256 " --version\n"
257 " --help\n"),
258 #ifdef DEFAULT_PWMD_SOCKET
259 DEFAULT_PWMD_SOCKET
260 #else
261 "~/.pwmd/socket"
262 #endif
264 fprintf (status == EXIT_FAILURE ? stderr : stdout,
265 N_("\n"
266 "An optional url may be in the form of:\n"
267 " --url /path/to/socket\n"
268 " --url file://[path/to/socket]\n"
269 #ifdef WITH_SSH
270 " or\n"
271 " --url ssh[46]://[username@]hostname[:port]\n"
272 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
273 #endif
274 #ifdef WITH_GNUTLS
275 " or\n"
276 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
277 " --client-key filename\n"
278 #endif
279 #ifdef HAVE_LIBREADLINE
280 "\n"
281 "Interactive mode is used when input is from a terminal.\n"
282 #endif
284 exit (status);
287 static gpg_error_t
288 inquire_cb (void *user, const char *keyword, gpg_error_t rc,
289 char **data, size_t * size)
291 struct inquire_s *inq = user;
292 int is_password = 0;
293 int is_newpassword = 0;
294 int sign = 0;
295 int is_keyparam = 0;
297 *data = NULL;
298 *size = 0;
300 if (rc)
301 return rc;
303 if (!strcmp (keyword, "PASSPHRASE"))
304 is_password = 1;
305 else if (!strcmp (keyword, "SIGN_PASSPHRASE"))
306 sign = 1;
307 else if (!strcmp (keyword, "NEW_PASSPHRASE"))
308 is_newpassword = 1;
309 #ifdef HAVE_LIBREADLINE
310 else if (!strcmp (keyword, "KEYPARAM") && !interactive)
312 #else
313 else if (!strcmp (keyword, "KEYPARAM"))
315 #endif
316 int fd;
317 if (!keyparams || !*keyparams)
318 return gpg_error (GPG_ERR_INV_PARAMETER);
320 fd = open (keyparams, O_RDONLY);
321 if (fd == -1)
323 fprintf (stderr, "%s: %s\n", keyparams, strerror (errno));
324 return gpg_error_from_syserror ();
327 rc = set_inquire (fd, NULL, &inq);
328 if (rc)
330 close (fd);
331 return rc;
334 if (!quiet)
335 fprintf (stderr, N_("Using file '%s' as %s.\n"), keyparams, keyword);
337 is_keyparam = 1;
340 if ((is_password && !keyfile) || (is_newpassword && !new_keyfile)
341 || (sign && !sign_keyfile))
343 char *tmp;
344 int local;
346 /* Try to use the local pinentry between inquires (new/sign/passphrase).
347 * If --no-pinentry was specified then the passphrase is read from the
348 * terminal as usual. */
349 pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local);
350 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, 1);
351 rc = pwmd_password (pwm, keyword, &tmp, &inq->len);
352 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local);
353 if (rc && gpg_err_code (rc) != GPG_ERR_EOF)
354 return rc;
356 pwmd_free (inq->line);
357 inq->line = tmp;
358 *data = inq->line;
359 *size = inq->len;
360 return gpg_error (GPG_ERR_EOF);
362 else if ((is_newpassword && new_keyfile) || (is_password && keyfile)
363 || (sign && sign_keyfile))
365 int fd;
367 if (sign)
368 fd = open (sign_keyfile, O_RDONLY);
369 else
370 fd = open (is_password || sign ? keyfile : new_keyfile, O_RDONLY);
372 if (fd == -1)
374 if (sign)
375 fprintf (stderr, "%s: %s\n", sign_keyfile, strerror (errno));
376 else
377 fprintf (stderr, "%s: %s\n", is_newpassword ? new_keyfile
378 : keyfile, strerror (errno));
379 return gpg_error_from_syserror ();
382 rc = set_inquire (fd, NULL, &inq);
383 if (rc)
385 close (fd);
386 return rc;
389 if (!quiet)
390 fprintf (stderr, N_("Using keyfile '%s' as %s.\n"),
391 sign ? sign_keyfile : is_newpassword ? new_keyfile
392 : keyfile, keyword);
394 #ifdef HAVE_LIBREADLINE
395 else if ((!inq->last_keyword || strcmp (keyword, inq->last_keyword))
396 && interactive && inq->fd == STDIN_FILENO)
398 fprintf (stderr,
400 ("%sPress CTRL-D to send the current line. Press twice to end. %s:\n"),
401 inq->last_keyword ? "\n" : "", keyword);
402 pwmd_free (inq->last_keyword);
403 inq->last_keyword = pwmd_strdup (keyword);
405 #endif
407 /* The first part of the command data. */
408 if (inq->len)
410 *data = inq->line;
411 *size = inq->len;
412 inq->len = 0;
413 return inq->fd == -1 ? gpg_error (GPG_ERR_EOF) : 0;
416 *size = read (inq->fd, inq->line, ASSUAN_LINELENGTH);
417 if (*size == -1)
419 *size = 0;
420 return gpg_error (gpg_error_from_syserror ());
422 else if (*size)
423 *data = inq->line;
424 else if (inq->fd != STDIN_FILENO &&
425 (is_newpassword || is_password || sign || is_keyparam))
427 *inq->line = 0;
428 inq->size = 1;
429 *data = inq->line;
430 *size = 1;
433 if (((is_newpassword && new_keyfile) || (is_password && keyfile)
434 || (sign && sign_keyfile) || (keyparams && is_keyparam))
435 && *size == inq->size)
436 return gpg_error (GPG_ERR_EOF);
438 return *size ? 0 : gpg_error (GPG_ERR_EOF);
441 static int
442 status_msg_cb (void *data, const char *line)
444 char *p = strchr (line, ' ');
445 char **s;
447 /* Ignore status messages specified by the client via --status-ignore. */
448 for (s = status_ignore; s && *s; s++)
450 char *tmp = strchr (line, ' ');
451 size_t len = tmp ? strlen (line) - strlen (tmp) : strlen (line);
453 if (!strncmp (line, *s, len) && len == strlen (*s))
454 return 0;
457 #ifdef HAVE_LIBREADLINE
458 if (interactive && !strncmp (line, "XFER ", 5)
459 #else
460 if (!strncmp (line, "XFER ", 5)
461 #endif
462 && *line != '#' && p && strchr (p, ' ') && *++p)
464 char *p1 = strchr (p, ' ');
465 int a = strtol (p, NULL, 10);
467 if (isdigit (*p) && p1)
469 int b = strtol (p1, NULL, 10);
470 char l[64] = { 0 };
471 int t = a && b ? a * 100 / b : 0;
473 strncpy (l, line, strlen (line) - strlen (p) - 1);
474 fprintf (statusfp, "\rS:%s %i/%i %i%%%s", l, a, b, t,
475 a == b ? "\n" : "");
476 fflush (statusfp);
477 return 0;
481 fprintf (statusfp, "S:%s\n", line);
482 fflush (statusfp);
483 #ifdef HAVE_LIBREADLINE
484 rl_on_new_line ();
485 #endif
486 return 0;
489 static gpg_error_t
490 process_cmd ()
492 return pwmd_process (pwm);
495 #ifdef WITH_SSH
496 static gpg_error_t
497 knownhost_cb (void *data, const char *host, const char *key, size_t len)
499 gpg_error_t rc = 0;
500 char *buf =
501 pwmd_strdup_printf (N_
502 ("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"),
503 (char *) data, host, host);
505 if (no_pinentry && !isatty (STDIN_FILENO))
507 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
508 pwmd_free (buf);
509 return GPG_ERR_ENOTTY;
511 else if (no_pinentry)
513 for (char *p = buf, len = 0; *p; p++, len++)
515 if (*p == '\n')
516 len = 0;
518 if (len == 78)
520 char *t = p;
522 while (len && !isspace (*(--p)))
523 len--;
525 if (len)
526 *p = '\n';
527 len = 78 - len;
528 p = t;
531 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_PROMPT, N_("Accept [y/N]:"));
534 if (!rc)
535 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, buf);
537 pwmd_free (buf);
538 if (rc)
539 return rc;
541 return pwmd_getpin (pwm, NULL, NULL, NULL, PWMD_PINENTRY_CONFIRM);
543 #endif
545 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
546 static pwmd_socket_t
547 is_remote_url (const char *str)
549 if (!str)
550 return PWMD_SOCKET_LOCAL;
552 #ifdef WITH_SSH
553 if (strstr (str, "ssh://") || strstr (str, "ssh4://")
554 || strstr (str, "ssh6://"))
555 return PWMD_SOCKET_SSH;
556 #endif
558 #ifdef WITH_GNUTLS
559 if (strstr (str, "tls://") || strstr (str, "tls4://")
560 || strstr (str, "tls6://"))
561 return PWMD_SOCKET_TLS;
562 #endif
564 return PWMD_SOCKET_LOCAL;
566 #endif
568 static char *
569 escape (const char *str)
571 const char *p;
572 char *buf = pwmd_malloc (ASSUAN_LINELENGTH + 1), *b = buf;
573 size_t len = 0;
575 for (p = str; *p; p++, len++)
577 if (len == ASSUAN_LINELENGTH)
578 break;
580 if (*p == '\\')
582 switch (*++p)
584 case 't':
585 *b++ = '\t';
586 break;
587 case 'n':
588 *b++ = '\n';
589 break;
590 case 'v':
591 *b++ = '\v';
592 break;
593 case 'b':
594 *b++ = '\b';
595 break;
596 case 'f':
597 *b++ = '\f';
598 break;
599 case 'r':
600 *b++ = '\r';
601 break;
602 default:
603 *b++ = *p;
604 break;
607 if (!*p)
608 break;
610 continue;
613 *b++ = *p;
616 *b = 0;
617 return buf;
620 static void
621 free_inquire (struct inquire_s *inq)
623 if (!inq)
624 return;
626 pwmd_free (inq->line);
628 if (inq->fd != -1 && inq->fd != STDIN_FILENO)
629 close (inq->fd);
631 pwmd_free (inq->last_keyword);
632 pwmd_free (inq);
635 /* When *result is not NULL it is updated to the new values and not
636 * reallocated. */
637 static gpg_error_t
638 set_inquire (int fd, const char *line, struct inquire_s **result)
640 struct inquire_s inq = { 0 };
641 struct stat st = { 0 };
642 gpg_error_t rc;
644 if (fd != -1)
646 if (fstat (fd, &st) == -1)
647 return gpg_error_from_syserror ();
649 inq.size = st.st_size;
652 inq.fd = fd;
653 inq.line = pwmd_calloc (1, ASSUAN_LINELENGTH);
654 if (!inq.line)
655 return GPG_ERR_ENOMEM;
657 if (line)
659 char *s = escape (line);
661 if (!s)
663 pwmd_free (inq.line);
664 return GPG_ERR_ENOMEM;
667 if (strlen (s) >= ASSUAN_LINELENGTH)
669 pwmd_free (inq.line);
670 pwmd_free (s);
671 return GPG_ERR_LINE_TOO_LONG;
674 strncpy (inq.line, s, ASSUAN_LINELENGTH - 1);
675 inq.len = strlen (s);
676 pwmd_free (s);
679 rc = pwmd_setopt (pwm, PWMD_OPTION_INQUIRE_TOTAL,
680 st.st_size ? st.st_size + strlen (inq.line) : 0);
681 if (rc)
683 pwmd_free (inq.line);
684 return rc;
687 if (*result == NULL)
688 *result = pwmd_malloc (sizeof (struct inquire_s));
689 else
691 if ((*result)->fd != -1 && (*result)->fd != STDIN_FILENO)
692 close ((*result)->fd);
694 pwmd_free ((*result)->line);
695 (*result)->line = NULL;
696 (*result)->fd = -1;
697 (*result)->len = 0;
700 memcpy (*result, &inq, sizeof (struct inquire_s));
701 memset (&inq, 0, sizeof (struct inquire_s));
702 return rc;
705 #ifdef HAVE_LIBREADLINE
706 static int
707 interactive_hook (void)
709 interactive_error = process_cmd ();
711 if (interactive_error)
712 rl_event_hook = NULL;
714 return 0;
717 static int
718 get_readline_char (FILE *fp)
720 if (rl_line_buffer
721 && (!strncmp (rl_line_buffer, ".set passphrase-file ", 16)
722 || !strncmp (rl_line_buffer, ".set new-passphrase-file ", 20)
723 || !strncmp (rl_line_buffer, ".set sign-passphrase-file ", 21)))
724 rl_inhibit_completion = 0;
725 else if (rl_line_buffer
726 && !strncmp (rl_line_buffer, ".redir ", 7))
728 char *p = strchr (rl_line_buffer, ' ');
730 if (strchr (++p, ' '))
731 rl_inhibit_completion = 1;
732 else
733 rl_inhibit_completion = 0;
735 else if (rl_line_buffer
736 && !strncmp (rl_line_buffer, ".read ", 6))
738 char *p = rl_line_buffer + 6;
740 if (strstr (p, "--prefix "))
742 p = strstr (p, "--prefix ");
743 p += 9;
744 p = strchr (p, ' ');
745 if (p)
746 p++;
749 if (!p || strchr (p, ' '))
750 rl_inhibit_completion = 1;
751 else
752 rl_inhibit_completion = 0;
754 else
755 rl_inhibit_completion = 1;
757 return fgetc (fp);
760 static void
761 print_help ()
763 fprintf (stderr,
765 ("------------------------------------------------------------\n"
766 "Elements are TAB delimited. Type HELP for protocol commands.\n"
767 "Type .help for pwmc commands. Press CTRL-D to quit.\n"
768 "------------------------------------------------------------\n"));
770 #endif
772 static char *
773 parse_arg (const char *src, char *dst, size_t len)
775 char *p = dst;
776 const char *s = src;
777 size_t n = 0;
779 for (; s && *s && *s != ' ' && n < len; s++, n++)
780 *p++ = *s;
782 *p = 0;
783 return dst;
786 static char *
787 parse_opt (char **line, const char *opt, gpg_error_t * rc)
789 static char result[ASSUAN_LINELENGTH] = { 0 }, *r = result;
790 char *s = strstr (*line, opt);
792 *rc = 0;
793 result[0] = 0;
794 r = result;
796 if (s)
798 size_t len = 0;
799 int quote = 0;
800 size_t rlen = strlen (opt);
801 char *p = s + rlen;
802 int lastc = 0;
804 while (*p && *p == ' ')
806 rlen++;
807 p++;
810 for (; *p && len < sizeof (result) - 1; p++, rlen++)
812 if (isspace (*p) && !quote)
813 break;
815 if (*p == '\"' && lastc != '\\')
817 quote = !quote;
818 lastc = *p;
819 continue;
822 *r++ = lastc = *p;
823 len++;
826 *r = 0;
828 if (len >= sizeof (result) - 1)
829 *rc = GPG_ERR_LINE_TOO_LONG;
830 else
832 p = s + rlen;
834 while (*p && *p == ' ')
835 p++;
837 *line = p;
841 return result;
844 static gpg_error_t
845 read_command (const char *line, char **result, size_t * len)
847 int fd;
848 gpg_error_t rc = 0;
849 char *file = NULL;
850 struct inquire_s *inq = NULL;
851 char *p = (char *) line;
852 const char *prefix = parse_opt (&p, "--prefix", &rc);
853 char filebuf[ASSUAN_LINELENGTH];
855 if (rc)
856 return rc;
858 rc = GPG_ERR_SYNTAX;
860 if (p && *p)
862 while (*p && isspace (*p))
863 p++;
865 file = parse_arg (p, filebuf, sizeof (filebuf));
866 if (file && *file)
868 p += strlen (file) + 1;
870 while (*p && isspace (*p))
871 p++;
873 if (*p)
874 rc = 0;
878 if (rc)
880 fprintf (stderr,
882 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
883 fprintf (stderr,
885 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\\ = \\)\n"));
886 return rc;
889 fd = open (file, O_RDONLY);
890 if (fd == -1)
891 return gpg_error_from_syserror ();
893 rc = set_inquire (fd, prefix && *prefix ? prefix : NULL, &inq);
894 if (rc)
896 close (fd);
897 return rc;
900 rc = pwmd_command (pwm, result, len, inquire_cb, inq, "%s", p);
901 free_inquire (inq);
902 return rc;
905 static gpg_error_t
906 redir_command (const char *line)
908 const char *p = line;
909 int fd;
910 gpg_error_t rc = GPG_ERR_SYNTAX;
911 char *file = NULL;
912 struct inquire_s *inq = NULL;
913 char *result = NULL;
914 size_t len = 0;
915 char filebuf[ASSUAN_LINELENGTH];
917 if (p && *p && *++p)
919 file = parse_arg (p, filebuf, sizeof (filebuf));
920 if (file && *file)
922 p += strlen (file) + 1;
924 while (*p && isspace (*p))
925 p++;
927 if (*p)
928 rc = 0;
932 if (rc)
934 fprintf (stderr, N_("Usage: .redir <filename> <command> [args]\n"));
935 return rc;
938 fd = open (file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
939 if (fd == -1)
940 return gpg_error_from_syserror ();
942 #ifdef HAVE_LIBREADLINE
943 rc = set_inquire (interactive ? STDIN_FILENO : inquirefd, NULL, &inq);
944 #else
945 rc = set_inquire (inquirefd, NULL, &inq);
946 #endif
947 if (rc)
949 close (fd);
950 return rc;
953 rc = parse_dotcommand (p, &result, &len, inq);
954 if (!rc && result && len--)
955 { // null byte which is always appended
956 if (write (fd, result, len) != len)
957 rc = GPG_ERR_TOO_SHORT;
958 pwmd_free (result);
961 free_inquire (inq);
962 close (fd);
963 return rc;
966 static gpg_error_t
967 help_command (const char *line)
969 fprintf (stderr,
970 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
971 " .redir <filename> <command>\n"
972 " redirect the output of a command to the specified file\n"
973 "\n"
974 " .open <filename>\n"
975 " open the specified filename losing any changes to the current one\n"
976 "\n"
977 " .read [--prefix <string>] <filename> <command> [args]\n"
978 " obtain data from the specified filename for an inquire command\n"
979 "\n"
980 " .set help | <name> [<value>]\n"
981 " set option <name> to <value>\n"
982 "\n"
983 " .save [args]\n"
984 " write changes of the file to disk\n"
985 "\n"
986 " .passwd [args]\n"
987 " change the passphrase of a data file\n"
988 "\n"
989 " .help\n"
990 " this help text\n"));
991 return 0;
994 static gpg_error_t
995 open_command (char *line)
997 struct inquire_s *inq = NULL;
998 const char *file = line;
999 gpg_error_t rc;
1000 int local;
1002 while (file && isspace (*file))
1003 file++;
1005 if (!file || !*file)
1007 fprintf (stderr, N_("Usage: .open <filename>\n"));
1008 return GPG_ERR_SYNTAX;
1011 #ifdef HAVE_LIBREADLINE
1012 if (interactive || !quiet)
1013 #else
1014 if (!quiet)
1015 #endif
1016 fprintf (stderr, N_("Opening data file \"%s\" ...\n"), file);
1018 #ifdef HAVE_LIBREADLINE
1019 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1020 #else
1021 rc = set_inquire (-1, NULL, &inq);
1022 #endif
1023 if (rc)
1024 return rc;
1026 pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local);
1028 if (keyfile)
1030 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1031 if (!rc)
1032 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, 1);
1034 else
1035 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1037 if (!rc)
1038 rc = pwmd_open (pwm, file, inquire_cb, inq);
1040 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local);
1042 #ifdef HAVE_LIBREADLINE
1043 if (interactive)
1044 reset_keyfiles ();
1045 #endif
1047 free_inquire (inq);
1048 if (!rc && file != filename)
1050 pwmd_free (filename);
1051 filename = pwmd_strdup (file);
1054 return rc;
1057 static gpg_error_t
1058 set_command (const char *line)
1060 gpg_error_t rc = 0;
1061 char name[256] = { 0 };
1062 char value[512] = { 0 };
1063 char *namep;
1064 char *valuep;
1065 const char *p = line;
1067 while (p && *p && isspace (*p))
1068 p++;
1070 namep = parse_arg (p, name, sizeof (name));
1071 if (!namep || !*namep)
1073 fprintf (stderr, N_("Usage: .set help | <name> [<value>]\n"));
1074 return GPG_ERR_SYNTAX;
1077 p += strlen (namep);
1078 while (p && *p && isspace (*p))
1079 p++;
1081 valuep = parse_arg (p, value, sizeof (value));
1083 if (!strcmp (name, "passphrase-file") || !strcmp (name, "new-passphrase-file")
1084 || !strcmp (name, "sign-passphrase-file"))
1086 int is_newkeyfile = 1;
1087 int sign = !strcmp (name, "sign-passphrase-file");
1089 if (!strcmp (name, "passphrase-file") || sign)
1090 is_newkeyfile = 0;
1092 if (is_newkeyfile)
1094 pwmd_free (new_keyfile);
1095 new_keyfile = NULL;
1097 else if (sign)
1099 pwmd_free (sign_keyfile);
1100 sign_keyfile = NULL;
1102 else
1104 pwmd_free (keyfile);
1105 keyfile = NULL;
1108 if (!rc && *valuep)
1110 if (is_newkeyfile)
1111 new_keyfile = pwmd_strdup (value);
1112 else if (sign)
1113 sign_keyfile = pwmd_strdup (value);
1114 else
1115 keyfile = pwmd_strdup (value);
1117 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1119 else if (!local_pin && !no_pinentry)
1121 pwmd_socket_t t;
1123 pwmd_socket_type (pwm, &t);
1124 if (t == PWMD_SOCKET_LOCAL)
1125 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1128 else if (!strcmp(name, "pinentry-timeout"))
1130 char *e = NULL;
1131 int n = strtol(valuep, &e, 10);
1133 if (e && *e)
1134 return gpg_error (GPG_ERR_INV_VALUE);
1136 if (!*valuep)
1137 n = DEFAULT_PIN_TIMEOUT;
1139 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, n);
1141 else if (!strcmp (name, "help"))
1143 fprintf (stderr,
1145 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1146 "delimited. When no value is specified the option is unset.\n\n"
1147 "passphrase-file [<filename>]\n"
1148 " set or unset the file to be used when a passphrase is required (*)\n"
1149 "\n"
1150 "new-passphrase-file [<filename>]\n"
1151 " set or unset the file to be used when a new passphrase is required (*)\n"
1152 "\n"
1153 "sign-passphrase-file [<filename>]\n"
1154 " set or unset the file to be used when a passphrase is required for\n"
1155 " signing (symmetric) (*)\n"
1156 "\n"
1157 "pinentry-timeout <seconds>\n"
1158 " the amount of seconds before pinentry gives up waiting for input\n"
1159 "\n"
1160 "* = the next protocol command will unset this value\n"
1163 else
1164 rc = GPG_ERR_UNKNOWN_OPTION;
1166 return rc;
1169 static gpg_error_t
1170 do_save_passwd_command (const char *line, int save)
1172 struct inquire_s *inq = NULL;
1173 gpg_error_t rc;
1174 int local;
1176 #ifdef HAVE_LIBREADLINE
1177 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1178 #else
1179 rc = set_inquire (-1, NULL, &inq);
1180 #endif
1181 if (rc)
1182 return rc;
1184 pwmd_getopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, &local);
1186 if (new_keyfile || keyfile || sign_keyfile)
1188 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1189 if (!rc)
1190 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, 1);
1192 else
1193 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1195 if (!rc)
1197 if (save)
1198 rc = pwmd_save (pwm, line, inquire_cb, inq);
1199 else
1200 rc = pwmd_passwd (pwm, line, inquire_cb, inq);
1203 pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local);
1205 #ifdef HAVE_LIBREADLINE
1206 if (interactive)
1207 reset_keyfiles ();
1208 #endif
1210 free_inquire (inq);
1211 return rc;
1214 static gpg_error_t
1215 save_command (const char *line)
1217 return do_save_passwd_command (line, 1);
1220 static gpg_error_t
1221 parse_dotcommand (const char *line, char **result,
1222 size_t * len, struct inquire_s *inq)
1224 const char *p = line;
1225 gpg_error_t rc = 0;
1227 if (!strncmp (p, ".read", 5))
1228 rc = read_command (p + 5, result, len);
1229 else if (!strncmp (p, ".redir", 6))
1230 rc = redir_command (p + 6);
1231 else if (!strncmp (p, ".help", 5))
1232 rc = help_command (p + 5);
1233 else if (!strncmp (p, ".open", 5))
1234 rc = open_command ((char *)p + 5);
1235 else if (!strncmp (p, ".set", 4))
1236 rc = set_command (p + 4);
1237 else if (!strncmp (p, ".save", 5))
1238 rc = do_save_passwd_command (p + 5, 1);
1239 else if (!strncmp (p, ".passwd", 7))
1240 rc = do_save_passwd_command (p + 7, 0);
1241 else
1243 rc = pwmd_command (pwm, result, len, inquire_cb, inq, "%s", line);
1244 #ifdef HAVE_LIBREADLINE
1245 if (interactive)
1247 #endif
1248 reset_keyfiles ();
1249 #ifdef HAVE_LIBREADLINE
1251 #endif
1253 if (!rc && !strncasecmp (line, "RESET", 5))
1255 pwmd_free (filename);
1256 filename = NULL;
1260 return FINISH (rc);
1263 #ifdef HAVE_LIBREADLINE
1264 #ifdef HAVE_READLINE_HISTORY
1265 static void
1266 add_history_item (const char *line)
1268 HIST_ENTRY **list, *p = NULL;
1269 int i;
1271 list = history_list ();
1272 for (i = 0; list && list[i]; i++)
1274 if (!strcmp (list[i]->line, line))
1276 p = list[i];
1277 break;
1281 if (p)
1283 char *s;
1285 p = remove_history (i);
1286 s = free_history_entry (p);
1287 free (s);
1290 add_history (line);
1292 #endif
1294 static gpg_error_t
1295 do_interactive ()
1297 gpg_error_t rc;
1298 struct inquire_s *inq = NULL;
1300 rl_initialize ();
1301 rc = process_cmd ();
1302 if (rc)
1303 return rc;
1305 rc = set_inquire (STDIN_FILENO, NULL, &inq);
1306 if (rc)
1307 return rc;
1309 fprintf (stderr,
1310 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1311 print_help ();
1312 rl_event_hook = &interactive_hook;
1313 rl_getc_function = get_readline_char;
1314 rl_set_keyboard_input_timeout (100000);
1316 for (;;)
1318 char *line;
1319 char *result = NULL;
1320 size_t len;
1321 char buf[255];
1323 rc = 0;
1324 snprintf (buf, sizeof (buf), "pwmc%s%s> ",
1325 filename ? ":" : "", filename ? filename : "");
1326 line = readline (buf);
1327 if (interactive_error)
1329 free (line);
1330 rc = interactive_error;
1331 break;
1334 if (!line)
1336 rc = finalize ();
1337 if (!rc)
1338 break;
1340 if (gpg_err_code (rc) != GPG_ERR_CANCELED &&
1341 gpg_err_code (rc) != GPG_ERR_EOF)
1342 fprintf (stderr, "ERR %i: %s\n", rc, gpg_strerror (rc));
1344 continue;
1346 else if (!*line)
1348 free (line);
1349 continue;
1352 #ifdef HAVE_READLINE_HISTORY
1353 add_history_item (line);
1354 #endif
1355 rc = parse_dotcommand (line, &result, &len, inq);
1356 free (line);
1357 if (rc)
1359 char *tmp = NULL;
1361 if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
1362 (void) pwmd_command (pwm, &tmp, NULL, NULL, NULL,
1363 "GETINFO last_error");
1365 show_error (pwm, rc, tmp);
1366 pwmd_free (tmp);
1368 else if (result && len)
1369 printf ("%s%s", result, result[len - 1] != '\n' ? "\n" : "");
1371 pwmd_free (result);
1374 free_inquire (inq);
1375 return rc;
1377 #endif
1379 static gpg_error_t
1380 finalize ()
1382 gpg_error_t rc = 0;
1383 #ifdef HAVE_LIBREADLINE
1384 int quit = 0;
1386 if (interactive)
1388 int finished = 0;
1390 fprintf (stderr, "\n");
1394 char *p, buf[16];
1396 fprintf (stderr,
1398 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1399 p = fgets (buf, sizeof (buf), stdin);
1401 if (feof (stdin))
1403 clearerr (stdin);
1404 return GPG_ERR_EOF;
1407 switch (*p)
1409 case 'h':
1410 print_help ();
1411 break;
1412 case 'c':
1413 return GPG_ERR_CANCELED;
1414 case 'Q':
1415 return 0;
1416 case 'f':
1417 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1418 "CLEARCACHE %s", filename);
1419 if (rc)
1420 return rc;
1422 interactive_hook ();
1423 break;
1424 case 'S':
1425 quit = 1;
1426 case 's':
1427 save = 1;
1428 finished = 1;
1429 break;
1430 default:
1431 break;
1434 while (!finished);
1436 #endif
1438 if (save && !filename)
1440 fprintf (stderr,
1442 ("No filename was specified on the command line. Aborting.\n"));
1443 return GPG_ERR_CANCELED;
1446 if (save && filename)
1448 char *args =
1449 pwmd_strdup_printf ("%s %s%s %s%s %s",
1450 symmetric ? "--symmetric" : "",
1451 keyid ? "--keyid=" : "",
1452 keyid ? keyid : "",
1453 sign_keyid ? "--sign-keyid=" : "",
1454 sign_keyid ? sign_keyid : "",
1455 keyparams ? "--inquire-keyparam" : "");
1457 #ifdef HAVE_LIBREADLINE
1458 if (!quiet || interactive)
1460 #else
1461 if (!quiet)
1463 #endif
1464 fprintf (stderr, "\n");
1465 fprintf (stderr, N_("Saving changes ...\n"));
1468 rc = save_command (args);
1469 pwmd_free (args);
1472 #ifdef HAVE_LIBREADLINE
1473 if (interactive)
1474 return rc ? rc : quit ? 0 : GPG_ERR_CANCELED;
1475 #endif
1477 return rc;
1480 static void
1481 parse_status_ignore (char *str)
1483 size_t n = 0;
1484 char **p, *s;
1486 for (p = status_ignore; p && *p; p++)
1487 pwmd_free (*p);
1489 pwmd_free (status_ignore);
1490 status_ignore = NULL;
1491 if (!str || !*str)
1492 return;
1494 while ((s = strsep (&str, ",")))
1496 p = pwmd_realloc (status_ignore, (n + 2) * sizeof (char *));
1497 p[n++] = pwmd_strdup (s);
1498 p[n] = NULL;
1499 status_ignore = p;
1504 main (int argc, char *argv[])
1506 int connected = 0;
1507 gpg_error_t rc;
1508 int opt;
1509 char command[ASSUAN_LINELENGTH], *p = NULL;
1510 char *result = NULL;
1511 size_t len = 0;
1512 char *pinentry_path = NULL;
1513 char *display = NULL, *tty = NULL, *ttytype = NULL;
1514 char *lcctype = NULL, *lcmessages = NULL;
1515 int outfd = STDOUT_FILENO;
1516 FILE *outfp = stdout;
1517 FILE *inquirefp = stdin;
1518 int show_status = 1;
1519 char *clientname = "pwmc";
1520 char *inquire = NULL;
1521 char *inquire_line = NULL;
1522 int timeout = 0;
1523 #ifdef WITH_SSH
1524 int use_ssh_agent = 1;
1525 char *knownhosts = NULL;
1526 char *identity = NULL;
1527 int needs_passphrase = 0;
1528 char *ssh_passphrase_file = NULL;
1529 #endif
1530 #ifdef WITH_GNUTLS
1531 char *cacert = NULL;
1532 char *clientcert = NULL;
1533 char *clientkey = NULL;
1534 char *prio = NULL;
1535 int tls_verify = 0;
1536 char *tls_fingerprint = NULL;
1537 #endif
1538 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1539 pwmd_socket_t socktype;
1540 long socket_timeout = 300;
1541 int connect_timeout = 120;
1542 #endif
1543 #ifdef HAVE_LIBREADLINE
1544 int no_interactive = 0;
1545 #endif
1546 int lock_on_open = 1;
1547 long lock_timeout = 50;
1548 char *url = NULL;
1549 char *tmp = NULL;
1550 /* The order is important. */
1551 enum
1553 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1554 OPT_SOCKET_TIMEOUT, OPT_CONNECT_TIMEOUT,
1555 #endif
1556 #ifdef WITH_SSH
1557 OPT_USE_SSH_AGENT, OPT_IDENTITY, OPT_KNOWNHOSTS, OPT_SSH_NEEDS_PASSPHRASE,
1558 OPT_SSH_PASSPHRASE_FILE,
1559 #endif
1560 #ifdef WITH_GNUTLS
1561 OPT_CACERT, OPT_CLIENTCERT, OPT_CLIENTKEY, OPT_PRIORITY, OPT_VERIFY,
1562 OPT_SERVER_FP,
1563 #endif
1564 OPT_URL, OPT_LOCAL, OPT_TTYNAME, OPT_TTYTYPE, OPT_DISPLAY, OPT_LC_CTYPE,
1565 OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES, OPT_PINENTRY, OPT_KEYFILE,
1566 OPT_PASSPHRASE_FILE, OPT_NEW_KEYFILE, OPT_NEW_PASSPHRASE_FILE,
1567 OPT_SIGN_KEYFILE, OPT_SIGN_PASSPHRASE_FILE, OPT_NOLOCK, OPT_LOCK_TIMEOUT,
1568 OPT_SAVE, OPT_OUTPUT_FD, OPT_INQUIRE, OPT_INQUIRE_FD, OPT_INQUIRE_FILE,
1569 OPT_INQUIRE_LINE, OPT_NO_STATUS, OPT_STATUS_IGNORE, OPT_STATUSFD, OPT_NAME,
1570 OPT_VERSION, OPT_HELP, OPT_KEYID, OPT_SIGN_KEYID, OPT_SYMMETRIC,
1571 OPT_KEYPARAMS, OPT_NO_PINENTRY, OPT_QUIET,
1572 #ifdef HAVE_LIBREADLINE
1573 OPT_NO_INTERACTIVE,
1574 #endif
1576 const struct option long_opts[] = {
1577 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1578 {"socket-timeout", 1, 0, 0},
1579 {"connect-timeout", 1, 0, 0},
1580 #endif
1582 #ifdef WITH_SSH
1583 {"no-ssh-agent", 0, 0, 0},
1584 {"identity", 1, 0, 'i'},
1585 {"knownhosts", 1, 0, 'k'},
1586 {"ssh-needs-passphrase", 0, 0, 0},
1587 {"ssh-passphrase-file", 1, 0, 0},
1588 #endif
1589 #ifdef WITH_GNUTLS
1590 {"ca-cert", 1, 0, 0},
1591 {"client-cert", 1, 0, 0},
1592 {"client-key", 1, 0, 0},
1593 {"tls-priority", 1, 0, 0},
1594 {"tls-verify", 0, 0, 0},
1595 {"tls-fingerprint", 1, 0, 0},
1596 #endif
1597 {"url", 1, 0, 0},
1598 {"local-pinentry", 0, 0},
1599 {"ttyname", 1, 0, 'y'},
1600 {"ttytype", 1, 0, 't'},
1601 {"display", 1, 0, 'd'},
1602 {"lc-ctype", 1, 0, 0},
1603 {"lc-messages", 1, 0, 0},
1604 {"timeout", 1, 0, 0},
1605 {"tries", 1, 0, 0},
1606 {"pinentry", 1, 0, 0},
1607 {"key-file", 1, 0, 0},
1608 {"passphrase-file", 1, 0, 0},
1609 {"new-key-file", 1, 0, 0},
1610 {"new-passphrase-file", 1, 0, 0},
1611 {"sign-key-file", 1, 0, 0},
1612 {"sign-passphrase-file", 1, 0, 0},
1613 {"no-lock", 0, 0, 0},
1614 {"lock-timeout", 1, 0, 0},
1615 {"save", 0, 0, 'S'},
1616 {"output-fd", 1, 0, 0},
1617 {"inquire", 1, 0, 0},
1618 {"inquire-fd", 1, 0, 0},
1619 {"inquire-file", 1, 0, 0},
1620 {"inquire-line", 1, 0, 'L'},
1621 {"no-status", 0, 0, 0},
1622 {"status-ignore", 1, 0, 0},
1623 {"status-fd", 1, 0, 0},
1624 {"name", 1, 0, 'n'},
1625 {"version", 0, 0, 0},
1626 {"help", 0, 0, 0},
1627 {"keyid", 1, 0, 0},
1628 {"sign-keyid", 1, 0, 0},
1629 {"symmetric", 0, 0, 0},
1630 {"key-params", 1, 0, 0},
1631 {"no-pinentry", 0, 0, 0},
1632 {"quiet", 0, 0, 0},
1633 #ifdef HAVE_LIBREADLINE
1634 {"no-interactive", 0, 0},
1635 #endif
1636 {0, 0, 0, 0}
1638 #ifdef WITH_SSH
1639 const char *optstring = "L:y:t:d:P:I:Sn:i:k:s";
1640 #else
1641 const char *optstring = "L:y:t:d:P:I:Sn:s";
1642 #endif
1643 int opt_index = 0;
1645 #ifdef ENABLE_NLS
1646 setlocale (LC_ALL, "");
1647 bindtextdomain ("libpwmd", LOCALEDIR);
1648 #endif
1650 tries = DEFAULT_PIN_TRIES;
1651 inquirefd = STDIN_FILENO;
1652 statusfd = STDERR_FILENO;
1653 statusfp = stderr;
1654 tmp = pwmd_strdup (DEFAULT_STATUS_IGNORE);
1655 parse_status_ignore (tmp);
1656 pwmd_free (tmp);
1658 while ((opt =
1659 getopt_long (argc, argv, optstring, long_opts, &opt_index)) != -1)
1661 switch (opt)
1663 /* Handle long options without a short option part. */
1664 case 0:
1665 switch (opt_index)
1667 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1668 case OPT_SOCKET_TIMEOUT:
1669 socket_timeout = strtol (optarg, &p, 10);
1670 break;
1671 case OPT_CONNECT_TIMEOUT:
1672 connect_timeout = strtol (optarg, &p, 10);
1673 break;
1674 #endif
1675 #ifdef WITH_SSH
1676 case OPT_USE_SSH_AGENT:
1677 use_ssh_agent = 0;
1678 break;
1679 case OPT_SSH_NEEDS_PASSPHRASE:
1680 needs_passphrase = 1;
1681 break;
1682 case OPT_SSH_PASSPHRASE_FILE:
1683 ssh_passphrase_file = optarg;
1684 break;
1685 #endif
1686 #ifdef WITH_GNUTLS
1687 case OPT_CACERT:
1688 cacert = optarg;
1689 break;
1690 case OPT_CLIENTCERT:
1691 clientcert = optarg;
1692 break;
1693 case OPT_CLIENTKEY:
1694 clientkey = optarg;
1695 break;
1696 case OPT_PRIORITY:
1697 prio = optarg;
1698 break;
1699 case OPT_VERIFY:
1700 tls_verify = 1;
1701 break;
1702 case OPT_SERVER_FP:
1703 tls_fingerprint = optarg;
1704 break;
1705 #endif
1706 case OPT_SYMMETRIC:
1707 symmetric = 1;
1708 break;
1709 case OPT_KEYPARAMS:
1710 keyparams = optarg;
1711 break;
1712 case OPT_KEYFILE:
1713 case OPT_PASSPHRASE_FILE:
1714 keyfile = pwmd_strdup (optarg);
1715 break;
1716 case OPT_NEW_KEYFILE:
1717 case OPT_NEW_PASSPHRASE_FILE:
1718 new_keyfile = pwmd_strdup (optarg);
1719 break;
1720 case OPT_SIGN_KEYFILE:
1721 case OPT_SIGN_PASSPHRASE_FILE:
1722 sign_keyfile = pwmd_strdup (optarg);
1723 break;
1724 case OPT_NOLOCK:
1725 lock_on_open = 0;
1726 break;
1727 case OPT_LOCK_TIMEOUT:
1728 lock_timeout = strtol (optarg, &p, 10);
1729 break;
1730 case OPT_URL:
1731 url = optarg;
1732 break;
1733 case OPT_LOCAL:
1734 local_pin = 1;
1735 break;
1736 case OPT_LC_CTYPE:
1737 lcctype = pwmd_strdup (optarg);
1738 break;
1739 case OPT_LC_MESSAGES:
1740 lcmessages = pwmd_strdup (optarg);
1741 break;
1742 case OPT_TIMEOUT:
1743 timeout = strtol (optarg, &p, 10);
1744 break;
1745 case OPT_TRIES:
1746 tries = strtol (optarg, &p, 10);
1747 break;
1748 case OPT_INQUIRE:
1749 inquire = escape (optarg);
1750 break;
1751 case OPT_INQUIRE_FD:
1752 inquirefd = strtol (optarg, &p, 10);
1753 if (!p)
1755 inquirefp = fdopen (inquirefd, "r");
1756 if (!inquirefp)
1757 err (EXIT_FAILURE, "%i", inquirefd);
1759 break;
1760 case OPT_INQUIRE_FILE:
1761 inquirefd = open (optarg, O_RDONLY);
1762 if (inquirefd == -1)
1763 err (EXIT_FAILURE, "%s", optarg);
1764 inquirefp = fdopen (inquirefd, "r");
1765 break;
1766 case OPT_OUTPUT_FD:
1767 outfd = strtol (optarg, &p, 10);
1768 if (!p || !*p)
1770 outfp = fdopen (outfd, "w");
1771 if (!outfp)
1772 err (EXIT_FAILURE, "%i", outfd);
1774 break;
1775 case OPT_NO_STATUS:
1776 show_status = 0;
1777 break;
1778 case OPT_STATUSFD:
1779 statusfd = strtol (optarg, &p, 10);
1780 if (!p || !*p)
1782 statusfp = fdopen (statusfd, "w");
1783 if (!statusfp)
1784 err (EXIT_FAILURE, "%i", statusfd);
1786 break;
1787 case OPT_STATUS_IGNORE:
1788 parse_status_ignore (optarg);
1789 break;
1790 case OPT_VERSION:
1791 printf ("%s (pwmc)\n\n"
1792 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016\n"
1793 "%s\n"
1794 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1795 "Compile-time features:\n"
1796 #ifdef HAVE_LIBREADLINE
1797 "+INTERACTIVE "
1798 #else
1799 "-INTERACTIVE "
1800 #endif
1801 #ifdef WITH_SSH
1802 "+SSH "
1803 #else
1804 "-SSH "
1805 #endif
1806 #ifdef WITH_GNUTLS
1807 "+GNUTLS "
1808 #else
1809 "-GNUTLS "
1810 #endif
1811 #ifdef WITH_PINENTRY
1812 "+PINENTRY "
1813 #else
1814 "-PINENTRY "
1815 #endif
1816 #ifdef WITH_QUALITY
1817 "+QUALITY "
1818 #else
1819 "-QUALITY "
1820 #endif
1821 #ifdef MEM_DEBUG
1822 "+MEM_DEBUG "
1823 #else
1824 "-MEM_DEBUG "
1825 #endif
1826 "\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1827 exit (EXIT_SUCCESS);
1828 case OPT_PINENTRY:
1829 pinentry_path = optarg;
1830 break;
1831 case OPT_HELP:
1832 usage (argv[0], EXIT_SUCCESS);
1833 case OPT_KEYID:
1834 keyid = optarg;
1835 break;
1836 case OPT_SIGN_KEYID:
1837 sign_keyid = optarg;
1838 break;
1839 case OPT_QUIET:
1840 quiet = 1;
1841 show_status = 0;
1842 break;
1843 case OPT_NO_PINENTRY:
1844 no_pinentry = 1;
1845 break;
1846 #ifdef HAVE_LIBREADLINE
1847 case OPT_NO_INTERACTIVE:
1848 no_interactive = 1;
1849 break;
1850 #endif
1851 default:
1852 usage (argv[0], EXIT_FAILURE);
1855 if (p && *p)
1857 fprintf (stderr, N_("%s: invalid argument for option '--%s'\n"),
1858 argv[0], long_opts[opt_index].name);
1859 usage (argv[0], EXIT_FAILURE);
1862 break;
1863 #ifdef WITH_SSH
1864 case 'i':
1865 identity = optarg;
1866 break;
1867 case 'k':
1868 knownhosts = optarg;
1869 break;
1870 #endif
1871 case 'L':
1872 inquire_line = optarg;
1873 break;
1874 case 'y':
1875 tty = optarg;
1876 break;
1877 case 't':
1878 ttytype = optarg;
1879 break;
1880 case 'd':
1881 display = optarg;
1882 break;
1883 case 'S':
1884 save = 1;
1885 break;
1886 case 'n':
1887 clientname = optarg;
1888 break;
1889 default:
1890 usage (argv[0], EXIT_FAILURE);
1894 #ifdef HAVE_LIBREADLINE
1895 if (isatty (STDIN_FILENO) && !inquire && !inquire_line && !no_interactive)
1896 interactive = 1;
1897 #endif
1899 pwmd_init ();
1900 rc = pwmd_new (clientname, &pwm);
1901 if (rc)
1902 goto done;
1904 filename = argv[optind] ? pwmd_strdup (argv[optind]) : NULL;
1905 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1906 if (rc)
1907 goto done;
1909 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY, local_pin);
1910 if (rc)
1911 goto done;
1913 pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
1914 if (!quiet)
1915 fprintf (stderr, N_("Connecting ...\n"));
1917 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1918 socktype = is_remote_url (url);
1919 if (socktype != PWMD_SOCKET_LOCAL)
1921 local_pin = 1;
1922 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1923 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, connect_timeout);
1924 if (rc)
1925 goto done;
1926 #endif
1928 if (socktype == PWMD_SOCKET_SSH)
1930 #ifdef WITH_SSH
1931 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_CB, knownhost_cb);
1932 if (rc)
1933 goto done;
1935 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_DATA, clientname);
1936 if (rc)
1937 goto done;
1939 if (!getenv ("SSH_AUTH_SOCK") || identity)
1940 use_ssh_agent = 0;
1942 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_AGENT, use_ssh_agent);
1943 if (rc)
1944 goto done;
1946 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_NEEDS_PASSPHRASE,
1947 needs_passphrase);
1948 if (rc)
1949 goto done;
1951 if (ssh_passphrase_file)
1953 struct stat st;
1954 int fd;
1956 if (stat (ssh_passphrase_file, &st) == -1)
1958 rc = gpg_error_from_syserror ();
1959 fprintf(stderr, "%s: %s\n", ssh_passphrase_file,
1960 gpg_strerror (rc));
1961 goto done;
1964 result = pwmd_calloc (1, st.st_size+1);
1965 if (!result)
1967 rc = GPG_ERR_ENOMEM;
1968 goto done;
1971 fd = open (ssh_passphrase_file, O_RDONLY);
1972 if (fd != -1)
1974 len = read (fd, result, st.st_size);
1975 if (len == st.st_size)
1976 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_PASSPHRASE, result);
1977 else
1978 rc = gpg_error_from_syserror ();
1980 close (fd);
1982 else
1983 rc = gpg_error_from_syserror ();
1985 pwmd_free (result);
1986 result = NULL;
1987 len = 0;
1989 if (rc)
1991 fprintf(stderr, "%s: %s\n", ssh_passphrase_file,
1992 gpg_strerror (rc));
1993 goto done;
1997 rc = pwmd_connect (pwm, url, identity, knownhosts);
1998 #endif
2000 #ifdef WITH_GNUTLS
2001 else
2003 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_VERIFY, tls_verify);
2004 if (rc)
2005 goto done;
2007 rc = pwmd_connect (pwm, url, clientcert, clientkey, cacert, prio,
2008 tls_fingerprint);
2010 #endif
2012 else
2013 rc = pwmd_connect (pwm, url);
2014 #else
2015 rc = pwmd_connect (pwm, url);
2016 #endif
2017 if (rc)
2018 goto done;
2020 if (!quiet)
2021 fprintf (stderr, N_("Connected.\n"));
2023 connected = 1;
2024 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2025 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, socket_timeout);
2026 if (rc)
2027 goto done;
2028 #endif
2030 if (lock_timeout)
2032 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
2033 "OPTION LOCK-TIMEOUT=%li", lock_timeout);
2034 if (rc)
2035 goto done;
2038 if (lock_on_open)
2040 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCK_ON_OPEN, 1);
2041 if (rc)
2042 goto done;
2045 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, NULL, NULL);
2046 if (rc)
2047 goto done;
2049 if (timeout > 0)
2051 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
2052 if (rc)
2053 goto done;
2056 if (pinentry_path)
2058 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
2059 if (rc)
2060 goto done;
2063 if (display)
2065 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
2066 if (rc)
2067 goto done;
2070 if (tty)
2072 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, tty);
2073 if (rc)
2074 goto done;
2077 if (ttytype)
2079 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
2080 if (rc)
2081 goto done;
2084 if (lcctype)
2086 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
2087 if (rc)
2088 goto done;
2091 if (lcmessages)
2093 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES, lcmessages);
2094 if (rc)
2095 goto done;
2098 if (show_status)
2100 rc = pwmd_setopt (pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
2101 if (rc)
2102 goto done;
2105 if (filename)
2107 rc = open_command (filename);
2108 if (rc)
2109 goto done;
2112 #ifdef HAVE_LIBREADLINE
2113 if (interactive)
2115 rc = do_interactive ();
2116 result = NULL;
2117 goto do_exit;
2119 #endif
2121 if (inquire)
2123 struct inquire_s *inq = NULL;
2125 rc = set_inquire (inquirefd, inquire_line, &inq);
2126 if (!rc)
2127 rc = pwmd_command (pwm, &result, &len, inquire_cb, inq, "%s", inquire);
2129 free_inquire (inq);
2130 goto done;
2133 if (fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1)
2135 rc = gpg_error_from_errno (errno);
2136 goto done;
2139 ssize_t n;
2141 for (;;)
2143 rc = process_cmd ();
2145 if (rc)
2146 goto done;
2148 n = read (STDIN_FILENO, command, sizeof (command)-1);
2149 if (n == -1)
2151 if (errno == EAGAIN)
2153 usleep (100000);
2154 continue;
2157 rc = gpg_error_from_errno (errno);
2158 goto done;
2160 else if (!n)
2161 goto done;
2163 p = command;
2164 command[n] = 0;
2165 break;
2168 if (!p || !*p || !strcasecmp (p, "BYE"))
2169 goto done;
2172 struct inquire_s *inq = NULL;
2173 rc = set_inquire (inquirefd, inquire_line, &inq);
2174 if (!rc)
2176 rc = parse_dotcommand (command, &result, &len, inq);
2177 free_inquire (inq);
2180 if (rc)
2181 goto done;
2183 done:
2184 if (result)
2186 fwrite (result, 1, result[len - 1] == 0 ? len - 1 : len, outfp);
2187 fflush (outfp);
2188 pwmd_free (result);
2191 result = NULL;
2192 if (!rc)
2193 rc = finalize ();
2194 else if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
2195 (void) pwmd_command (pwm, &result, NULL, NULL, NULL,
2196 "GETINFO last_error");
2198 #ifdef HAVE_LIBREADLINE
2199 do_exit:
2200 #endif
2201 wipememory (command, 0, sizeof (command));
2203 if (rc && !quiet)
2204 show_error (pwm, rc, result);
2206 pwmd_close (pwm);
2207 reset_keyfiles ();
2208 pwmd_deinit ();
2209 pwmd_free (result);
2210 pwmd_free (filename);
2211 parse_status_ignore (NULL);
2212 if (connected && !quiet)
2213 fprintf (stderr, N_("Connection closed.\n"));
2215 exit (rc ? EXIT_FAILURE : EXIT_SUCCESS);