Fix pwmd_save() to determine whether to use pinentry.
[libpwmd.git] / src / pwmc.c
blob9a5c777bb3ee1a11b2a80578292db19f1f83cca8
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
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 HAVE_LOCALE_H
43 #include <locale.h>
44 #endif
46 #ifdef HAVE_GETOPT_LONG
47 #ifdef HAVE_GETOPT_H
48 #include <getopt.h>
49 #endif
50 #else
51 #include "getopt_long.h"
52 #endif
54 #ifdef HAVE_LIBREADLINE
55 #if defined(HAVE_READLINE_READLINE_H)
56 #include <readline/readline.h>
57 #elif defined(HAVE_READLINE_H)
58 #include <readline.h>
59 #endif /* !defined(HAVE_READLINE_H) */
60 static int interactive_error;
61 static int interactive;
62 #endif /* HAVE_LIBREADLINE */
64 #ifdef HAVE_READLINE_HISTORY
65 #if defined(HAVE_READLINE_HISTORY_H)
66 #include <readline/history.h>
67 #elif defined(HAVE_HISTORY_H)
68 #include <history.h>
69 #endif
70 #endif /* HAVE_READLINE_HISTORY */
72 #ifndef LINE_MAX
73 #define LINE_MAX 2048
74 #endif
76 #include "gettext.h"
77 #define N_(msgid) gettext(msgid)
79 #include "mem.h"
81 #define DEFAULT_PIN_TRIES 3
82 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
83 ? gpg_error(rc) : rc
85 static int no_pinentry;
86 static pwm_t *pwm;
87 static char *filename;
88 static int save;
89 static int force_save;
90 static int no_passphrase;
91 static char *cipher;
92 static char *keygrip;
93 static char *sign_keygrip;
94 static char *keyparams;
95 static char *password;
96 static char *keyfile;
97 static char *new_keyfile;
98 static unsigned long s2k_count;
99 static uint64_t iterations;
100 static int iterations_arg;
101 static int tries;
102 static int local_pin;
103 static int inquirefd;
104 static int quiet;
105 static int no_gpg_agent;
107 struct inquire_s
109 int fd;
110 char *line;
111 size_t len;
112 size_t size; // from stat(2).
113 int header;
116 static gpg_error_t finalize ();
117 static gpg_error_t set_inquire (int fd, const char *line,
118 struct inquire_s **result);
119 static gpg_error_t parse_dotcommand (const char *line, char **result,
120 size_t * len, struct inquire_s *inq);
121 static gpg_error_t open_command (const char *line);
122 #ifdef WITH_SSH
123 static gpg_error_t get_password (char **result, pwmd_pinentry_t w, int echo);
124 #endif
126 static void
127 show_error (gpg_error_t rc, const char *str)
129 fprintf (stderr, "ERR %i: %s%s%s%s", rc, gpg_strerror (rc),
130 str ? ": " : "", str ? str : "", str ? "" : "\n");
133 static void
134 usage (const char *pn, int status)
136 fprintf (status == EXIT_FAILURE ? stderr : stdout,
137 N_("Read a PWMD protocol command from standard input.\n\n"
138 "Usage: pwmc [options] [file]\n"
139 " --url <string>\n"
140 " a url string to connect to (see below)\n"
141 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
142 " --connect-timeout <seconds>\n"
143 " seconds before connecting to a remote host fails (120)\n"
144 " --socket-timeout <seconds>\n"
145 " seconds before a remote command fails (0=disabled, default=300)\n"
146 #endif
147 #ifdef WITH_GNUTLS
148 " --ca-cert <filename>\n"
149 " certificate authority (CA) used to sign the server cert\n"
150 " --client-cert <filename>\n"
151 " client certificate to use for authentication\n"
152 " --client-key <filename>\n"
153 " key file used to protect the client certificate\n"
154 " --tls-priority <string>\n"
155 " compression, cipher and hash algorithm string (SECURE256)\n"
156 " --tls-verify\n"
157 " verify the hostname against the server certificate\n"
158 " --tls-fingerprint <string>\n"
159 " a SHA-1 hash of the server fingerprint to verify against\n"
160 #endif
161 #ifdef WITH_SSH
162 " --no-ssh-agent\n"
163 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
164 " --identity, -i <filename>\n"
165 " the ssh identity file to use for authentication\n"
166 " --knownhosts, -k <filename>\n"
167 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
168 #endif
169 " --no-lock\n"
170 " do not lock the data file upon opening it\n"
171 " --lock-timeout <N>\n"
172 " time in tenths of a second to wait for a locked data file\n"
173 " --name, -n <string>\n"
174 " set the client name\n"
175 " --pinentry <path>\n"
176 " the full path to the pinentry binary (server default)\n"
177 " --local-pinentry\n"
178 " force using a local pinentry\n"
179 " --no-pinentry\n"
180 " disable pinentry both remotely and locally\n"
181 " --ttyname, -y <path>\n"
182 " tty that pinentry will use\n"
183 " --ttytype, -t <string>\n"
184 " pinentry terminal type (default is $TERM)\n"
185 " --display, -d\n"
186 " pinentry display (default is $DISPLAY)\n"
187 " --lc-ctype <string>\n"
188 " locale setting for pinentry\n"
189 " --lc-messages <string>\n"
190 " locale setting for pinentry\n"
191 " --tries <N>\n"
192 " number of pinentry tries before failing (3)\n"
193 " --timeout <seconds>\n"
194 " pinentry timeout\n"
195 " --inquire <COMMAND>\n"
196 " the specified command (with any options) uses a server inquire while\n"
197 " command data is read via the inquire file descriptor (stdin)\n"
198 " --inquire-line, -L <STRING>\n"
199 " the initial line to send (i.e., element path) before the inquire data\n"
200 " --inquire-fd <FD>\n"
201 " read inquire data from the specified file descriptor (stdin)\n"
202 " --inquire-file <filename>\n"
203 " read inquire data from the specified filename\n"
204 " --output-fd <FD>\n"
205 " redirect command output to the specified file descriptor\n"
206 " --save, -S\n"
207 " send the SAVE command before exiting\n"
208 " --force-save\n"
209 " like --save but always ask for a passphrase\n"
210 " --no-passphrase\n"
211 " do not require a passphrase when saving a new file\n"
212 " --no-gpg-agent\n"
213 " disable use of gpg-agent when saving to a new file\n"
214 " --key-file <filename>\n"
215 " obtain the passphrase from the specified filename\n"
216 " --new-key-file <filename>\n"
217 " obtain the passphrase to save with from the specified filename\n"
218 " --cipher <string>\n"
219 " the cipher to use when saving (see pwmd(1))\n"
220 " --cipher-iterations <N>\n"
221 " the number of times to encrypt the XML data (N+1)\n"
222 " --key-params <string>\n"
223 " the key parameters to use when saving a new file (pwmd default)\n"
224 " --keygrip <string>\n"
225 " the hex string of the keygrip to save to\n"
226 " --sign-keygrip <string>\n"
227 " the hex string of the keygrip to sign with\n"
228 " --s2k-count <N>\n"
229 " the number of times to hash the passphrase for a new file\n"
230 " --no-status\n"
231 " disable showing of status messages from the server\n"
232 " --quiet\n"
233 " disable showing of extra messages (implies --no-status)\n"
234 #ifdef HAVE_LIBREADLINE
235 " --interactive\n"
236 " use a shell like interface to pwmd (allows more than one command)\n"
237 #endif
238 " --version\n"
239 " --help\n"));
240 fprintf (status == EXIT_FAILURE ? stderr : stdout,
241 N_("\n"
242 "An optional url may be in the form of:\n"
243 " --url /path/to/socket\n"
244 " --url file://[path/to/socket]\n"
245 #ifdef WITH_SSH
246 " or\n"
247 " --url ssh[46]://[username@]hostname[:port]\n"
248 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
249 #endif
250 #ifdef WITH_GNUTLS
251 " or\n"
252 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
253 " --client-key filename\n"
254 #endif
256 exit (status);
259 static gpg_error_t
260 inquire_cb (void *user, const char *keyword, gpg_error_t rc,
261 char **data, size_t * size)
263 struct inquire_s *inq = user;
264 int is_password = 0;
265 int is_newpassword = 0;
267 *data = NULL;
268 *size = 0;
270 if (rc)
271 return rc;
273 if (!strcmp (keyword, "PASSPHRASE"))
274 is_password = 1;
275 else if (!strcmp (keyword, "NEW_PASSPHRASE"))
276 is_newpassword = 1;
277 #ifdef HAVE_LIBREADLINE
278 else if (!strcmp (keyword, "KEYPARAM") && !interactive)
280 #else
281 else if (!strcmp (keyword, "KEYPARAM"))
283 #endif
284 if (!keyparams || !*keyparams)
285 return gpg_error (GPG_ERR_INV_PARAMETER);
287 *data = keyparams;
288 *size = strlen (keyparams);
289 return gpg_error (GPG_ERR_EOF);
292 if ((is_newpassword && new_keyfile) || (is_password && keyfile))
294 int fd = open (is_password ? keyfile : new_keyfile, O_RDONLY);
296 if (fd == -1)
298 fprintf (stderr, "%s: %s\n", is_newpassword ? new_keyfile : keyfile,
299 strerror (errno));
300 return gpg_error_from_syserror ();
303 rc = set_inquire (fd, NULL, &inq);
304 if (rc)
306 close (fd);
307 return rc;
310 if (!quiet)
311 fprintf (stderr, N_("Using keyfile '%s' as %s.\n"),
312 is_newpassword ? new_keyfile : keyfile, keyword);
314 if (!new_keyfile || is_newpassword)
316 pwmd_socket_t t;
318 pwmd_socket_type (pwm, &t);
319 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
320 if (!no_pinentry && t == PWMD_SOCKET_LOCAL)
321 pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 0);
324 else if (is_password && !keyfile)
326 char *tmp;
328 rc = pwmd_password (pwm, keyword, &tmp, &inq->len);
329 if (rc && gpg_err_code (rc) != GPG_ERR_EOF)
330 return rc;
332 pwmd_free (inq->line);
333 inq->line = tmp;
334 *data = inq->line;
335 *size = inq->len;
336 return gpg_error (GPG_ERR_EOF);
338 #ifdef HAVE_LIBREADLINE
339 else if (!inq->header && interactive)
341 fprintf (stderr,
343 ("Press CTRL-D to send the current line. Press twice to end. %s:\n"),
344 keyword);
345 inq->header = 1;
347 #endif
349 /* The first part of the command data. */
350 if (inq->len)
352 *data = inq->line;
353 *size = inq->len;
354 inq->len = 0;
355 return inq->fd == -1 ? gpg_error (GPG_ERR_EOF) : 0;
358 *size = read (inq->fd, inq->line, ASSUAN_LINELENGTH);
359 if (*size == -1)
361 *size = 0;
362 return gpg_error (gpg_error_from_syserror ());
364 else if (*size)
365 *data = inq->line;
366 else if (inq->fd != STDIN_FILENO && (is_newpassword || is_password))
368 *inq->line = 0;
369 inq->size = 1;
370 *data = inq->line;
371 *size = 1;
374 if (((is_newpassword && new_keyfile) || (is_password && keyfile))
375 && *size == inq->size)
376 return gpg_error (GPG_ERR_EOF);
378 return *size ? 0 : gpg_error (GPG_ERR_EOF);
381 static int
382 status_msg_cb (void *data, const char *line)
384 char *p = strchr (line, ' ');
386 if (!strcmp (line, "KEEPALIVE"))
387 return 0;
389 if (*line != '#' && p && strchr (p, ' ') && *++p)
391 char *p1 = strchr (p, ' ');
392 int a = strtol (p, NULL, 10);
394 if (isdigit (*p) && p1)
396 int b = strtol (p1, NULL, 10);
397 char l[64] = { 0 };
398 int t = a && b ? a * 100 / b : 0;
400 strncpy (l, line, strlen (line) - strlen (p) - 1);
401 fprintf (stderr, "\r%s %i/%i %i%%%s", l, a, b, t,
402 a == b ? "\n" : "");
403 fflush (stderr);
404 return 0;
408 fprintf (stderr, "%s\n", line);
409 fflush (stderr);
410 #ifdef HAVE_LIBREADLINE
411 rl_on_new_line ();
412 #endif
413 return 0;
416 static gpg_error_t
417 process_cmd ()
419 return pwmd_process (pwm);
422 #ifdef WITH_SSH
423 static gpg_error_t
424 get_password (char **result, pwmd_pinentry_t w, int echo)
426 char buf[LINE_MAX] = { 0 }, *p;
427 struct termios told, tnew;
428 char *key = NULL;
430 *result = NULL;
432 if (!isatty (STDIN_FILENO))
434 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
435 return GPG_ERR_ENOTTY;
438 if (!echo)
440 if (tcgetattr (STDIN_FILENO, &told) == -1)
441 return gpg_error_from_syserror ();
443 memcpy (&tnew, &told, sizeof (struct termios));
444 tnew.c_lflag &= ~(ECHO);
445 tnew.c_lflag |= ICANON | ECHONL;
447 if (tcsetattr (STDIN_FILENO, TCSANOW, &tnew) == -1)
449 int n = errno;
451 tcsetattr (STDIN_FILENO, TCSANOW, &told);
452 return gpg_error_from_errno (n);
456 switch (w)
458 case PWMD_PINENTRY_OPEN:
459 fprintf (stderr, N_("Password for %s: "), filename);
460 break;
461 case PWMD_PINENTRY_OPEN_FAILED:
462 fprintf (stderr, N_("Invalid password. Password for %s: "), filename);
463 break;
464 case PWMD_PINENTRY_SAVE:
465 fprintf (stderr, N_("New password for %s: "), filename);
466 break;
467 case PWMD_PINENTRY_SAVE_CONFIRM:
468 fprintf (stderr, N_("Confirm password: "));
469 break;
470 default:
471 break;
474 if ((p = fgets (buf, sizeof (buf), stdin)) == NULL)
476 tcsetattr (STDIN_FILENO, TCSANOW, &told);
477 return 0;
480 if (!echo)
481 tcsetattr (STDIN_FILENO, TCSANOW, &told);
483 if (feof (stdin))
485 clearerr (stdin);
486 return GPG_ERR_CANCELED;
489 p[strlen (p) - 1] = 0;
491 if (buf[0])
493 key = pwmd_strdup_printf ("%s", p);
494 memset (&buf, 0, sizeof (buf));
496 if (!key)
497 return GPG_ERR_ENOMEM;
500 *result = key;
501 return 0;
504 static gpg_error_t
505 knownhost_cb (void *data, const char *host, const char *key, size_t len)
507 gpg_error_t rc;
508 char *buf =
509 pwmd_strdup_printf (N_
510 ("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?"),
511 (char *) data, host, host);
513 if (no_pinentry && !isatty (STDIN_FILENO))
515 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
516 pwmd_free (buf);
517 return GPG_ERR_ENOTTY;
519 else if (no_pinentry)
521 for (char *p = buf, len = 0; *p; p++, len++)
523 if (*p == '\n')
524 len = 0;
526 if (len == 78)
528 char *t = p;
530 while (!isspace (*(--p)));
531 *p = '\n';
532 p = t;
533 len = 0;
537 fprintf (stderr, "%s\n\n", buf);
538 pwmd_free (buf);
542 char *result;
544 fprintf (stderr, N_("Trust this connection [y/N]: "));
545 fflush (stderr);
546 rc = get_password (&result, PWMD_PINENTRY_CONFIRM, 1);
548 if (rc)
549 return rc;
551 if (!result || !*result || *result == 'n' || *result == 'N')
553 if (result && *result)
554 pwmd_free (result);
556 return GPG_ERR_NOT_CONFIRMED;
559 if ((*result == 'y' || *result == 'Y') && *(result + 1) == 0)
561 pwmd_free (result);
562 return 0;
565 while (1);
568 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, buf);
569 pwmd_free (buf);
571 if (rc)
572 return rc;
574 return pwmd_getpin (pwm, NULL, NULL, NULL, PWMD_PINENTRY_CONFIRM);
576 #endif
578 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
579 static pwmd_socket_t
580 is_remote_url (const char *str)
582 if (!str)
583 return PWMD_SOCKET_LOCAL;
585 #ifdef WITH_SSH
586 if (strstr (str, "ssh://") || strstr (str, "ssh4://")
587 || strstr (str, "ssh6://"))
588 return PWMD_SOCKET_SSH;
589 #endif
591 #ifdef WITH_GNUTLS
592 if (strstr (str, "tls://") || strstr (str, "tls4://")
593 || strstr (str, "tls6://"))
594 return PWMD_SOCKET_TLS;
595 #endif
597 return PWMD_SOCKET_LOCAL;
599 #endif
601 static char *
602 escape (const char *str)
604 const char *p;
605 char *buf = pwmd_malloc (ASSUAN_LINELENGTH + 1), *b = buf;
606 size_t len = 0;
608 for (p = str; *p; p++, len++)
610 if (len == ASSUAN_LINELENGTH)
611 break;
613 if (*p == '\\')
615 switch (*++p)
617 case 't':
618 *b++ = '\t';
619 break;
620 case 'n':
621 *b++ = '\n';
622 break;
623 case 'v':
624 *b++ = '\v';
625 break;
626 case 'b':
627 *b++ = '\b';
628 break;
629 case 'f':
630 *b++ = '\f';
631 break;
632 case 'r':
633 *b++ = '\r';
634 break;
635 default:
636 *b++ = *p;
637 break;
640 if (!*p)
641 break;
643 continue;
646 *b++ = *p;
649 *b = 0;
650 return buf;
653 static void
654 free_inquire (struct inquire_s *inq)
656 if (!inq)
657 return;
659 pwmd_free (inq->line);
661 if (inq->fd != -1 && inq->fd != STDIN_FILENO)
662 close (inq->fd);
664 pwmd_free (inq);
667 /* When *result is not NULL it is updated to the new values and not
668 * reallocated. */
669 static gpg_error_t
670 set_inquire (int fd, const char *line, struct inquire_s **result)
672 struct inquire_s inq = { 0 };
673 struct stat st = { 0 };
674 gpg_error_t rc;
676 if (fd != -1)
678 if (fstat (fd, &st) == -1)
679 return gpg_error_from_syserror ();
681 inq.size = st.st_size;
684 inq.fd = fd;
685 inq.line = pwmd_calloc (1, ASSUAN_LINELENGTH);
686 if (!inq.line)
687 return GPG_ERR_ENOMEM;
689 if (line)
691 char *s = escape (line);
693 if (!s)
695 pwmd_free (inq.line);
696 return GPG_ERR_ENOMEM;
699 if (strlen (s) >= ASSUAN_LINELENGTH)
701 pwmd_free (inq.line);
702 pwmd_free (s);
703 return GPG_ERR_LINE_TOO_LONG;
706 strncpy (inq.line, s, ASSUAN_LINELENGTH - 1);
707 inq.len = strlen (s);
708 pwmd_free (s);
711 rc = pwmd_setopt (pwm, PWMD_OPTION_INQUIRE_TOTAL,
712 st.st_size ? st.st_size + strlen (inq.line) : 0);
713 if (rc)
715 pwmd_free (inq.line);
716 return rc;
719 if (*result == NULL)
720 *result = pwmd_malloc (sizeof (struct inquire_s));
721 else
723 if ((*result)->fd != -1 && (*result)->fd != STDIN_FILENO)
724 close ((*result)->fd);
726 pwmd_free ((*result)->line);
727 (*result)->line = NULL;
728 (*result)->fd = -1;
729 (*result)->len = 0;
732 memcpy (*result, &inq, sizeof (struct inquire_s));
733 memset (&inq, 0, sizeof (struct inquire_s));
734 return rc;
737 #ifdef HAVE_LIBREADLINE
738 static int
739 interactive_hook (void)
741 interactive_error = process_cmd ();
743 if (interactive_error)
744 rl_event_hook = NULL;
746 return 0;
749 static void
750 print_help ()
752 fprintf (stderr,
754 ("------------------------------------------------------------------------------\n"
755 "Elements are TAB delimited. Press CTRL-V then TAB to insert from the prompt.\n"
756 "\n"
757 "Type HELP for protocol commands. Type .help for pwmc commands. Press CTRL-D\n"
758 "to quit.\n"
759 "------------------------------------------------------------------------------\n"));
761 #endif
763 static char *
764 parse_arg (const char *src, char *dst, size_t len)
766 char *p = dst;
767 const char *s = src;
768 size_t n = 0;
770 for (; s && *s && *s != ' ' && n < len; s++, n++)
771 *p++ = *s;
773 *p = 0;
774 return dst;
777 static char *
778 parse_opt (char **line, const char *opt, gpg_error_t * rc)
780 static char result[ASSUAN_LINELENGTH] = { 0 }, *r = result;
781 size_t len = 0;
782 char *s = strstr (*line, opt);
784 *rc = 0;
785 result[0] = 0;
786 r = result;
788 if (s)
790 int quote = 0;
791 size_t rlen = strlen (opt);
792 char *p = s + rlen;
793 int lastc = 0;
795 while (*p && *p == ' ')
797 rlen++;
798 p++;
801 for (; *p && len < sizeof (result) - 1; p++, rlen++)
803 if (isspace (*p) && !quote)
804 break;
806 if (*p == '\"' && lastc != '\\')
808 quote = !quote;
809 lastc = *p;
810 continue;
813 *r++ = lastc = *p;
814 len++;
817 *r = 0;
819 if (len >= sizeof (result) - 1)
820 *rc = GPG_ERR_LINE_TOO_LONG;
821 else
823 p = s + rlen;
825 while (*p && *p == ' ')
826 p++;
828 *line = p;
832 return result;
835 static gpg_error_t
836 read_command (const char *line, char **result, size_t * len)
838 int fd;
839 gpg_error_t rc = 0;
840 char filebuf[ASSUAN_LINELENGTH];
841 char *filename = NULL;
842 struct inquire_s *inq = NULL;
843 char *p = (char *) line;
844 const char *prefix = parse_opt (&p, "--prefix", &rc);
846 if (rc)
847 return rc;
849 rc = GPG_ERR_SYNTAX;
851 if (p && *p)
853 while (*p && isspace (*p))
854 p++;
856 filename = parse_arg (p, filebuf, sizeof (filebuf));
857 if (filename && *filename)
859 p += strlen (filename) + 1;
861 while (*p && isspace (*p))
862 p++;
864 if (*p)
865 rc = 0;
869 if (rc)
871 fprintf (stderr,
873 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
874 fprintf (stderr,
876 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\" = \")\n"));
877 return rc;
880 fd = open (filename, O_RDONLY);
881 if (fd == -1)
882 return gpg_error_from_syserror ();
884 rc = set_inquire (fd, prefix && *prefix ? prefix : NULL, &inq);
885 if (rc)
887 close (fd);
888 return rc;
891 inq->header = 1;
892 rc = pwmd_command (pwm, result, len, inquire_cb, inq, p);
893 free_inquire (inq);
894 return rc;
897 static gpg_error_t
898 redir_command (const char *line)
900 const char *p = line;
901 int fd;
902 gpg_error_t rc = GPG_ERR_SYNTAX;
903 char filebuf[ASSUAN_LINELENGTH];
904 char *filename = NULL;
905 struct inquire_s *inq = NULL;
906 char *result = NULL;
907 size_t len = 0;
909 if (p && *p && *++p)
911 filename = parse_arg (p, filebuf, sizeof (filebuf));
912 if (filename && *filename)
914 p += strlen (filename) + 1;
916 while (*p && isspace (*p))
917 p++;
919 if (*p)
920 rc = 0;
924 if (rc)
926 fprintf (stderr, N_("Usage: .redir <filename> <command> [args]\n"));
927 return rc;
930 fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
931 if (fd == -1)
932 return gpg_error_from_syserror ();
934 #ifdef HAVE_LIBREADLINE
935 rc = set_inquire (interactive ? STDIN_FILENO : inquirefd, NULL, &inq);
936 #else
937 rc = set_inquire (inquirefd, NULL, &inq);
938 #endif
939 if (rc)
941 close (fd);
942 return rc;
945 rc = parse_dotcommand (p, &result, &len, inq);
946 if (!rc && result && len--)
947 { // null byte which is always appended
948 if (write (fd, result, len) != len)
949 rc = GPG_ERR_TOO_SHORT;
950 pwmd_free (result);
953 free_inquire (inq);
954 close (fd);
955 return rc;
958 static gpg_error_t
959 help_command (const char *line)
961 fprintf (stderr,
962 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
963 " .redir <filename> <command>\n"
964 " redirect the output of a command to the specified file\n"
965 "\n"
966 " .open <filename>\n"
967 " open the specified filename losing any changes to the current one\n"
968 "\n"
969 " .read [--prefix <string>] <filename> <command> [args]\n"
970 " obtain data from the specified filename for an inquire command\n"
971 "\n"
972 " .set help | <name> [<value>]\n"
973 " set option <name> to <value>\n"
974 "\n"
975 " .save [args]\n"
976 " write changes of the file to disk\n"
977 "\n"
978 " .help\n"
979 " this help text\n"));
980 return 0;
983 static gpg_error_t
984 open_command (const char *line)
986 struct inquire_s *inq = NULL;
987 const char *filename = line;
988 gpg_error_t rc;
990 while (filename && isspace (*filename))
991 filename++;
993 if (!filename || !*filename)
995 fprintf (stderr, N_("Usage: .open <filename>\n"));
996 return GPG_ERR_SYNTAX;
999 #ifdef HAVE_LIBREADLINE
1000 if (interactive || !quiet)
1001 #else
1002 if (!quiet)
1003 #endif
1004 fprintf (stderr, N_("Opening data file \"%s\" ...\n"), filename);
1006 #ifdef HAVE_LIBREADLINE
1007 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1008 #else
1009 rc = set_inquire (-1, NULL, &inq);
1010 #endif
1011 if (rc)
1012 return rc;
1014 if (keyfile)
1015 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1017 #ifdef HAVE_LIBREADLINE
1018 // For safety. This file may be a different one. Make the user set it
1019 // again if needed.
1020 if (interactive)
1022 pwmd_free (new_keyfile);
1023 new_keyfile = NULL;
1025 #endif
1027 rc = pwmd_open (pwm, filename, inquire_cb, inq);
1028 free_inquire (inq);
1029 return rc;
1032 static gpg_error_t
1033 set_command (const char *line)
1035 gpg_error_t rc = 0;
1036 char name[256] = { 0 };
1037 char value[512] = { 0 };
1038 char *namep;
1039 char *valuep;
1040 const char *p = line;
1042 while (p && *p && isspace (*p))
1043 p++;
1045 namep = parse_arg (p, name, sizeof (name));
1046 if (!namep || !*namep)
1048 fprintf (stderr, N_("Usage: .set help | <name> [<value>]\n"));
1049 return GPG_ERR_SYNTAX;
1052 p += strlen (namep);
1053 while (p && *p && isspace (*p))
1054 p++;
1056 valuep = parse_arg (p, value, sizeof (value));
1058 if (!strcmp (name, "keyfile") || !strcmp (name, "new-keyfile"))
1060 int is_newkeyfile = 1;
1061 int is_pkcs = 1;
1062 char datafile[256];
1064 if (!strcmp (name, "keyfile"))
1065 is_newkeyfile = 0;
1067 if (is_newkeyfile)
1069 pwmd_free (new_keyfile);
1070 new_keyfile = NULL;
1072 else
1074 pwmd_free (keyfile);
1075 keyfile = NULL;
1078 p += strlen (valuep);
1079 while (p && *p && isspace (*p))
1080 p++;
1082 valuep = (char *) p;
1083 if (*valuep)
1085 memcpy (datafile, value, sizeof (datafile));
1086 valuep = parse_arg (p, value, sizeof (value));
1087 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL, "KEYGRIP %s",
1088 datafile);
1089 if (gpg_err_code (rc) == GPG_ERR_NOT_SUPPORTED
1090 || (gpg_err_source (rc) == GPG_ERR_SOURCE_USER_1
1091 && gpg_err_code (rc) == GPG_ERR_ENOENT))
1093 rc = 0;
1094 is_pkcs = 0;
1096 else if (!rc)
1097 is_pkcs = 1;
1100 if (!rc && *valuep)
1102 if (is_newkeyfile)
1103 new_keyfile = pwmd_strdup (value);
1104 else
1105 keyfile = pwmd_strdup (value);
1107 if (!is_pkcs)
1108 rc = 0;
1109 else
1110 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1111 "AGENT option pinentry-mode=loopback");
1113 if (!rc)
1115 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 1);
1116 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)
1126 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 0);
1127 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1131 else if (!strcmp (name, "help"))
1133 fprintf (stderr,
1135 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1136 "delimited. When no value is specified the option is unset.\n\n"
1137 "keyfile <datafile> [<filename>]\n"
1138 " set or unset the keyfile to be used when a passphrase is required\n"
1139 "\n" "new-keyfile <datafile> [<filename>]\n"
1140 " set or unset the keyfile to be used when a new passphrase is required\n"));
1142 else
1143 rc = GPG_ERR_UNKNOWN_OPTION;
1145 return rc;
1148 static gpg_error_t
1149 save_command (const char *line)
1151 struct inquire_s *inq = NULL;
1152 gpg_error_t rc;
1154 #ifdef HAVE_LIBREADLINE
1155 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1156 #else
1157 rc = set_inquire (-1, NULL, &inq);
1158 #endif
1159 if (rc)
1160 return rc;
1162 rc = pwmd_save (pwm, line, inquire_cb, inq);
1163 free_inquire (inq);
1165 #ifdef HAVE_LIBREADLINE
1166 // For safety. This file may be a different one. Make the user set it
1167 // again if needed.
1168 if (interactive)
1170 pwmd_free (new_keyfile);
1171 new_keyfile = NULL;
1173 #endif
1175 return rc;
1178 static gpg_error_t
1179 parse_dotcommand (const char *line, char **result,
1180 size_t * len, struct inquire_s *inq)
1182 const char *p = line;
1183 gpg_error_t rc = 0;
1185 if (!strncmp (p, ".read", 5))
1186 rc = read_command (p + 5, result, len);
1187 else if (!strncmp (p, ".redir", 6))
1188 rc = redir_command (p + 6);
1189 else if (!strncmp (p, ".help", 5))
1190 rc = help_command (p + 5);
1191 else if (!strncmp (p, ".open", 5))
1192 rc = open_command (p + 5);
1193 else if (!strncmp (p, ".set", 4))
1194 rc = set_command (p + 4);
1195 else if (!strncmp (p, ".save", 5))
1196 rc = save_command (p + 5);
1197 else
1198 rc = pwmd_command (pwm, result, len, inquire_cb, inq, line);
1200 return FINISH (rc);
1203 #ifdef HAVE_LIBREADLINE
1204 static gpg_error_t
1205 do_interactive ()
1207 gpg_error_t rc;
1208 struct inquire_s *inq = NULL;
1210 rl_initialize ();
1211 rc = process_cmd ();
1212 if (rc)
1213 return rc;
1215 rc = set_inquire (STDIN_FILENO, NULL, &inq);
1216 if (rc)
1217 return rc;
1219 fprintf (stderr,
1220 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1221 print_help ();
1222 rl_event_hook = &interactive_hook;
1223 rl_set_keyboard_input_timeout (100000);
1225 for (;;)
1227 char *line;
1228 char *result = NULL;
1229 size_t len;
1231 rc = 0;
1232 line = readline ("pwm> ");
1233 if (interactive_error)
1235 rc = interactive_error;
1236 break;
1239 if (!line)
1241 rc = finalize ();
1242 if (!rc)
1243 break;
1245 if (gpg_err_code (rc) != GPG_ERR_CANCELED &&
1246 gpg_err_code (rc) != GPG_ERR_EOF)
1247 fprintf (stderr, "ERR %i: %s\n", rc, gpg_strerror (rc));
1249 continue;
1251 else if (!*line)
1253 free (line);
1254 continue;
1257 #ifdef HAVE_READLINE_HISTORY
1258 add_history (line);
1259 #endif
1260 inq->header = 0;
1261 rc = parse_dotcommand (line, &result, &len, inq);
1262 free (line);
1263 if (rc)
1265 char *tmp = NULL;
1267 if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
1268 (void) pwmd_command (pwm, &tmp, NULL, NULL, NULL,
1269 "GETINFO last_error");
1271 show_error (rc, tmp);
1272 pwmd_free (tmp);
1274 else if (result && len)
1275 printf ("%s%s", result, result[len - 1] != '\n' ? "\n" : "");
1277 pwmd_free (result);
1280 free_inquire (inq);
1281 return rc;
1283 #endif
1285 static char *
1286 itoa (long long int n)
1288 static char buf[64];
1290 snprintf (buf, sizeof (buf), "%llu", n);
1291 return buf;
1294 static gpg_error_t
1295 finalize ()
1297 gpg_error_t rc = 0;
1298 #ifdef HAVE_LIBREADLINE
1299 int quit = 0;
1301 if (!force_save && interactive)
1303 char *p, buf[16];
1304 int finished = 0;
1306 fprintf (stderr, "\n");
1310 fprintf (stderr,
1312 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1313 p = fgets (buf, sizeof (buf), stdin);
1315 if (feof (stdin))
1317 clearerr (stdin);
1318 return GPG_ERR_EOF;
1321 switch (*p)
1323 case 'h':
1324 print_help ();
1325 break;
1326 case 'c':
1327 return GPG_ERR_CANCELED;
1328 case 'Q':
1329 return 0;
1330 case 'f':
1331 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1332 "CLEARCACHE %s", filename);
1333 if (rc)
1334 return rc;
1336 interactive_hook ();
1337 break;
1338 case 'S':
1339 quit = 1;
1340 case 's':
1341 save = 1;
1342 finished = 1;
1343 break;
1344 default:
1345 break;
1348 while (!finished);
1350 #endif
1352 if (save && !filename)
1354 fprintf (stderr,
1356 ("No filename was specified on the command line. Aborting.\n"));
1357 return GPG_ERR_CANCELED;
1360 if (save && filename)
1362 char *args =
1363 pwmd_strdup_printf ("%s%s %s%s %s %s%s %s%s %s --s2k-count=%lu",
1364 keygrip ? "--keygrip=" : "",
1365 keygrip ? keygrip : "",
1366 sign_keygrip ? "--sign-keygrip=" : "",
1367 sign_keygrip ? sign_keygrip : "",
1368 no_passphrase ? "--no-passphrase" : "",
1369 cipher ? "--cipher=" : "", cipher ? cipher : "",
1370 iterations_arg ? "--cipher-iterations=" : "",
1371 iterations_arg ? itoa (iterations) : "",
1372 no_gpg_agent ? "--no-agent" : "",
1373 s2k_count);
1375 #ifdef HAVE_LIBREADLINE
1376 if (!quiet || interactive)
1378 #else
1379 if (!quiet)
1381 #endif
1382 fprintf (stderr, "\n");
1383 fprintf (stderr, N_("Saving changes ...\n"));
1386 rc = pwmd_save (pwm, args, inquire_cb, NULL);
1387 pwmd_free (args);
1389 if (!rc)
1390 no_passphrase = 0; // reset to avoid usage error on the next SAVE
1393 #ifdef HAVE_LIBREADLINE
1394 if (interactive)
1395 return rc ? rc : quit ? 0 : GPG_ERR_CANCELED;
1396 #endif
1398 return rc;
1402 main (int argc, char *argv[])
1404 int connected = 0;
1405 gpg_error_t rc;
1406 int opt;
1407 char command[ASSUAN_LINELENGTH], *p = NULL;
1408 char *result = NULL;
1409 size_t len;
1410 char *pinentry_path = NULL;
1411 char *display = NULL, *tty = NULL, *ttytype = NULL;
1412 char *lcctype = NULL, *lcmessages = NULL;
1413 int outfd = STDOUT_FILENO;
1414 FILE *outfp = stdout;
1415 FILE *inquirefp = stdin;
1416 int show_status = 1;
1417 char *clientname = "pwmc";
1418 char *inquire = NULL;
1419 char *inquire_line = NULL;
1420 int timeout = 0;
1421 #ifdef WITH_SSH
1422 int use_ssh_agent = 1;
1423 char *knownhosts = NULL;
1424 char *identity = NULL;
1425 #endif
1426 #ifdef WITH_GNUTLS
1427 char *cacert = NULL;
1428 char *clientcert = NULL;
1429 char *clientkey = NULL;
1430 char *prio = NULL;
1431 int tls_verify = 0;
1432 char *tls_fingerprint = NULL;
1433 #endif
1434 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1435 pwmd_socket_t socktype;
1436 long socket_timeout = 300;
1437 int connect_timeout = 120;
1438 #endif
1439 int lock_on_open = 1;
1440 long lock_timeout = 0;
1441 char *url = NULL;
1442 /* The order is important. */
1443 enum
1445 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1446 OPT_SOCKET_TIMEOUT, OPT_CONNECT_TIMEOUT,
1447 #endif
1448 #ifdef WITH_SSH
1449 OPT_USE_SSH_AGENT, OPT_IDENTITY, OPT_KNOWNHOSTS,
1450 #endif
1451 #ifdef WITH_GNUTLS
1452 OPT_CACERT, OPT_CLIENTCERT, OPT_CLIENTKEY, OPT_PRIORITY, OPT_VERIFY,
1453 OPT_SERVER_FP,
1454 #endif
1455 OPT_URL, OPT_LOCAL, OPT_FORCE_SAVE, OPT_TTYNAME, OPT_TTYTYPE,
1456 OPT_DISPLAY, OPT_LC_CTYPE, OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES,
1457 OPT_PINENTRY, OPT_KEYFILE, OPT_NEW_KEYFILE, OPT_NOLOCK,
1458 OPT_LOCK_TIMEOUT, OPT_SAVE, OPT_OUTPUT_FD, OPT_INQUIRE,
1459 OPT_INQUIRE_FD, OPT_INQUIRE_FILE, OPT_INQUIRE_LINE, OPT_NO_STATUS,
1460 OPT_NAME, OPT_VERSION, OPT_HELP, OPT_KEYGRIP, OPT_SIGN_KEYGRIP,
1461 OPT_NOPASSPHRASE, OPT_CIPHER, OPT_KEYPARAMS, OPT_NO_PINENTRY,
1462 OPT_S2K_COUNT, OPT_ITERATIONS, OPT_QUIET, OPT_NO_GPG_AGENT,
1463 #ifdef HAVE_LIBREADLINE
1464 OPT_INTERACTIVE,
1465 #endif
1467 const struct option long_opts[] = {
1468 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1469 {"socket-timeout", 1, 0, 0},
1470 {"connect-timeout", 1, 0, 0},
1471 #endif
1473 #ifdef WITH_SSH
1474 {"no-ssh-agent", 0, 0, 0},
1475 {"identity", 1, 0, 'i'},
1476 {"knownhosts", 1, 0, 'k'},
1477 #endif
1478 #ifdef WITH_GNUTLS
1479 {"ca-cert", 1, 0, 0},
1480 {"client-cert", 1, 0, 0},
1481 {"client-key", 1, 0, 0},
1482 {"tls-priority", 1, 0, 0},
1483 {"tls-verify", 0, 0, 0},
1484 {"tls-fingerprint", 1, 0, 0},
1485 #endif
1486 {"url", 1, 0, 0},
1487 {"local-pinentry", 0, 0},
1488 {"force-save", 0, 0},
1489 {"ttyname", 1, 0, 'y'},
1490 {"ttytype", 1, 0, 't'},
1491 {"display", 1, 0, 'd'},
1492 {"lc-ctype", 1, 0, 0},
1493 {"lc-messages", 1, 0, 0},
1494 {"timeout", 1, 0, 0},
1495 {"tries", 1, 0, 0},
1496 {"pinentry", 1, 0, 0},
1497 {"key-file", 1, 0, 0},
1498 {"new-key-file", 1, 0, 0},
1499 {"no-lock", 0, 0, 0},
1500 {"lock-timeout", 1, 0, 0},
1501 {"save", 0, 0, 'S'},
1502 {"output-fd", 1, 0, 0},
1503 {"inquire", 1, 0, 0},
1504 {"inquire-fd", 1, 0, 0},
1505 {"inquire-file", 1, 0, 0},
1506 {"inquire-line", 1, 0, 'L'},
1507 {"no-status", 0, 0, 0},
1508 {"name", 1, 0, 'n'},
1509 {"version", 0, 0, 0},
1510 {"help", 0, 0, 0},
1511 {"keygrip", 1, 0, 0},
1512 {"sign-keygrip", 1, 0, 0},
1513 {"no-passphrase", 0, 0, 0},
1514 {"cipher", 1, 0, 0},
1515 {"key-params", 1, 0, 0},
1516 {"no-pinentry", 0, 0, 0},
1517 {"s2k-count", 1, 0, 0},
1518 {"cipher-iterations", 1, 0, 0},
1519 {"quiet", 0, 0, 0},
1520 {"no-gpg-agent", 0, 0, 0},
1521 #ifdef HAVE_LIBREADLINE
1522 {"interactive", 0, 0},
1523 #endif
1524 {0, 0, 0, 0}
1526 #ifdef WITH_SSH
1527 const char *optstring = "L:y:t:d:P:I:Sn:i:k:";
1528 #else
1529 const char *optstring = "L:y:t:d:P:I:Sn:";
1530 #endif
1531 int opt_index = 0;
1533 #ifdef ENABLE_NLS
1534 setlocale (LC_ALL, "");
1535 bindtextdomain ("libpwmd", LOCALEDIR);
1536 #endif
1538 tries = DEFAULT_PIN_TRIES;
1539 inquirefd = STDIN_FILENO;
1541 while ((opt =
1542 getopt_long (argc, argv, optstring, long_opts, &opt_index)) != -1)
1544 switch (opt)
1546 /* Handle long options without a short option part. */
1547 case 0:
1548 switch (opt_index)
1550 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1551 case OPT_SOCKET_TIMEOUT:
1552 socket_timeout = strtol (optarg, &p, 10);
1553 break;
1554 case OPT_CONNECT_TIMEOUT:
1555 connect_timeout = strtol (optarg, &p, 10);
1556 break;
1557 #endif
1558 #ifdef WITH_SSH
1559 case OPT_USE_SSH_AGENT:
1560 use_ssh_agent = 0;
1561 break;
1562 #endif
1563 #ifdef WITH_GNUTLS
1564 case OPT_CACERT:
1565 cacert = optarg;
1566 break;
1567 case OPT_CLIENTCERT:
1568 clientcert = optarg;
1569 break;
1570 case OPT_CLIENTKEY:
1571 clientkey = optarg;
1572 break;
1573 case OPT_PRIORITY:
1574 prio = optarg;
1575 break;
1576 case OPT_VERIFY:
1577 tls_verify = 1;
1578 break;
1579 case OPT_SERVER_FP:
1580 tls_fingerprint = optarg;
1581 break;
1582 #endif
1583 case OPT_NO_GPG_AGENT:
1584 no_gpg_agent = 1;
1585 break;
1586 case OPT_KEYPARAMS:
1587 keyparams = optarg;
1588 break;
1589 case OPT_KEYFILE:
1590 keyfile = pwmd_strdup (optarg);
1591 break;
1592 case OPT_NEW_KEYFILE:
1593 new_keyfile = pwmd_strdup (optarg);
1594 break;
1595 case OPT_NOLOCK:
1596 lock_on_open = 0;
1597 break;
1598 case OPT_LOCK_TIMEOUT:
1599 lock_timeout = strtol (optarg, &p, 10);
1600 break;
1601 case OPT_URL:
1602 url = optarg;
1603 break;
1604 case OPT_LOCAL:
1605 local_pin = 1;
1606 break;
1607 case OPT_FORCE_SAVE:
1608 save = force_save = 1;
1609 break;
1610 case OPT_LC_CTYPE:
1611 lcctype = pwmd_strdup (optarg);
1612 break;
1613 case OPT_LC_MESSAGES:
1614 lcmessages = pwmd_strdup (optarg);
1615 break;
1616 case OPT_TIMEOUT:
1617 timeout = strtol (optarg, &p, 10);
1618 break;
1619 case OPT_TRIES:
1620 tries = strtol (optarg, &p, 10);
1621 break;
1622 case OPT_INQUIRE:
1623 inquire = optarg;
1624 break;
1625 case OPT_INQUIRE_FD:
1626 inquirefd = strtol (optarg, &p, 10);
1627 if (!p)
1629 inquirefp = fdopen (inquirefd, "r");
1630 if (!inquirefp)
1632 pwmd_free (password);
1633 err (EXIT_FAILURE, "%i", inquirefd);
1636 break;
1637 case OPT_INQUIRE_FILE:
1638 inquirefd = open (optarg, O_RDONLY);
1639 if (inquirefd == -1)
1641 pwmd_free (password);
1642 err (EXIT_FAILURE, "%s", optarg);
1644 inquirefp = fdopen (inquirefd, "r");
1645 break;
1646 case OPT_OUTPUT_FD:
1647 outfd = strtol (optarg, &p, 10);
1648 if (!p)
1650 outfp = fdopen (outfd, "w");
1651 if (!outfp)
1653 pwmd_free (password);
1654 err (EXIT_FAILURE, "%i", outfd);
1657 break;
1658 case OPT_NO_STATUS:
1659 show_status = 0;
1660 break;
1661 case OPT_VERSION:
1662 pwmd_free (password);
1663 printf ("%s (pwmc)\n\n"
1664 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013\n"
1665 "%s\n"
1666 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1667 "Compile-time features:\n"
1668 #ifdef HAVE_LIBREADLINE
1669 "+INTERACTIVE "
1670 #else
1671 "-INTERACTIVE "
1672 #endif
1673 #ifdef WITH_SSH
1674 "+SSH "
1675 #else
1676 "-SSH "
1677 #endif
1678 #ifdef WITH_GNUTLS
1679 "+GNUTLS "
1680 #else
1681 "-GNUTLS "
1682 #endif
1683 #ifdef WITH_PINENTRY
1684 "+PINENTRY "
1685 #else
1686 "-PINENTRY "
1687 #endif
1688 #ifdef WITH_QUALITY
1689 "+CRACK "
1690 #else
1691 "-CRACK "
1692 #endif
1693 #ifdef MEM_DEBUG
1694 "+MEM_DEBUG "
1695 #else
1696 "-MEM_DEBUG "
1697 #endif
1698 "\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1699 exit (EXIT_SUCCESS);
1700 case OPT_PINENTRY:
1701 pinentry_path = optarg;
1702 break;
1703 case OPT_HELP:
1704 usage (argv[0], EXIT_SUCCESS);
1705 case OPT_KEYGRIP:
1706 keygrip = optarg;
1707 break;
1708 case OPT_SIGN_KEYGRIP:
1709 sign_keygrip = optarg;
1710 break;
1711 case OPT_S2K_COUNT:
1712 s2k_count = strtoul (optarg, &p, 10);
1713 break;
1714 case OPT_ITERATIONS:
1715 iterations = strtoull (optarg, &p, 10);
1716 iterations_arg = 1;
1717 break;
1718 case OPT_QUIET:
1719 quiet = 1;
1720 show_status = 0;
1721 break;
1722 case OPT_NOPASSPHRASE:
1723 no_passphrase = 1;
1724 break;
1725 case OPT_CIPHER:
1726 cipher = optarg;
1727 break;
1728 case OPT_NO_PINENTRY:
1729 no_pinentry = 1;
1730 break;
1731 #ifdef HAVE_LIBREADLINE
1732 case OPT_INTERACTIVE:
1733 interactive = 1;
1734 break;
1735 #endif
1736 default:
1737 usage (argv[0], EXIT_FAILURE);
1740 if (p && *p)
1742 fprintf (stderr, N_("%s: invalid argument for option '--%s'\n"),
1743 argv[0], long_opts[opt_index].name);
1744 usage (argv[0], EXIT_FAILURE);
1747 break;
1748 #ifdef WITH_SSH
1749 case 'i':
1750 identity = optarg;
1751 break;
1752 case 'k':
1753 knownhosts = optarg;
1754 break;
1755 #endif
1756 case 'L':
1757 inquire_line = optarg;
1758 break;
1759 case 'y':
1760 tty = optarg;
1761 break;
1762 case 't':
1763 ttytype = optarg;
1764 break;
1765 case 'd':
1766 display = optarg;
1767 break;
1768 case 'S':
1769 save = 1;
1770 break;
1771 case 'n':
1772 clientname = optarg;
1773 break;
1774 default:
1775 pwmd_free (password);
1776 usage (argv[0], EXIT_FAILURE);
1780 #ifdef HAVE_LIBREADLINE
1781 if (interactive && !isatty (STDIN_FILENO))
1783 pwmd_free (password);
1784 usage (argv[0], EXIT_FAILURE);
1786 else if (isatty (STDIN_FILENO) && !inquire && !inquire_line)
1787 interactive = 1;
1788 #endif
1790 filename = argv[optind];
1791 #ifdef WITH_GNUTLS
1792 gnutls_global_set_mem_functions (pwmd_malloc, pwmd_malloc, NULL,
1793 pwmd_realloc, pwmd_free);
1794 #endif
1795 pwmd_init ();
1796 rc = pwmd_new (clientname, &pwm);
1797 if (rc)
1798 goto done;
1800 pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
1801 if (!quiet)
1802 fprintf (stderr, N_("Connecting ...\n"));
1804 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1805 socktype = is_remote_url (url);
1806 if (socktype != PWMD_SOCKET_LOCAL)
1808 local_pin = 1;
1809 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1810 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, connect_timeout);
1811 if (rc)
1812 goto done;
1813 #endif
1815 if (socktype == PWMD_SOCKET_SSH)
1817 #ifdef WITH_SSH
1818 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_CB, knownhost_cb);
1819 if (rc)
1820 goto done;
1822 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_DATA, clientname);
1823 if (rc)
1824 goto done;
1826 if (!getenv ("SSH_AUTH_SOCK") || identity)
1827 use_ssh_agent = 0;
1829 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_AGENT, use_ssh_agent);
1830 if (rc)
1831 goto done;
1833 rc = pwmd_connect (pwm, url, identity, knownhosts);
1834 #endif
1836 #ifdef WITH_GNUTLS
1837 else
1839 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_VERIFY, tls_verify);
1840 if (rc)
1841 goto done;
1843 rc = pwmd_connect (pwm, url, clientcert, clientkey, cacert, prio,
1844 tls_fingerprint);
1846 #endif
1848 else
1849 rc = pwmd_connect (pwm, url);
1850 #else
1851 rc = pwmd_connect (pwm, url);
1852 #endif
1853 if (rc)
1854 goto done;
1856 if (!quiet)
1857 fprintf (stderr, N_("Connected.\n"));
1859 connected = 1;
1860 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1861 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, socket_timeout);
1862 if (rc)
1863 goto done;
1864 #endif
1866 if (lock_timeout)
1868 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1869 "OPTION LOCK-TIMEOUT=%li", lock_timeout);
1870 if (rc)
1871 goto done;
1874 if (lock_on_open)
1876 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCK_ON_OPEN, 1);
1877 if (rc)
1878 goto done;
1881 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, NULL);
1882 if (rc)
1883 goto done;
1885 if (timeout > 0)
1887 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
1888 if (rc)
1889 goto done;
1892 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1893 if (rc)
1894 goto done;
1896 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY,
1897 (local_pin || keyfile || new_keyfile));
1898 if (rc)
1899 goto done;
1901 if (pinentry_path)
1903 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
1904 if (rc)
1905 goto done;
1908 if (display)
1910 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
1911 if (rc)
1912 goto done;
1915 if (tty)
1917 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, tty);
1918 if (rc)
1919 goto done;
1922 if (ttytype)
1924 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
1925 if (rc)
1926 goto done;
1929 if (lcctype)
1931 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
1932 if (rc)
1933 goto done;
1936 if (lcmessages)
1938 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES, lcmessages);
1939 if (rc)
1940 goto done;
1943 if (show_status)
1945 rc = pwmd_setopt (pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
1946 if (rc)
1947 goto done;
1950 if (filename)
1952 rc = open_command (filename);
1953 if (rc)
1954 goto done;
1957 #ifdef HAVE_LIBREADLINE
1958 if (interactive)
1960 if (!force_save)
1961 save = 0;
1963 rc = do_interactive ();
1964 result = NULL;
1965 goto do_exit;
1967 #endif
1969 if (inquire)
1971 struct inquire_s *inq = NULL;
1973 rc = set_inquire (inquirefd, inquire_line, &inq);
1974 if (!rc)
1975 rc = pwmd_command (pwm, &result, &len, inquire_cb, inq, inquire);
1977 free_inquire (inq);
1978 goto done;
1981 fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK);
1982 ssize_t n;
1984 for (;;)
1986 rc = process_cmd ();
1988 if (rc)
1989 goto done;
1991 n = read (STDIN_FILENO, command, sizeof (command));
1992 if (n == -1)
1994 if (errno == EAGAIN)
1996 usleep (100000);
1997 continue;
2000 rc = gpg_error_from_errno (errno);
2001 goto done;
2003 else if (!n)
2004 goto done;
2006 p = command;
2007 command[n] = 0;
2008 break;
2011 if (!p || !*p || !strcasecmp (p, "BYE"))
2012 goto done;
2015 struct inquire_s *inq = NULL;
2016 rc = set_inquire (inquirefd, inquire_line, &inq);
2017 if (!rc)
2019 rc = parse_dotcommand (command, &result, &len, inq);
2020 free_inquire (inq);
2023 if (rc)
2024 goto done;
2026 done:
2027 if (result)
2029 fwrite (result, 1, result[len - 1] == 0 ? len - 1 : len, outfp);
2030 fflush (outfp);
2031 pwmd_free (result);
2034 pwmd_free (password);
2035 password = result = NULL;
2036 if (!rc)
2037 rc = finalize ();
2038 else if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
2039 (void) pwmd_command (pwm, &result, NULL, NULL, NULL,
2040 "GETINFO last_error");
2042 #ifdef HAVE_LIBREADLINE
2043 do_exit:
2044 #endif
2045 memset (command, 0, sizeof (command));
2046 pwmd_close (pwm);
2047 pwmd_free (keyfile);
2048 pwmd_free (new_keyfile);
2049 pwmd_deinit ();
2051 if (rc && !quiet)
2052 show_error (rc, result);
2054 pwmd_free (result);
2055 if (connected && !quiet)
2056 fprintf (stderr, N_("Connection closed.\n"));
2058 exit (rc ? EXIT_FAILURE : EXIT_SUCCESS);