Fix parsing of the STATE status message.
[libpwmd.git] / src / pwmc.c
blob348e24c681bc85cbca609a902c406b6e5d948f6a
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015
3 Ben Kibbey <bjk@luxsci.net>
5 This file is part of libpwmd.
7 Libpwmd is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 2 of the License, or
10 (at your option) any later version.
12 Libpwmd is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Libpwmd. If not, see <http://www.gnu.org/licenses/>.
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <stdint.h>
28 #include <err.h>
29 #include <errno.h>
30 #include <string.h>
31 #include <libpwmd.h>
32 #include <assuan.h>
33 #include <sys/select.h>
34 #include <fcntl.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <libgen.h>
38 #include <termios.h>
39 #include <limits.h>
40 #include <ctype.h>
42 #ifdef WITH_GNUTLS
43 #include <gnutls/gnutls.h>
44 #endif
46 #ifdef HAVE_LOCALE_H
47 #include <locale.h>
48 #endif
50 #ifdef HAVE_GETOPT_LONG
51 #ifdef HAVE_GETOPT_H
52 #include <getopt.h>
53 #endif
54 #else
55 #include "getopt_long.h"
56 #endif
58 #ifdef HAVE_LIBREADLINE
59 #if defined(HAVE_READLINE_READLINE_H)
60 #include <readline/readline.h>
61 #elif defined(HAVE_READLINE_H)
62 #include <readline.h>
63 #endif /* !defined(HAVE_READLINE_H) */
64 static int interactive_error;
65 static int interactive;
66 #endif /* HAVE_LIBREADLINE */
68 #ifdef HAVE_READLINE_HISTORY
69 #if defined(HAVE_READLINE_HISTORY_H)
70 #include <readline/history.h>
71 #elif defined(HAVE_HISTORY_H)
72 #include <history.h>
73 #endif
74 #endif /* HAVE_READLINE_HISTORY */
76 #ifndef LINE_MAX
77 #define LINE_MAX 2048
78 #endif
80 #include "gettext.h"
81 #define N_(msgid) gettext(msgid)
83 #include "mem.h"
86 #define DEFAULT_STATUS_IGNORE "KEEPALIVE,STATE,GPGME,PASSPHRASE_INFO,PASSPHRASE_HINT"
87 #define DEFAULT_PIN_TIMEOUT 30
88 #define DEFAULT_PIN_TRIES 3
89 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
90 ? gpg_error(rc) : rc
92 static int no_pinentry;
93 static pwm_t *pwm;
94 static char *filename;
95 static int save;
96 static char *keyid;
97 static char *sign_keyid;
98 static char *keyparams;
99 static char *keyfile;
100 static char *new_keyfile;
101 static int tries;
102 static int local_pin;
103 static int inquirefd;
104 static int statusfd;
105 FILE *statusfp;
106 static int quiet;
107 static char **status_ignore;
109 struct inquire_s
111 int fd;
112 char *line;
113 size_t len;
114 size_t size; // from stat(2).
115 char *last_keyword;
118 static gpg_error_t finalize ();
119 static gpg_error_t set_inquire (int fd, const char *line,
120 struct inquire_s **result);
121 static gpg_error_t parse_dotcommand (const char *line, char **result,
122 size_t * len, struct inquire_s *inq);
123 static gpg_error_t open_command (const char *line);
124 #ifdef WITH_SSH
125 static gpg_error_t get_password (char **result, pwmd_pinentry_t w, int echo);
126 #endif
128 static void
129 show_error (pwm_t *pwm, gpg_error_t rc, const char *str)
131 #ifdef WITH_GNUTLS
132 if (pwmd_tls_error (pwm))
133 fprintf(stderr, "TLS: %s\n", gnutls_strerror(pwmd_tls_error(pwm)));
134 #endif
135 fprintf (stderr, "ERR %i: %s%s%s%s", rc, gpg_strerror (rc),
136 str ? ": " : "", str ? str : "", str ? "" : "\n");
139 static void
140 usage (const char *pn, int status)
142 fprintf (status == EXIT_FAILURE ? stderr : stdout,
143 N_("Usage: pwmc [options] [file]\n"
144 " --url <string>\n"
145 " a url string to connect to (%s, see below)\n"
146 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
147 " --connect-timeout <seconds>\n"
148 " seconds before connecting to a remote host fails (0=disabled, 120)\n"
149 " --socket-timeout <seconds>\n"
150 " seconds before a remote command fails (0=disabled, 300)\n"
151 #endif
152 #ifdef WITH_GNUTLS
153 " --ca-cert <filename>\n"
154 " certificate authority (CA) used to sign the server cert\n"
155 " --client-cert <filename>\n"
156 " client certificate to use for authentication\n"
157 " --client-key <filename>\n"
158 " key file used to protect the client certificate\n"
159 " --tls-priority <string>\n"
160 " compression, cipher and hash algorithm string (SECURE256)\n"
161 " --tls-verify\n"
162 " verify the hostname against the server certificate\n"
163 " --tls-fingerprint <string>\n"
164 " a SHA-256 hash of the server fingerprint to verify against\n"
165 #endif
166 #ifdef WITH_SSH
167 " --no-ssh-agent\n"
168 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
169 " --identity, -i <filename>\n"
170 " the ssh identity file to use for authentication\n"
171 " --knownhosts, -k <filename>\n"
172 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
173 #endif
174 " --no-lock\n"
175 " do not lock the data file upon opening it\n"
176 " --lock-timeout <N>\n"
177 " time in tenths of a second to wait for a locked data file (50)\n"
178 " --name, -n <string>\n"
179 " set the client name\n"
180 " --pinentry <path>\n"
181 " the full path to the pinentry binary\n"
182 " --local-pinentry\n"
183 " force using a local pinentry\n"
184 " --no-pinentry\n"
185 " disable pinentry both remotely and locally\n"
186 " --ttyname, -y <path>\n"
187 " tty that pinentry will use\n"
188 " --ttytype, -t <string>\n"
189 " pinentry terminal type (default is $TERM)\n"
190 " --display, -d\n"
191 " pinentry display (default is $DISPLAY)\n"
192 " --lc-ctype <string>\n"
193 " locale setting for pinentry\n"
194 " --lc-messages <string>\n"
195 " locale setting for pinentry\n"
196 " --tries <N>\n"
197 " number of pinentry tries before failing (3)\n"
198 " --timeout <seconds>\n"
199 " pinentry timeout\n"
200 " --inquire <COMMAND>\n"
201 " the specified command (with any options) uses a server inquire while\n"
202 " command data is read via the inquire file descriptor (stdin)\n"
203 " --inquire-line, -L <STRING>\n"
204 " the initial line to send (i.e., element path) before the inquire data\n"
205 " --inquire-fd <FD>\n"
206 " read inquire data from the specified file descriptor (stdin)\n"
207 " --inquire-file <filename>\n"
208 " read inquire data from the specified filename\n"
209 " --output-fd <FD>\n"
210 " redirect command output to the specified file descriptor\n"
211 " --save, -S\n"
212 " send the SAVE command before exiting\n"
213 " --key-file <filename>\n"
214 " obtain the passphrase from the specified filename\n"
215 " --new-key-file <filename>\n"
216 " obtain the passphrase to save with from the specified filename\n"
217 " --key-params <string>\n"
218 " the key parameters to use when saving a new file (pwmd default)\n"
219 " --keyid <recipient>[,<recipient>]\n"
220 " the public key ID to u\n"
221 " --sign-keyid <string>\n"
222 " the key ID to sign the data file with\n"
223 " --no-status\n"
224 " disable showing of status messages from the server\n"
225 " --status-ignore <string[,...]>\n"
226 " prevent parsing of the specified status message keywords\n"
227 " --quiet\n"
228 " disable showing of extra messages (implies --no-status)\n"
229 " --status-fd <FD>\n"
230 " redirect status messages to the specified file descriptor\n"
231 #ifdef HAVE_LIBREADLINE
232 " --interactive\n"
233 " use a shell like interface to pwmd (allows more than one command)\n"
234 #endif
235 " --version\n"
236 " --help\n"),
237 #ifdef DEFAULT_PWMD_SOCKET
238 DEFAULT_PWMD_SOCKET
239 #else
240 "~/.pwmd/socket"
241 #endif
243 fprintf (status == EXIT_FAILURE ? stderr : stdout,
244 N_("\n"
245 "An optional url may be in the form of:\n"
246 " --url /path/to/socket\n"
247 " --url file://[path/to/socket]\n"
248 #ifdef WITH_SSH
249 " or\n"
250 " --url ssh[46]://[username@]hostname[:port]\n"
251 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
252 #endif
253 #ifdef WITH_GNUTLS
254 " or\n"
255 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
256 " --client-key filename\n"
257 #endif
258 #ifdef HAVE_LIBREADLINE
259 "\n"
260 "Interactive mode is used when input is from a terminal.\n"
261 #endif
263 exit (status);
266 static gpg_error_t
267 inquire_cb (void *user, const char *keyword, gpg_error_t rc,
268 char **data, size_t * size)
270 struct inquire_s *inq = user;
271 int is_password = 0;
272 int is_newpassword = 0;
274 *data = NULL;
275 *size = 0;
277 if (rc)
278 return rc;
280 if (!strcmp (keyword, "PASSPHRASE"))
281 is_password = 1;
282 else if (!strcmp (keyword, "NEW_PASSPHRASE"))
283 is_newpassword = 1;
284 #ifdef HAVE_LIBREADLINE
285 else if (!strcmp (keyword, "KEYPARAM") && !interactive)
287 #else
288 else if (!strcmp (keyword, "KEYPARAM"))
290 #endif
291 if (!keyparams || !*keyparams)
292 return gpg_error (GPG_ERR_INV_PARAMETER);
294 *data = keyparams;
295 *size = strlen (keyparams);
296 return gpg_error (GPG_ERR_EOF);
299 if ((is_newpassword && new_keyfile) || (is_password && keyfile))
301 int fd = open (is_password ? keyfile : new_keyfile, O_RDONLY);
303 if (fd == -1)
305 fprintf (stderr, "%s: %s\n", is_newpassword ? new_keyfile : keyfile,
306 strerror (errno));
307 return gpg_error_from_syserror ();
310 rc = set_inquire (fd, NULL, &inq);
311 if (rc)
313 close (fd);
314 return rc;
317 if (!quiet)
318 fprintf (stderr, N_("Using keyfile '%s' as %s.\n"),
319 is_newpassword ? new_keyfile : keyfile, keyword);
321 if (!new_keyfile || is_newpassword)
323 pwmd_socket_t t;
325 pwmd_socket_type (pwm, &t);
326 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
327 if (!no_pinentry && t == PWMD_SOCKET_LOCAL)
328 pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 0);
331 else if ((is_password && !keyfile) || (is_newpassword && !new_keyfile))
333 char *tmp;
335 rc = pwmd_password (pwm, keyword, &tmp, &inq->len);
336 if (rc && gpg_err_code (rc) != GPG_ERR_EOF)
337 return rc;
339 pwmd_free (inq->line);
340 inq->line = tmp;
341 *data = inq->line;
342 *size = inq->len;
343 return gpg_error (GPG_ERR_EOF);
345 #ifdef HAVE_LIBREADLINE
346 else if ((!inq->last_keyword || strcmp (keyword, inq->last_keyword))
347 && interactive)
349 fprintf (stderr,
351 ("%sPress CTRL-D to send the current line. Press twice to end. %s:\n"),
352 inq->last_keyword ? "\n" : "", keyword);
353 pwmd_free (inq->last_keyword);
354 inq->last_keyword = pwmd_strdup (keyword);
356 #endif
358 /* The first part of the command data. */
359 if (inq->len)
361 *data = inq->line;
362 *size = inq->len;
363 inq->len = 0;
364 return inq->fd == -1 ? gpg_error (GPG_ERR_EOF) : 0;
367 *size = read (inq->fd, inq->line, ASSUAN_LINELENGTH);
368 if (*size == -1)
370 *size = 0;
371 return gpg_error (gpg_error_from_syserror ());
373 else if (*size)
374 *data = inq->line;
375 else if (inq->fd != STDIN_FILENO && (is_newpassword || is_password))
377 *inq->line = 0;
378 inq->size = 1;
379 *data = inq->line;
380 *size = 1;
383 if (((is_newpassword && new_keyfile) || (is_password && keyfile))
384 && *size == inq->size)
385 return gpg_error (GPG_ERR_EOF);
387 return *size ? 0 : gpg_error (GPG_ERR_EOF);
390 static int
391 status_msg_cb (void *data, const char *line)
393 char *p = strchr (line, ' ');
394 char **s;
396 /* Ignore status messages specified by the client via --status-ignore. */
397 for (s = status_ignore; s && *s; s++)
399 char *tmp = strchr (line, ' ');
400 size_t len = tmp ? strlen (line) - strlen (tmp) : strlen (line);
402 if (!strncmp (line, *s, len) && len == strlen (*s))
403 return 0;
406 if (statusfd != STDERR_FILENO && strncmp (line, "STATE ", 6) && *line != '#'
407 && p && strchr (p, ' ') && *++p)
409 char *p1 = strchr (p, ' ');
410 int a = strtol (p, NULL, 10);
412 if (isdigit (*p) && p1)
414 int b = strtol (p1, NULL, 10);
415 char l[64] = { 0 };
416 int t = a && b ? a * 100 / b : 0;
418 strncpy (l, line, strlen (line) - strlen (p) - 1);
419 fprintf (statusfp, "\r%s %i/%i %i%%%s", l, a, b, t,
420 a == b ? "\n" : "");
421 fflush (statusfp);
422 return 0;
426 fprintf (statusfp, "%s\n", line);
427 fflush (statusfp);
428 #ifdef HAVE_LIBREADLINE
429 rl_on_new_line ();
430 #endif
431 return 0;
434 static gpg_error_t
435 process_cmd ()
437 return pwmd_process (pwm);
440 #ifdef WITH_SSH
441 static gpg_error_t
442 get_password (char **result, pwmd_pinentry_t w, int echo)
444 char buf[LINE_MAX] = { 0 }, *p;
445 struct termios told, tnew;
446 char *key = NULL;
448 *result = NULL;
450 if (!isatty (STDIN_FILENO))
452 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
453 return GPG_ERR_ENOTTY;
456 if (!echo)
458 if (tcgetattr (STDIN_FILENO, &told) == -1)
459 return gpg_error_from_syserror ();
461 memcpy (&tnew, &told, sizeof (struct termios));
462 tnew.c_lflag &= ~(ECHO);
463 tnew.c_lflag |= ICANON | ECHONL;
465 if (tcsetattr (STDIN_FILENO, TCSANOW, &tnew) == -1)
467 int n = errno;
469 tcsetattr (STDIN_FILENO, TCSANOW, &told);
470 return gpg_error_from_errno (n);
474 switch (w)
476 case PWMD_PINENTRY_OPEN:
477 fprintf (stderr, N_("Password for %s: "), filename);
478 break;
479 case PWMD_PINENTRY_OPEN_FAILED:
480 fprintf (stderr, N_("Invalid password. Password for %s: "), filename);
481 break;
482 case PWMD_PINENTRY_SAVE:
483 fprintf (stderr, N_("New password for %s: "), filename);
484 break;
485 case PWMD_PINENTRY_SAVE_CONFIRM:
486 fprintf (stderr, N_("Confirm password: "));
487 break;
488 default:
489 break;
492 if ((p = fgets (buf, sizeof (buf), stdin)) == NULL)
494 tcsetattr (STDIN_FILENO, TCSANOW, &told);
495 return 0;
498 if (!echo)
499 tcsetattr (STDIN_FILENO, TCSANOW, &told);
501 if (feof (stdin))
503 clearerr (stdin);
504 return GPG_ERR_CANCELED;
507 p[strlen (p) - 1] = 0;
509 if (buf[0])
511 key = pwmd_strdup_printf ("%s", p);
512 memset (&buf, 0, sizeof (buf));
514 if (!key)
515 return GPG_ERR_ENOMEM;
518 *result = key;
519 return 0;
522 static gpg_error_t
523 knownhost_cb (void *data, const char *host, const char *key, size_t len)
525 gpg_error_t rc;
526 char *buf =
527 pwmd_strdup_printf (N_
528 ("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?"),
529 (char *) data, host, host);
531 if (no_pinentry && !isatty (STDIN_FILENO))
533 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
534 pwmd_free (buf);
535 return GPG_ERR_ENOTTY;
537 else if (no_pinentry)
539 for (char *p = buf, len = 0; *p; p++, len++)
541 if (*p == '\n')
542 len = 0;
544 if (len == 78)
546 char *t = p;
548 while (!isspace (*(--p)));
549 *p = '\n';
550 p = t;
551 len = 0;
555 fprintf (stderr, "%s\n\n", buf);
556 pwmd_free (buf);
560 char *result;
562 fprintf (stderr, N_("Trust this connection [y/N]: "));
563 fflush (stderr);
564 rc = get_password (&result, PWMD_PINENTRY_CONFIRM, 1);
566 if (rc)
567 return rc;
569 if (!result || !*result || *result == 'n' || *result == 'N')
571 if (result && *result)
572 pwmd_free (result);
574 return GPG_ERR_NOT_CONFIRMED;
577 if ((*result == 'y' || *result == 'Y') && *(result + 1) == 0)
579 pwmd_free (result);
580 return 0;
583 while (1);
586 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, buf);
587 pwmd_free (buf);
589 if (rc)
590 return rc;
592 return pwmd_getpin (pwm, NULL, NULL, NULL, PWMD_PINENTRY_CONFIRM);
594 #endif
596 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
597 static pwmd_socket_t
598 is_remote_url (const char *str)
600 if (!str)
601 return PWMD_SOCKET_LOCAL;
603 #ifdef WITH_SSH
604 if (strstr (str, "ssh://") || strstr (str, "ssh4://")
605 || strstr (str, "ssh6://"))
606 return PWMD_SOCKET_SSH;
607 #endif
609 #ifdef WITH_GNUTLS
610 if (strstr (str, "tls://") || strstr (str, "tls4://")
611 || strstr (str, "tls6://"))
612 return PWMD_SOCKET_TLS;
613 #endif
615 return PWMD_SOCKET_LOCAL;
617 #endif
619 static char *
620 escape (const char *str)
622 const char *p;
623 char *buf = pwmd_malloc (ASSUAN_LINELENGTH + 1), *b = buf;
624 size_t len = 0;
626 for (p = str; *p; p++, len++)
628 if (len == ASSUAN_LINELENGTH)
629 break;
631 if (*p == '\\')
633 switch (*++p)
635 case 't':
636 *b++ = '\t';
637 break;
638 case 'n':
639 *b++ = '\n';
640 break;
641 case 'v':
642 *b++ = '\v';
643 break;
644 case 'b':
645 *b++ = '\b';
646 break;
647 case 'f':
648 *b++ = '\f';
649 break;
650 case 'r':
651 *b++ = '\r';
652 break;
653 default:
654 *b++ = *p;
655 break;
658 if (!*p)
659 break;
661 continue;
664 *b++ = *p;
667 *b = 0;
668 return buf;
671 static void
672 free_inquire (struct inquire_s *inq)
674 if (!inq)
675 return;
677 pwmd_free (inq->line);
679 if (inq->fd != -1 && inq->fd != STDIN_FILENO)
680 close (inq->fd);
682 pwmd_free (inq->last_keyword);
683 pwmd_free (inq);
686 /* When *result is not NULL it is updated to the new values and not
687 * reallocated. */
688 static gpg_error_t
689 set_inquire (int fd, const char *line, struct inquire_s **result)
691 struct inquire_s inq = { 0 };
692 struct stat st = { 0 };
693 gpg_error_t rc;
695 if (fd != -1)
697 if (fstat (fd, &st) == -1)
698 return gpg_error_from_syserror ();
700 inq.size = st.st_size;
703 inq.fd = fd;
704 inq.line = pwmd_calloc (1, ASSUAN_LINELENGTH);
705 if (!inq.line)
706 return GPG_ERR_ENOMEM;
708 if (line)
710 char *s = escape (line);
712 if (!s)
714 pwmd_free (inq.line);
715 return GPG_ERR_ENOMEM;
718 if (strlen (s) >= ASSUAN_LINELENGTH)
720 pwmd_free (inq.line);
721 pwmd_free (s);
722 return GPG_ERR_LINE_TOO_LONG;
725 strncpy (inq.line, s, ASSUAN_LINELENGTH - 1);
726 inq.len = strlen (s);
727 pwmd_free (s);
730 rc = pwmd_setopt (pwm, PWMD_OPTION_INQUIRE_TOTAL,
731 st.st_size ? st.st_size + strlen (inq.line) : 0);
732 if (rc)
734 pwmd_free (inq.line);
735 return rc;
738 if (*result == NULL)
739 *result = pwmd_malloc (sizeof (struct inquire_s));
740 else
742 if ((*result)->fd != -1 && (*result)->fd != STDIN_FILENO)
743 close ((*result)->fd);
745 pwmd_free ((*result)->line);
746 (*result)->line = NULL;
747 (*result)->fd = -1;
748 (*result)->len = 0;
751 memcpy (*result, &inq, sizeof (struct inquire_s));
752 memset (&inq, 0, sizeof (struct inquire_s));
753 return rc;
756 #ifdef HAVE_LIBREADLINE
757 static int
758 interactive_hook (void)
760 interactive_error = process_cmd ();
762 if (interactive_error)
763 rl_event_hook = NULL;
765 return 0;
768 static void
769 print_help ()
771 fprintf (stderr,
773 ("------------------------------------------------------------------------------\n"
774 "Elements are TAB delimited. Press CTRL-V then TAB to insert from the prompt.\n"
775 "\n"
776 "Type HELP for protocol commands. Type .help for pwmc commands. Press CTRL-D\n"
777 "to quit.\n"
778 "------------------------------------------------------------------------------\n"));
780 #endif
782 static char *
783 parse_arg (const char *src, char *dst, size_t len)
785 char *p = dst;
786 const char *s = src;
787 size_t n = 0;
789 for (; s && *s && *s != ' ' && n < len; s++, n++)
790 *p++ = *s;
792 *p = 0;
793 return dst;
796 static char *
797 parse_opt (char **line, const char *opt, gpg_error_t * rc)
799 static char result[ASSUAN_LINELENGTH] = { 0 }, *r = result;
800 char *s = strstr (*line, opt);
802 *rc = 0;
803 result[0] = 0;
804 r = result;
806 if (s)
808 size_t len = 0;
809 int quote = 0;
810 size_t rlen = strlen (opt);
811 char *p = s + rlen;
812 int lastc = 0;
814 while (*p && *p == ' ')
816 rlen++;
817 p++;
820 for (; *p && len < sizeof (result) - 1; p++, rlen++)
822 if (isspace (*p) && !quote)
823 break;
825 if (*p == '\"' && lastc != '\\')
827 quote = !quote;
828 lastc = *p;
829 continue;
832 *r++ = lastc = *p;
833 len++;
836 *r = 0;
838 if (len >= sizeof (result) - 1)
839 *rc = GPG_ERR_LINE_TOO_LONG;
840 else
842 p = s + rlen;
844 while (*p && *p == ' ')
845 p++;
847 *line = p;
851 return result;
854 static gpg_error_t
855 read_command (const char *line, char **result, size_t * len)
857 int fd;
858 gpg_error_t rc = 0;
859 char *filename = NULL;
860 struct inquire_s *inq = NULL;
861 char *p = (char *) line;
862 const char *prefix = parse_opt (&p, "--prefix", &rc);
864 if (rc)
865 return rc;
867 rc = GPG_ERR_SYNTAX;
869 if (p && *p)
871 char filebuf[ASSUAN_LINELENGTH];
873 while (*p && isspace (*p))
874 p++;
876 filename = parse_arg (p, filebuf, sizeof (filebuf));
877 if (filename && *filename)
879 p += strlen (filename) + 1;
881 while (*p && isspace (*p))
882 p++;
884 if (*p)
885 rc = 0;
889 if (rc)
891 fprintf (stderr,
893 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
894 fprintf (stderr,
896 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\" = \")\n"));
897 return rc;
900 fd = open (filename, O_RDONLY);
901 if (fd == -1)
902 return gpg_error_from_syserror ();
904 rc = set_inquire (fd, prefix && *prefix ? prefix : NULL, &inq);
905 if (rc)
907 close (fd);
908 return rc;
911 rc = pwmd_command (pwm, result, len, inquire_cb, inq, p);
912 free_inquire (inq);
913 return rc;
916 static gpg_error_t
917 redir_command (const char *line)
919 const char *p = line;
920 int fd;
921 gpg_error_t rc = GPG_ERR_SYNTAX;
922 char *filename = NULL;
923 struct inquire_s *inq = NULL;
924 char *result = NULL;
925 size_t len = 0;
927 if (p && *p && *++p)
929 char filebuf[ASSUAN_LINELENGTH];
931 filename = parse_arg (p, filebuf, sizeof (filebuf));
932 if (filename && *filename)
934 p += strlen (filename) + 1;
936 while (*p && isspace (*p))
937 p++;
939 if (*p)
940 rc = 0;
944 if (rc)
946 fprintf (stderr, N_("Usage: .redir <filename> <command> [args]\n"));
947 return rc;
950 fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
951 if (fd == -1)
952 return gpg_error_from_syserror ();
954 #ifdef HAVE_LIBREADLINE
955 rc = set_inquire (interactive ? STDIN_FILENO : inquirefd, NULL, &inq);
956 #else
957 rc = set_inquire (inquirefd, NULL, &inq);
958 #endif
959 if (rc)
961 close (fd);
962 return rc;
965 rc = parse_dotcommand (p, &result, &len, inq);
966 if (!rc && result && len--)
967 { // null byte which is always appended
968 if (write (fd, result, len) != len)
969 rc = GPG_ERR_TOO_SHORT;
970 pwmd_free (result);
973 free_inquire (inq);
974 close (fd);
975 return rc;
978 static gpg_error_t
979 help_command (const char *line)
981 fprintf (stderr,
982 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
983 " .redir <filename> <command>\n"
984 " redirect the output of a command to the specified file\n"
985 "\n"
986 " .open <filename>\n"
987 " open the specified filename losing any changes to the current one\n"
988 "\n"
989 " .read [--prefix <string>] <filename> <command> [args]\n"
990 " obtain data from the specified filename for an inquire command\n"
991 "\n"
992 " .set help | <name> [<value>]\n"
993 " set option <name> to <value>\n"
994 "\n"
995 " .save [args]\n"
996 " write changes of the file to disk\n"
997 "\n"
998 " .passwd [args]\n"
999 " change the passphrase of a data file\n"
1000 "\n"
1001 " .help\n"
1002 " this help text\n"));
1003 return 0;
1006 static gpg_error_t
1007 open_command (const char *line)
1009 struct inquire_s *inq = NULL;
1010 const char *filename = line;
1011 gpg_error_t rc;
1013 while (filename && isspace (*filename))
1014 filename++;
1016 if (!filename || !*filename)
1018 fprintf (stderr, N_("Usage: .open <filename>\n"));
1019 return GPG_ERR_SYNTAX;
1022 #ifdef HAVE_LIBREADLINE
1023 if (interactive || !quiet)
1024 #else
1025 if (!quiet)
1026 #endif
1027 fprintf (stderr, N_("Opening data file \"%s\" ...\n"), filename);
1029 #ifdef HAVE_LIBREADLINE
1030 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1031 #else
1032 rc = set_inquire (-1, NULL, &inq);
1033 #endif
1034 if (rc)
1035 return rc;
1037 if (keyfile)
1038 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1039 else
1040 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1042 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1043 rc = pwmd_open (pwm, filename, inquire_cb, inq);
1044 free_inquire (inq);
1045 return rc;
1048 static gpg_error_t
1049 set_command (const char *line)
1051 gpg_error_t rc = 0;
1052 char name[256] = { 0 };
1053 char value[512] = { 0 };
1054 char *namep;
1055 char *valuep;
1056 const char *p = line;
1058 while (p && *p && isspace (*p))
1059 p++;
1061 namep = parse_arg (p, name, sizeof (name));
1062 if (!namep || !*namep)
1064 fprintf (stderr, N_("Usage: .set help | <name> [<value>]\n"));
1065 return GPG_ERR_SYNTAX;
1068 p += strlen (namep);
1069 while (p && *p && isspace (*p))
1070 p++;
1072 valuep = parse_arg (p, value, sizeof (value));
1074 if (!strcmp (name, "keyfile") || !strcmp (name, "new-keyfile"))
1076 int is_newkeyfile = 1;
1078 if (!strcmp (name, "keyfile"))
1079 is_newkeyfile = 0;
1081 if (is_newkeyfile)
1083 pwmd_free (new_keyfile);
1084 new_keyfile = NULL;
1086 else
1088 pwmd_free (keyfile);
1089 keyfile = NULL;
1092 p += strlen (valuep);
1093 while (p && *p && isspace (*p))
1094 p++;
1096 valuep = (char *) p;
1097 if (!rc && *valuep)
1099 if (is_newkeyfile)
1100 new_keyfile = pwmd_strdup (value);
1101 else
1102 keyfile = pwmd_strdup (value);
1104 if (!rc)
1106 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 1);
1107 if (!rc)
1108 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1111 else if (!local_pin && !no_pinentry)
1113 pwmd_socket_t t;
1115 pwmd_socket_type (pwm, &t);
1116 if (t == PWMD_SOCKET_LOCAL)
1118 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 0);
1119 if (!rc)
1120 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1124 else if (!strcmp(name, "pinentry-timeout"))
1126 char *e = NULL;
1127 int n = strtol(valuep, &e, 10);
1129 if (e && *e)
1130 return gpg_error (GPG_ERR_INV_VALUE);
1132 if (!valuep || !*valuep)
1133 n = DEFAULT_PIN_TIMEOUT;
1135 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, n);
1137 else if (!strcmp (name, "help"))
1139 fprintf (stderr,
1141 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1142 "delimited. When no value is specified the option is unset.\n\n"
1143 "keyfile <datafile> [<filename>]\n"
1144 " set or unset the keyfile to be used when a passphrase is required (*)\n"
1145 "\n"
1146 "new-keyfile <datafile> [<filename>]\n"
1147 " set or unset the keyfile to be used when a new passphrase is required (*)\n"
1148 "\n"
1149 "pinentry-timeout <seconds>\n"
1150 " the amount of seconds before pinentry gives up waiting for input\n"
1151 "\n"
1152 "* = the next protocol command will unset this value\n"
1155 else
1156 rc = GPG_ERR_UNKNOWN_OPTION;
1158 return rc;
1161 static gpg_error_t
1162 save_command (const char *line)
1164 struct inquire_s *inq = NULL;
1165 gpg_error_t rc;
1167 #ifdef HAVE_LIBREADLINE
1168 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1169 #else
1170 rc = set_inquire (-1, NULL, &inq);
1171 #endif
1172 if (rc)
1173 return rc;
1175 if (new_keyfile || keyfile)
1176 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1178 rc = pwmd_save (pwm, line, inquire_cb, inq);
1179 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1180 free_inquire (inq);
1181 return rc;
1184 static gpg_error_t
1185 do_save_passwd_command (const char *line, int save)
1187 struct inquire_s *inq = NULL;
1188 gpg_error_t rc;
1190 #ifdef HAVE_LIBREADLINE
1191 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1192 #else
1193 rc = set_inquire (-1, NULL, &inq);
1194 #endif
1195 if (rc)
1196 return rc;
1198 if (new_keyfile || keyfile)
1199 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1201 if (save)
1202 rc = pwmd_save (pwm, line, inquire_cb, inq);
1203 else
1204 rc = pwmd_passwd (pwm, line, inquire_cb, inq);
1206 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1207 free_inquire (inq);
1208 return rc;
1211 static gpg_error_t
1212 parse_dotcommand (const char *line, char **result,
1213 size_t * len, struct inquire_s *inq)
1215 const char *p = line;
1216 gpg_error_t rc = 0;
1218 if (!strncmp (p, ".read", 5))
1219 rc = read_command (p + 5, result, len);
1220 else if (!strncmp (p, ".redir", 6))
1221 rc = redir_command (p + 6);
1222 else if (!strncmp (p, ".help", 5))
1223 rc = help_command (p + 5);
1224 else if (!strncmp (p, ".open", 5))
1225 rc = open_command (p + 5);
1226 else if (!strncmp (p, ".set", 4))
1227 rc = set_command (p + 4);
1228 else if (!strncmp (p, ".save", 5))
1229 rc = do_save_passwd_command (p + 5, 1);
1230 else if (!strncmp (p, ".passwd", 7))
1231 rc = do_save_passwd_command (p + 7, 0);
1232 else
1234 rc = pwmd_command (pwm, result, len, inquire_cb, inq, line);
1235 #ifdef HAVE_LIBREADLINE
1236 if (interactive)
1238 #endif
1239 pwmd_free (keyfile);
1240 pwmd_free (new_keyfile);
1241 keyfile = new_keyfile = NULL;
1242 #ifdef HAVE_LIBREADLINE
1244 #endif
1247 return FINISH (rc);
1250 #ifdef HAVE_LIBREADLINE
1251 static gpg_error_t
1252 do_interactive ()
1254 gpg_error_t rc;
1255 struct inquire_s *inq = NULL;
1257 rl_initialize ();
1258 rc = process_cmd ();
1259 if (rc)
1260 return rc;
1262 rc = set_inquire (STDIN_FILENO, NULL, &inq);
1263 if (rc)
1264 return rc;
1266 fprintf (stderr,
1267 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1268 print_help ();
1269 rl_event_hook = &interactive_hook;
1270 rl_set_keyboard_input_timeout (100000);
1272 for (;;)
1274 char *line;
1275 char *result = NULL;
1276 size_t len;
1278 rc = 0;
1279 line = readline ("pwm> ");
1280 if (interactive_error)
1282 free (line);
1283 rc = interactive_error;
1284 break;
1287 if (!line)
1289 rc = finalize ();
1290 if (!rc)
1291 break;
1293 if (gpg_err_code (rc) != GPG_ERR_CANCELED &&
1294 gpg_err_code (rc) != GPG_ERR_EOF)
1295 fprintf (stderr, "ERR %i: %s\n", rc, gpg_strerror (rc));
1297 continue;
1299 else if (!*line)
1301 free (line);
1302 continue;
1305 #ifdef HAVE_READLINE_HISTORY
1306 add_history (line);
1307 #endif
1308 rc = parse_dotcommand (line, &result, &len, inq);
1309 free (line);
1310 if (rc)
1312 char *tmp = NULL;
1314 if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
1315 (void) pwmd_command (pwm, &tmp, NULL, NULL, NULL,
1316 "GETINFO last_error");
1318 show_error (pwm, rc, tmp);
1319 pwmd_free (tmp);
1321 else if (result && len)
1322 printf ("%s%s", result, result[len - 1] != '\n' ? "\n" : "");
1324 pwmd_free (result);
1327 free_inquire (inq);
1328 return rc;
1330 #endif
1332 static gpg_error_t
1333 finalize ()
1335 gpg_error_t rc = 0;
1336 #ifdef HAVE_LIBREADLINE
1337 int quit = 0;
1339 if (interactive)
1341 int finished = 0;
1343 fprintf (stderr, "\n");
1347 char *p, buf[16];
1349 fprintf (stderr,
1351 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1352 p = fgets (buf, sizeof (buf), stdin);
1354 if (feof (stdin))
1356 clearerr (stdin);
1357 return GPG_ERR_EOF;
1360 switch (*p)
1362 case 'h':
1363 print_help ();
1364 break;
1365 case 'c':
1366 return GPG_ERR_CANCELED;
1367 case 'Q':
1368 return 0;
1369 case 'f':
1370 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1371 "CLEARCACHE %s", filename);
1372 if (rc)
1373 return rc;
1375 interactive_hook ();
1376 break;
1377 case 'S':
1378 quit = 1;
1379 case 's':
1380 save = 1;
1381 finished = 1;
1382 break;
1383 default:
1384 break;
1387 while (!finished);
1389 #endif
1391 if (save && !filename)
1393 fprintf (stderr,
1395 ("No filename was specified on the command line. Aborting.\n"));
1396 return GPG_ERR_CANCELED;
1399 if (save && filename)
1401 char *args =
1402 pwmd_strdup_printf ("%s%s %s%s %s",
1403 keyid ? "--keyid=" : "",
1404 keyid ? keyid : "",
1405 sign_keyid ? "--sign-keyid=" : "",
1406 sign_keyid ? sign_keyid : "",
1407 keyparams ? "--inquire-keyparam" : "");
1409 #ifdef HAVE_LIBREADLINE
1410 if (!quiet || interactive)
1412 #else
1413 if (!quiet)
1415 #endif
1416 fprintf (stderr, "\n");
1417 fprintf (stderr, N_("Saving changes ...\n"));
1420 rc = save_command (args);
1421 pwmd_free (args);
1424 #ifdef HAVE_LIBREADLINE
1425 if (interactive)
1426 return rc ? rc : quit ? 0 : GPG_ERR_CANCELED;
1427 #endif
1429 return rc;
1432 static void
1433 parse_status_ignore (char *str)
1435 size_t n = 0;
1436 char **p, *s;
1438 for (p = status_ignore; p && *p; p++)
1439 pwmd_free (*p);
1441 pwmd_free (status_ignore);
1442 status_ignore = NULL;
1443 if (!str || !*str)
1444 return;
1446 while ((s = strsep (&str, ",")))
1448 p = pwmd_realloc (status_ignore, (n + 2) * sizeof (char **));
1449 p[n++] = pwmd_strdup (s);
1450 p[n] = NULL;
1451 status_ignore = p;
1456 main (int argc, char *argv[])
1458 int connected = 0;
1459 gpg_error_t rc;
1460 int opt;
1461 char command[ASSUAN_LINELENGTH], *p = NULL;
1462 char *result = NULL;
1463 size_t len = 0;
1464 char *pinentry_path = NULL;
1465 char *display = NULL, *tty = NULL, *ttytype = NULL;
1466 char *lcctype = NULL, *lcmessages = NULL;
1467 int outfd = STDOUT_FILENO;
1468 FILE *outfp = stdout;
1469 FILE *inquirefp = stdin;
1470 int show_status = 1;
1471 char *clientname = "pwmc";
1472 char *inquire = NULL;
1473 char *inquire_line = NULL;
1474 int timeout = 0;
1475 #ifdef WITH_SSH
1476 int use_ssh_agent = 1;
1477 char *knownhosts = NULL;
1478 char *identity = NULL;
1479 #endif
1480 #ifdef WITH_GNUTLS
1481 char *cacert = NULL;
1482 char *clientcert = NULL;
1483 char *clientkey = NULL;
1484 char *prio = NULL;
1485 int tls_verify = 0;
1486 char *tls_fingerprint = NULL;
1487 #endif
1488 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1489 pwmd_socket_t socktype;
1490 long socket_timeout = 300;
1491 int connect_timeout = 120;
1492 #endif
1493 int lock_on_open = 1;
1494 long lock_timeout = 50;
1495 char *url = NULL;
1496 char *tmp = NULL;
1497 /* The order is important. */
1498 enum
1500 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1501 OPT_SOCKET_TIMEOUT, OPT_CONNECT_TIMEOUT,
1502 #endif
1503 #ifdef WITH_SSH
1504 OPT_USE_SSH_AGENT, OPT_IDENTITY, OPT_KNOWNHOSTS,
1505 #endif
1506 #ifdef WITH_GNUTLS
1507 OPT_CACERT, OPT_CLIENTCERT, OPT_CLIENTKEY, OPT_PRIORITY, OPT_VERIFY,
1508 OPT_SERVER_FP,
1509 #endif
1510 OPT_URL, OPT_LOCAL, OPT_TTYNAME, OPT_TTYTYPE,
1511 OPT_DISPLAY, OPT_LC_CTYPE, OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES,
1512 OPT_PINENTRY, OPT_KEYFILE, OPT_NEW_KEYFILE, OPT_NOLOCK,
1513 OPT_LOCK_TIMEOUT, OPT_SAVE, OPT_OUTPUT_FD, OPT_INQUIRE,
1514 OPT_INQUIRE_FD, OPT_INQUIRE_FILE, OPT_INQUIRE_LINE, OPT_NO_STATUS,
1515 OPT_STATUS_IGNORE,
1516 OPT_STATUSFD, OPT_NAME, OPT_VERSION, OPT_HELP, OPT_KEYID, OPT_SIGN_KEYID,
1517 OPT_KEYPARAMS, OPT_NO_PINENTRY, OPT_QUIET,
1518 #ifdef HAVE_LIBREADLINE
1519 OPT_INTERACTIVE,
1520 #endif
1522 const struct option long_opts[] = {
1523 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1524 {"socket-timeout", 1, 0, 0},
1525 {"connect-timeout", 1, 0, 0},
1526 #endif
1528 #ifdef WITH_SSH
1529 {"no-ssh-agent", 0, 0, 0},
1530 {"identity", 1, 0, 'i'},
1531 {"knownhosts", 1, 0, 'k'},
1532 #endif
1533 #ifdef WITH_GNUTLS
1534 {"ca-cert", 1, 0, 0},
1535 {"client-cert", 1, 0, 0},
1536 {"client-key", 1, 0, 0},
1537 {"tls-priority", 1, 0, 0},
1538 {"tls-verify", 0, 0, 0},
1539 {"tls-fingerprint", 1, 0, 0},
1540 #endif
1541 {"url", 1, 0, 0},
1542 {"local-pinentry", 0, 0},
1543 {"ttyname", 1, 0, 'y'},
1544 {"ttytype", 1, 0, 't'},
1545 {"display", 1, 0, 'd'},
1546 {"lc-ctype", 1, 0, 0},
1547 {"lc-messages", 1, 0, 0},
1548 {"timeout", 1, 0, 0},
1549 {"tries", 1, 0, 0},
1550 {"pinentry", 1, 0, 0},
1551 {"key-file", 1, 0, 0},
1552 {"new-key-file", 1, 0, 0},
1553 {"no-lock", 0, 0, 0},
1554 {"lock-timeout", 1, 0, 0},
1555 {"save", 0, 0, 'S'},
1556 {"output-fd", 1, 0, 0},
1557 {"inquire", 1, 0, 0},
1558 {"inquire-fd", 1, 0, 0},
1559 {"inquire-file", 1, 0, 0},
1560 {"inquire-line", 1, 0, 'L'},
1561 {"no-status", 0, 0, 0},
1562 {"status-ignore", 1, 0, 0},
1563 {"status-fd", 1, 0, 0},
1564 {"name", 1, 0, 'n'},
1565 {"version", 0, 0, 0},
1566 {"help", 0, 0, 0},
1567 {"keyid", 1, 0, 0},
1568 {"sign-keyid", 1, 0, 0},
1569 {"key-params", 1, 0, 0},
1570 {"no-pinentry", 0, 0, 0},
1571 {"quiet", 0, 0, 0},
1572 #ifdef HAVE_LIBREADLINE
1573 {"interactive", 0, 0},
1574 #endif
1575 {0, 0, 0, 0}
1577 #ifdef WITH_SSH
1578 const char *optstring = "L:y:t:d:P:I:Sn:i:k:";
1579 #else
1580 const char *optstring = "L:y:t:d:P:I:Sn:";
1581 #endif
1582 int opt_index = 0;
1584 #ifdef ENABLE_NLS
1585 setlocale (LC_ALL, "");
1586 bindtextdomain ("libpwmd", LOCALEDIR);
1587 #endif
1589 tries = DEFAULT_PIN_TRIES;
1590 inquirefd = STDIN_FILENO;
1591 statusfd = STDERR_FILENO;
1592 statusfp = fdopen (statusfd, "w");
1593 tmp = pwmd_strdup (DEFAULT_STATUS_IGNORE);
1594 parse_status_ignore (tmp);
1595 pwmd_free (tmp);
1597 while ((opt =
1598 getopt_long (argc, argv, optstring, long_opts, &opt_index)) != -1)
1600 switch (opt)
1602 /* Handle long options without a short option part. */
1603 case 0:
1604 switch (opt_index)
1606 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1607 case OPT_SOCKET_TIMEOUT:
1608 socket_timeout = strtol (optarg, &p, 10);
1609 break;
1610 case OPT_CONNECT_TIMEOUT:
1611 connect_timeout = strtol (optarg, &p, 10);
1612 break;
1613 #endif
1614 #ifdef WITH_SSH
1615 case OPT_USE_SSH_AGENT:
1616 use_ssh_agent = 0;
1617 break;
1618 #endif
1619 #ifdef WITH_GNUTLS
1620 case OPT_CACERT:
1621 cacert = optarg;
1622 break;
1623 case OPT_CLIENTCERT:
1624 clientcert = optarg;
1625 break;
1626 case OPT_CLIENTKEY:
1627 clientkey = optarg;
1628 break;
1629 case OPT_PRIORITY:
1630 prio = optarg;
1631 break;
1632 case OPT_VERIFY:
1633 tls_verify = 1;
1634 break;
1635 case OPT_SERVER_FP:
1636 tls_fingerprint = optarg;
1637 break;
1638 #endif
1639 case OPT_KEYPARAMS:
1640 keyparams = optarg;
1641 break;
1642 case OPT_KEYFILE:
1643 keyfile = pwmd_strdup (optarg);
1644 break;
1645 case OPT_NEW_KEYFILE:
1646 new_keyfile = pwmd_strdup (optarg);
1647 break;
1648 case OPT_NOLOCK:
1649 lock_on_open = 0;
1650 break;
1651 case OPT_LOCK_TIMEOUT:
1652 lock_timeout = strtol (optarg, &p, 10);
1653 break;
1654 case OPT_URL:
1655 url = optarg;
1656 break;
1657 case OPT_LOCAL:
1658 local_pin = 1;
1659 break;
1660 case OPT_LC_CTYPE:
1661 lcctype = pwmd_strdup (optarg);
1662 break;
1663 case OPT_LC_MESSAGES:
1664 lcmessages = pwmd_strdup (optarg);
1665 break;
1666 case OPT_TIMEOUT:
1667 timeout = strtol (optarg, &p, 10);
1668 break;
1669 case OPT_TRIES:
1670 tries = strtol (optarg, &p, 10);
1671 break;
1672 case OPT_INQUIRE:
1673 inquire = escape (optarg);
1674 break;
1675 case OPT_INQUIRE_FD:
1676 inquirefd = strtol (optarg, &p, 10);
1677 if (!p)
1679 inquirefp = fdopen (inquirefd, "r");
1680 if (!inquirefp)
1681 err (EXIT_FAILURE, "%i", inquirefd);
1683 break;
1684 case OPT_INQUIRE_FILE:
1685 inquirefd = open (optarg, O_RDONLY);
1686 if (inquirefd == -1)
1687 err (EXIT_FAILURE, "%s", optarg);
1688 inquirefp = fdopen (inquirefd, "r");
1689 break;
1690 case OPT_OUTPUT_FD:
1691 outfd = strtol (optarg, &p, 10);
1692 if (!p || !*p)
1694 outfp = fdopen (outfd, "w");
1695 if (!outfp)
1696 err (EXIT_FAILURE, "%i", outfd);
1698 break;
1699 case OPT_NO_STATUS:
1700 show_status = 0;
1701 break;
1702 case OPT_STATUSFD:
1703 statusfd = strtol (optarg, &p, 10);
1704 if (!p || !*p)
1706 statusfp = fdopen (statusfd, "w");
1707 if (!statusfp)
1708 err (EXIT_FAILURE, "%i", statusfd);
1710 break;
1711 case OPT_STATUS_IGNORE:
1712 parse_status_ignore (optarg);
1713 break;
1714 case OPT_VERSION:
1715 printf ("%s (pwmc)\n\n"
1716 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015\n"
1717 "%s\n"
1718 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1719 "Compile-time features:\n"
1720 #ifdef HAVE_LIBREADLINE
1721 "+INTERACTIVE "
1722 #else
1723 "-INTERACTIVE "
1724 #endif
1725 #ifdef WITH_SSH
1726 "+SSH "
1727 #else
1728 "-SSH "
1729 #endif
1730 #ifdef WITH_GNUTLS
1731 "+GNUTLS "
1732 #else
1733 "-GNUTLS "
1734 #endif
1735 #ifdef WITH_PINENTRY
1736 "+PINENTRY "
1737 #else
1738 "-PINENTRY "
1739 #endif
1740 #ifdef WITH_QUALITY
1741 "+CRACK "
1742 #else
1743 "-CRACK "
1744 #endif
1745 #ifdef MEM_DEBUG
1746 "+MEM_DEBUG "
1747 #else
1748 "-MEM_DEBUG "
1749 #endif
1750 "\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1751 exit (EXIT_SUCCESS);
1752 case OPT_PINENTRY:
1753 pinentry_path = optarg;
1754 break;
1755 case OPT_HELP:
1756 usage (argv[0], EXIT_SUCCESS);
1757 case OPT_KEYID:
1758 keyid = optarg;
1759 break;
1760 case OPT_SIGN_KEYID:
1761 sign_keyid = optarg;
1762 break;
1763 case OPT_QUIET:
1764 quiet = 1;
1765 show_status = 0;
1766 break;
1767 case OPT_NO_PINENTRY:
1768 no_pinentry = 1;
1769 break;
1770 #ifdef HAVE_LIBREADLINE
1771 case OPT_INTERACTIVE:
1772 interactive = 1;
1773 break;
1774 #endif
1775 default:
1776 usage (argv[0], EXIT_FAILURE);
1779 if (p && *p)
1781 fprintf (stderr, N_("%s: invalid argument for option '--%s'\n"),
1782 argv[0], long_opts[opt_index].name);
1783 usage (argv[0], EXIT_FAILURE);
1786 break;
1787 #ifdef WITH_SSH
1788 case 'i':
1789 identity = optarg;
1790 break;
1791 case 'k':
1792 knownhosts = optarg;
1793 break;
1794 #endif
1795 case 'L':
1796 inquire_line = optarg;
1797 break;
1798 case 'y':
1799 tty = optarg;
1800 break;
1801 case 't':
1802 ttytype = optarg;
1803 break;
1804 case 'd':
1805 display = optarg;
1806 break;
1807 case 'S':
1808 save = 1;
1809 break;
1810 case 'n':
1811 clientname = optarg;
1812 break;
1813 default:
1814 usage (argv[0], EXIT_FAILURE);
1818 #ifdef HAVE_LIBREADLINE
1819 if (interactive && !isatty (STDIN_FILENO))
1820 usage (argv[0], EXIT_FAILURE);
1821 else if (isatty (STDIN_FILENO) && !inquire && !inquire_line)
1822 interactive = 1;
1823 #endif
1825 filename = argv[optind];
1826 #ifdef WITH_GNUTLS
1827 gnutls_global_set_mem_functions (pwmd_malloc, pwmd_malloc, NULL,
1828 pwmd_realloc, pwmd_free);
1829 #endif
1830 pwmd_init ();
1831 rc = pwmd_new (clientname, &pwm);
1832 if (rc)
1833 goto done;
1835 pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
1836 if (!quiet)
1837 fprintf (stderr, N_("Connecting ...\n"));
1839 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1840 socktype = is_remote_url (url);
1841 if (socktype != PWMD_SOCKET_LOCAL)
1843 local_pin = 1;
1844 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1845 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, connect_timeout);
1846 if (rc)
1847 goto done;
1848 #endif
1850 if (socktype == PWMD_SOCKET_SSH)
1852 #ifdef WITH_SSH
1853 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_CB, knownhost_cb);
1854 if (rc)
1855 goto done;
1857 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_DATA, clientname);
1858 if (rc)
1859 goto done;
1861 if (!getenv ("SSH_AUTH_SOCK") || identity)
1862 use_ssh_agent = 0;
1864 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_AGENT, use_ssh_agent);
1865 if (rc)
1866 goto done;
1868 rc = pwmd_connect (pwm, url, identity, knownhosts);
1869 #endif
1871 #ifdef WITH_GNUTLS
1872 else
1874 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_VERIFY, tls_verify);
1875 if (rc)
1876 goto done;
1878 rc = pwmd_connect (pwm, url, clientcert, clientkey, cacert, prio,
1879 tls_fingerprint);
1881 #endif
1883 else
1884 rc = pwmd_connect (pwm, url);
1885 #else
1886 rc = pwmd_connect (pwm, url);
1887 #endif
1888 if (rc)
1889 goto done;
1891 if (!quiet)
1892 fprintf (stderr, N_("Connected.\n"));
1894 connected = 1;
1895 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1896 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, socket_timeout);
1897 if (rc)
1898 goto done;
1899 #endif
1901 if (lock_timeout)
1903 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1904 "OPTION LOCK-TIMEOUT=%li", lock_timeout);
1905 if (rc)
1906 goto done;
1909 if (lock_on_open)
1911 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCK_ON_OPEN, 1);
1912 if (rc)
1913 goto done;
1916 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, NULL, NULL);
1917 if (rc)
1918 goto done;
1920 if (timeout > 0)
1922 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
1923 if (rc)
1924 goto done;
1927 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1928 if (rc)
1929 goto done;
1931 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY,
1932 (local_pin || keyfile || new_keyfile));
1933 if (rc)
1934 goto done;
1936 if (pinentry_path)
1938 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
1939 if (rc)
1940 goto done;
1943 if (display)
1945 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
1946 if (rc)
1947 goto done;
1950 if (tty)
1952 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, tty);
1953 if (rc)
1954 goto done;
1957 if (ttytype)
1959 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
1960 if (rc)
1961 goto done;
1964 if (lcctype)
1966 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
1967 if (rc)
1968 goto done;
1971 if (lcmessages)
1973 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES, lcmessages);
1974 if (rc)
1975 goto done;
1978 if (show_status)
1980 rc = pwmd_setopt (pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
1981 if (rc)
1982 goto done;
1985 if (filename)
1987 rc = open_command (filename);
1988 if (rc)
1989 goto done;
1992 #ifdef HAVE_LIBREADLINE
1993 if (interactive)
1995 rc = do_interactive ();
1996 result = NULL;
1997 goto do_exit;
1999 #endif
2001 if (inquire)
2003 struct inquire_s *inq = NULL;
2005 rc = set_inquire (inquirefd, inquire_line, &inq);
2006 if (!rc)
2007 rc = pwmd_command (pwm, &result, &len, inquire_cb, inq, inquire);
2009 free_inquire (inq);
2010 goto done;
2013 fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK);
2014 ssize_t n;
2016 for (;;)
2018 rc = process_cmd ();
2020 if (rc)
2021 goto done;
2023 n = read (STDIN_FILENO, command, sizeof (command));
2024 if (n == -1)
2026 if (errno == EAGAIN)
2028 usleep (100000);
2029 continue;
2032 rc = gpg_error_from_errno (errno);
2033 goto done;
2035 else if (!n)
2036 goto done;
2038 p = command;
2039 command[n] = 0;
2040 break;
2043 if (!p || !*p || !strcasecmp (p, "BYE"))
2044 goto done;
2047 struct inquire_s *inq = NULL;
2048 rc = set_inquire (inquirefd, inquire_line, &inq);
2049 if (!rc)
2051 rc = parse_dotcommand (command, &result, &len, inq);
2052 free_inquire (inq);
2055 if (rc)
2056 goto done;
2058 done:
2059 if (result)
2061 fwrite (result, 1, result[len - 1] == 0 ? len - 1 : len, outfp);
2062 fflush (outfp);
2063 pwmd_free (result);
2066 result = NULL;
2067 if (!rc)
2068 rc = finalize ();
2069 else if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
2070 (void) pwmd_command (pwm, &result, NULL, NULL, NULL,
2071 "GETINFO last_error");
2073 #ifdef HAVE_LIBREADLINE
2074 do_exit:
2075 #endif
2076 memset (command, 0, sizeof (command));
2078 if (rc && !quiet)
2079 show_error (pwm, rc, result);
2081 pwmd_close (pwm);
2082 pwmd_free (keyfile);
2083 pwmd_free (new_keyfile);
2084 pwmd_deinit ();
2085 pwmd_free (result);
2086 parse_status_ignore (NULL);
2087 if (connected && !quiet)
2088 fprintf (stderr, N_("Connection closed.\n"));
2090 exit (rc ? EXIT_FAILURE : EXIT_SUCCESS);