pwmc: Fix --output-fd.
[libpwmd.git] / src / pwmc.c
blob494ea56415952ede62b4ec90dcddf026585c4cfe
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014
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"
85 #define DEFAULT_PIN_TIMEOUT 30
86 #define DEFAULT_PIN_TRIES 3
87 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
88 ? gpg_error(rc) : rc
90 static int no_pinentry;
91 static pwm_t *pwm;
92 static char *filename;
93 static int save;
94 static char *keyid;
95 static char *sign_keyid;
96 static char *keyparams;
97 static char *keyfile;
98 static char *new_keyfile;
99 static int tries;
100 static int local_pin;
101 static int inquirefd;
102 static int statusfd;
103 FILE *statusfp;
104 static int quiet;
106 struct inquire_s
108 int fd;
109 char *line;
110 size_t len;
111 size_t size; // from stat(2).
112 char *last_keyword;
115 static gpg_error_t finalize ();
116 static gpg_error_t set_inquire (int fd, const char *line,
117 struct inquire_s **result);
118 static gpg_error_t parse_dotcommand (const char *line, char **result,
119 size_t * len, struct inquire_s *inq);
120 static gpg_error_t open_command (const char *line);
121 #ifdef WITH_SSH
122 static gpg_error_t get_password (char **result, pwmd_pinentry_t w, int echo);
123 #endif
125 static void
126 show_error (pwm_t *pwm, gpg_error_t rc, const char *str)
128 #ifdef WITH_GNUTLS
129 if (pwmd_tls_error (pwm))
130 fprintf(stderr, "TLS: %s\n", gnutls_strerror(pwmd_tls_error(pwm)));
131 #endif
132 fprintf (stderr, "ERR %i: %s%s%s%s", rc, gpg_strerror (rc),
133 str ? ": " : "", str ? str : "", str ? "" : "\n");
136 static void
137 usage (const char *pn, int status)
139 fprintf (status == EXIT_FAILURE ? stderr : stdout,
140 N_("Usage: pwmc [options] [file]\n"
141 " --url <string>\n"
142 " a url string to connect to (%s, see below)\n"
143 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
144 " --connect-timeout <seconds>\n"
145 " seconds before connecting to a remote host fails (0=disabled, 120)\n"
146 " --socket-timeout <seconds>\n"
147 " seconds before a remote command fails (0=disabled, 300)\n"
148 #endif
149 #ifdef WITH_GNUTLS
150 " --ca-cert <filename>\n"
151 " certificate authority (CA) used to sign the server cert\n"
152 " --client-cert <filename>\n"
153 " client certificate to use for authentication\n"
154 " --client-key <filename>\n"
155 " key file used to protect the client certificate\n"
156 " --tls-priority <string>\n"
157 " compression, cipher and hash algorithm string (SECURE256)\n"
158 " --tls-verify\n"
159 " verify the hostname against the server certificate\n"
160 " --tls-fingerprint <string>\n"
161 " a SHA-256 hash of the server fingerprint to verify against\n"
162 #endif
163 #ifdef WITH_SSH
164 " --no-ssh-agent\n"
165 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
166 " --identity, -i <filename>\n"
167 " the ssh identity file to use for authentication\n"
168 " --knownhosts, -k <filename>\n"
169 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
170 #endif
171 " --no-lock\n"
172 " do not lock the data file upon opening it\n"
173 " --lock-timeout <N>\n"
174 " time in tenths of a second to wait for a locked data file (50)\n"
175 " --name, -n <string>\n"
176 " set the client name\n"
177 " --pinentry <path>\n"
178 " the full path to the pinentry binary\n"
179 " --local-pinentry\n"
180 " force using a local pinentry\n"
181 " --no-pinentry\n"
182 " disable pinentry both remotely and locally\n"
183 " --ttyname, -y <path>\n"
184 " tty that pinentry will use\n"
185 " --ttytype, -t <string>\n"
186 " pinentry terminal type (default is $TERM)\n"
187 " --display, -d\n"
188 " pinentry display (default is $DISPLAY)\n"
189 " --lc-ctype <string>\n"
190 " locale setting for pinentry\n"
191 " --lc-messages <string>\n"
192 " locale setting for pinentry\n"
193 " --tries <N>\n"
194 " number of pinentry tries before failing (3)\n"
195 " --timeout <seconds>\n"
196 " pinentry timeout\n"
197 " --inquire <COMMAND>\n"
198 " the specified command (with any options) uses a server inquire while\n"
199 " command data is read via the inquire file descriptor (stdin)\n"
200 " --inquire-line, -L <STRING>\n"
201 " the initial line to send (i.e., element path) before the inquire data\n"
202 " --inquire-fd <FD>\n"
203 " read inquire data from the specified file descriptor (stdin)\n"
204 " --inquire-file <filename>\n"
205 " read inquire data from the specified filename\n"
206 " --output-fd <FD>\n"
207 " redirect command output to the specified file descriptor\n"
208 " --save, -S\n"
209 " send the SAVE command before exiting\n"
210 " --key-file <filename>\n"
211 " obtain the passphrase from the specified filename\n"
212 " --new-key-file <filename>\n"
213 " obtain the passphrase to save with from the specified filename\n"
214 " --key-params <string>\n"
215 " the key parameters to use when saving a new file (pwmd default)\n"
216 " --keyid <recipient>[,<recipient>]\n"
217 " the public key ID to u\n"
218 " --sign-keyid <string>\n"
219 " the key ID to sign the data file with\n"
220 " --no-status\n"
221 " disable showing of status messages from the server\n"
222 " --quiet\n"
223 " disable showing of extra messages (implies --no-status)\n"
224 " --status-fd <FD>\n"
225 " redirect status messages to the specified file descriptor\n"
226 #ifdef HAVE_LIBREADLINE
227 " --interactive\n"
228 " use a shell like interface to pwmd (allows more than one command)\n"
229 #endif
230 " --version\n"
231 " --help\n"),
232 #ifdef DEFAULT_PWMD_SOCKET
233 DEFAULT_PWMD_SOCKET
234 #else
235 "~/.pwmd/socket"
236 #endif
238 fprintf (status == EXIT_FAILURE ? stderr : stdout,
239 N_("\n"
240 "An optional url may be in the form of:\n"
241 " --url /path/to/socket\n"
242 " --url file://[path/to/socket]\n"
243 #ifdef WITH_SSH
244 " or\n"
245 " --url ssh[46]://[username@]hostname[:port]\n"
246 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
247 #endif
248 #ifdef WITH_GNUTLS
249 " or\n"
250 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
251 " --client-key filename\n"
252 #endif
253 #ifdef HAVE_LIBREADLINE
254 "\n"
255 "Interactive mode is used when input is from a terminal.\n"
256 #endif
258 exit (status);
261 static gpg_error_t
262 inquire_cb (void *user, const char *keyword, gpg_error_t rc,
263 char **data, size_t * size)
265 struct inquire_s *inq = user;
266 int is_password = 0;
267 int is_newpassword = 0;
269 *data = NULL;
270 *size = 0;
272 if (rc)
273 return rc;
275 if (!strcmp (keyword, "PASSPHRASE"))
276 is_password = 1;
277 else if (!strcmp (keyword, "NEW_PASSPHRASE"))
278 is_newpassword = 1;
279 #ifdef HAVE_LIBREADLINE
280 else if (!strcmp (keyword, "KEYPARAM") && !interactive)
282 #else
283 else if (!strcmp (keyword, "KEYPARAM"))
285 #endif
286 if (!keyparams || !*keyparams)
287 return gpg_error (GPG_ERR_INV_PARAMETER);
289 *data = keyparams;
290 *size = strlen (keyparams);
291 return gpg_error (GPG_ERR_EOF);
294 if ((is_newpassword && new_keyfile) || (is_password && keyfile))
296 int fd = open (is_password ? keyfile : new_keyfile, O_RDONLY);
298 if (fd == -1)
300 fprintf (stderr, "%s: %s\n", is_newpassword ? new_keyfile : keyfile,
301 strerror (errno));
302 return gpg_error_from_syserror ();
305 rc = set_inquire (fd, NULL, &inq);
306 if (rc)
308 close (fd);
309 return rc;
312 if (!quiet)
313 fprintf (stderr, N_("Using keyfile '%s' as %s.\n"),
314 is_newpassword ? new_keyfile : keyfile, keyword);
316 if (!new_keyfile || is_newpassword)
318 pwmd_socket_t t;
320 pwmd_socket_type (pwm, &t);
321 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
322 if (!no_pinentry && t == PWMD_SOCKET_LOCAL)
323 pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 0);
326 else if ((is_password && !keyfile) || (is_newpassword && !new_keyfile))
328 char *tmp;
330 rc = pwmd_password (pwm, keyword, &tmp, &inq->len);
331 if (rc && gpg_err_code (rc) != GPG_ERR_EOF)
332 return rc;
334 pwmd_free (inq->line);
335 inq->line = tmp;
336 *data = inq->line;
337 *size = inq->len;
338 return gpg_error (GPG_ERR_EOF);
340 #ifdef HAVE_LIBREADLINE
341 else if ((!inq->last_keyword || strcmp (keyword, inq->last_keyword))
342 && interactive)
344 fprintf (stderr,
346 ("%sPress CTRL-D to send the current line. Press twice to end. %s:\n"),
347 inq->last_keyword ? "\n" : "", keyword);
348 pwmd_free (inq->last_keyword);
349 inq->last_keyword = pwmd_strdup (keyword);
351 #endif
353 /* The first part of the command data. */
354 if (inq->len)
356 *data = inq->line;
357 *size = inq->len;
358 inq->len = 0;
359 return inq->fd == -1 ? gpg_error (GPG_ERR_EOF) : 0;
362 *size = read (inq->fd, inq->line, ASSUAN_LINELENGTH);
363 if (*size == -1)
365 *size = 0;
366 return gpg_error (gpg_error_from_syserror ());
368 else if (*size)
369 *data = inq->line;
370 else if (inq->fd != STDIN_FILENO && (is_newpassword || is_password))
372 *inq->line = 0;
373 inq->size = 1;
374 *data = inq->line;
375 *size = 1;
378 if (((is_newpassword && new_keyfile) || (is_password && keyfile))
379 && *size == inq->size)
380 return gpg_error (GPG_ERR_EOF);
382 return *size ? 0 : gpg_error (GPG_ERR_EOF);
385 static int
386 status_msg_cb (void *data, const char *line)
388 char *p = strchr (line, ' ');
390 if (!strcmp (line, "KEEPALIVE"))
391 return 0;
392 else if (!strncmp (line, "GPGME", 5))
393 return 0;
394 else if (!strncmp (line, "PASSPHRASE_HINT", 15))
395 return 0;
396 else if (!strncmp (line, "PASSPHRASE_INFO", 15))
397 return 0;
398 else if (!strncmp (line, "STATE", 5))
399 return 0;
401 if (statusfd != STDERR_FILENO && *line != '#'
402 && p && strchr (p, ' ') && *++p)
404 char *p1 = strchr (p, ' ');
405 int a = strtol (p, NULL, 10);
407 if (isdigit (*p) && p1)
409 int b = strtol (p1, NULL, 10);
410 char l[64] = { 0 };
411 int t = a && b ? a * 100 / b : 0;
413 strncpy (l, line, strlen (line) - strlen (p) - 1);
414 fprintf (statusfp, "\r%s %i/%i %i%%%s", l, a, b, t,
415 a == b ? "\n" : "");
416 fflush (statusfp);
417 return 0;
421 fprintf (statusfp, "%s\n", line);
422 fflush (statusfp);
423 #ifdef HAVE_LIBREADLINE
424 rl_on_new_line ();
425 #endif
426 return 0;
429 static gpg_error_t
430 process_cmd ()
432 return pwmd_process (pwm);
435 #ifdef WITH_SSH
436 static gpg_error_t
437 get_password (char **result, pwmd_pinentry_t w, int echo)
439 char buf[LINE_MAX] = { 0 }, *p;
440 struct termios told, tnew;
441 char *key = NULL;
443 *result = NULL;
445 if (!isatty (STDIN_FILENO))
447 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
448 return GPG_ERR_ENOTTY;
451 if (!echo)
453 if (tcgetattr (STDIN_FILENO, &told) == -1)
454 return gpg_error_from_syserror ();
456 memcpy (&tnew, &told, sizeof (struct termios));
457 tnew.c_lflag &= ~(ECHO);
458 tnew.c_lflag |= ICANON | ECHONL;
460 if (tcsetattr (STDIN_FILENO, TCSANOW, &tnew) == -1)
462 int n = errno;
464 tcsetattr (STDIN_FILENO, TCSANOW, &told);
465 return gpg_error_from_errno (n);
469 switch (w)
471 case PWMD_PINENTRY_OPEN:
472 fprintf (stderr, N_("Password for %s: "), filename);
473 break;
474 case PWMD_PINENTRY_OPEN_FAILED:
475 fprintf (stderr, N_("Invalid password. Password for %s: "), filename);
476 break;
477 case PWMD_PINENTRY_SAVE:
478 fprintf (stderr, N_("New password for %s: "), filename);
479 break;
480 case PWMD_PINENTRY_SAVE_CONFIRM:
481 fprintf (stderr, N_("Confirm password: "));
482 break;
483 default:
484 break;
487 if ((p = fgets (buf, sizeof (buf), stdin)) == NULL)
489 tcsetattr (STDIN_FILENO, TCSANOW, &told);
490 return 0;
493 if (!echo)
494 tcsetattr (STDIN_FILENO, TCSANOW, &told);
496 if (feof (stdin))
498 clearerr (stdin);
499 return GPG_ERR_CANCELED;
502 p[strlen (p) - 1] = 0;
504 if (buf[0])
506 key = pwmd_strdup_printf ("%s", p);
507 memset (&buf, 0, sizeof (buf));
509 if (!key)
510 return GPG_ERR_ENOMEM;
513 *result = key;
514 return 0;
517 static gpg_error_t
518 knownhost_cb (void *data, const char *host, const char *key, size_t len)
520 gpg_error_t rc;
521 char *buf =
522 pwmd_strdup_printf (N_
523 ("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?"),
524 (char *) data, host, host);
526 if (no_pinentry && !isatty (STDIN_FILENO))
528 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
529 pwmd_free (buf);
530 return GPG_ERR_ENOTTY;
532 else if (no_pinentry)
534 for (char *p = buf, len = 0; *p; p++, len++)
536 if (*p == '\n')
537 len = 0;
539 if (len == 78)
541 char *t = p;
543 while (!isspace (*(--p)));
544 *p = '\n';
545 p = t;
546 len = 0;
550 fprintf (stderr, "%s\n\n", buf);
551 pwmd_free (buf);
555 char *result;
557 fprintf (stderr, N_("Trust this connection [y/N]: "));
558 fflush (stderr);
559 rc = get_password (&result, PWMD_PINENTRY_CONFIRM, 1);
561 if (rc)
562 return rc;
564 if (!result || !*result || *result == 'n' || *result == 'N')
566 if (result && *result)
567 pwmd_free (result);
569 return GPG_ERR_NOT_CONFIRMED;
572 if ((*result == 'y' || *result == 'Y') && *(result + 1) == 0)
574 pwmd_free (result);
575 return 0;
578 while (1);
581 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, buf);
582 pwmd_free (buf);
584 if (rc)
585 return rc;
587 return pwmd_getpin (pwm, NULL, NULL, NULL, PWMD_PINENTRY_CONFIRM);
589 #endif
591 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
592 static pwmd_socket_t
593 is_remote_url (const char *str)
595 if (!str)
596 return PWMD_SOCKET_LOCAL;
598 #ifdef WITH_SSH
599 if (strstr (str, "ssh://") || strstr (str, "ssh4://")
600 || strstr (str, "ssh6://"))
601 return PWMD_SOCKET_SSH;
602 #endif
604 #ifdef WITH_GNUTLS
605 if (strstr (str, "tls://") || strstr (str, "tls4://")
606 || strstr (str, "tls6://"))
607 return PWMD_SOCKET_TLS;
608 #endif
610 return PWMD_SOCKET_LOCAL;
612 #endif
614 static char *
615 escape (const char *str)
617 const char *p;
618 char *buf = pwmd_malloc (ASSUAN_LINELENGTH + 1), *b = buf;
619 size_t len = 0;
621 for (p = str; *p; p++, len++)
623 if (len == ASSUAN_LINELENGTH)
624 break;
626 if (*p == '\\')
628 switch (*++p)
630 case 't':
631 *b++ = '\t';
632 break;
633 case 'n':
634 *b++ = '\n';
635 break;
636 case 'v':
637 *b++ = '\v';
638 break;
639 case 'b':
640 *b++ = '\b';
641 break;
642 case 'f':
643 *b++ = '\f';
644 break;
645 case 'r':
646 *b++ = '\r';
647 break;
648 default:
649 *b++ = *p;
650 break;
653 if (!*p)
654 break;
656 continue;
659 *b++ = *p;
662 *b = 0;
663 return buf;
666 static void
667 free_inquire (struct inquire_s *inq)
669 if (!inq)
670 return;
672 pwmd_free (inq->line);
674 if (inq->fd != -1 && inq->fd != STDIN_FILENO)
675 close (inq->fd);
677 pwmd_free (inq->last_keyword);
678 pwmd_free (inq);
681 /* When *result is not NULL it is updated to the new values and not
682 * reallocated. */
683 static gpg_error_t
684 set_inquire (int fd, const char *line, struct inquire_s **result)
686 struct inquire_s inq = { 0 };
687 struct stat st = { 0 };
688 gpg_error_t rc;
690 if (fd != -1)
692 if (fstat (fd, &st) == -1)
693 return gpg_error_from_syserror ();
695 inq.size = st.st_size;
698 inq.fd = fd;
699 inq.line = pwmd_calloc (1, ASSUAN_LINELENGTH);
700 if (!inq.line)
701 return GPG_ERR_ENOMEM;
703 if (line)
705 char *s = escape (line);
707 if (!s)
709 pwmd_free (inq.line);
710 return GPG_ERR_ENOMEM;
713 if (strlen (s) >= ASSUAN_LINELENGTH)
715 pwmd_free (inq.line);
716 pwmd_free (s);
717 return GPG_ERR_LINE_TOO_LONG;
720 strncpy (inq.line, s, ASSUAN_LINELENGTH - 1);
721 inq.len = strlen (s);
722 pwmd_free (s);
725 rc = pwmd_setopt (pwm, PWMD_OPTION_INQUIRE_TOTAL,
726 st.st_size ? st.st_size + strlen (inq.line) : 0);
727 if (rc)
729 pwmd_free (inq.line);
730 return rc;
733 if (*result == NULL)
734 *result = pwmd_malloc (sizeof (struct inquire_s));
735 else
737 if ((*result)->fd != -1 && (*result)->fd != STDIN_FILENO)
738 close ((*result)->fd);
740 pwmd_free ((*result)->line);
741 (*result)->line = NULL;
742 (*result)->fd = -1;
743 (*result)->len = 0;
746 memcpy (*result, &inq, sizeof (struct inquire_s));
747 memset (&inq, 0, sizeof (struct inquire_s));
748 return rc;
751 #ifdef HAVE_LIBREADLINE
752 static int
753 interactive_hook (void)
755 interactive_error = process_cmd ();
757 if (interactive_error)
758 rl_event_hook = NULL;
760 return 0;
763 static void
764 print_help ()
766 fprintf (stderr,
768 ("------------------------------------------------------------------------------\n"
769 "Elements are TAB delimited. Press CTRL-V then TAB to insert from the prompt.\n"
770 "\n"
771 "Type HELP for protocol commands. Type .help for pwmc commands. Press CTRL-D\n"
772 "to quit.\n"
773 "------------------------------------------------------------------------------\n"));
775 #endif
777 static char *
778 parse_arg (const char *src, char *dst, size_t len)
780 char *p = dst;
781 const char *s = src;
782 size_t n = 0;
784 for (; s && *s && *s != ' ' && n < len; s++, n++)
785 *p++ = *s;
787 *p = 0;
788 return dst;
791 static char *
792 parse_opt (char **line, const char *opt, gpg_error_t * rc)
794 static char result[ASSUAN_LINELENGTH] = { 0 }, *r = result;
795 char *s = strstr (*line, opt);
797 *rc = 0;
798 result[0] = 0;
799 r = result;
801 if (s)
803 size_t len = 0;
804 int quote = 0;
805 size_t rlen = strlen (opt);
806 char *p = s + rlen;
807 int lastc = 0;
809 while (*p && *p == ' ')
811 rlen++;
812 p++;
815 for (; *p && len < sizeof (result) - 1; p++, rlen++)
817 if (isspace (*p) && !quote)
818 break;
820 if (*p == '\"' && lastc != '\\')
822 quote = !quote;
823 lastc = *p;
824 continue;
827 *r++ = lastc = *p;
828 len++;
831 *r = 0;
833 if (len >= sizeof (result) - 1)
834 *rc = GPG_ERR_LINE_TOO_LONG;
835 else
837 p = s + rlen;
839 while (*p && *p == ' ')
840 p++;
842 *line = p;
846 return result;
849 static gpg_error_t
850 read_command (const char *line, char **result, size_t * len)
852 int fd;
853 gpg_error_t rc = 0;
854 char *filename = NULL;
855 struct inquire_s *inq = NULL;
856 char *p = (char *) line;
857 const char *prefix = parse_opt (&p, "--prefix", &rc);
859 if (rc)
860 return rc;
862 rc = GPG_ERR_SYNTAX;
864 if (p && *p)
866 char filebuf[ASSUAN_LINELENGTH];
868 while (*p && isspace (*p))
869 p++;
871 filename = parse_arg (p, filebuf, sizeof (filebuf));
872 if (filename && *filename)
874 p += strlen (filename) + 1;
876 while (*p && isspace (*p))
877 p++;
879 if (*p)
880 rc = 0;
884 if (rc)
886 fprintf (stderr,
888 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
889 fprintf (stderr,
891 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\" = \")\n"));
892 return rc;
895 fd = open (filename, O_RDONLY);
896 if (fd == -1)
897 return gpg_error_from_syserror ();
899 rc = set_inquire (fd, prefix && *prefix ? prefix : NULL, &inq);
900 if (rc)
902 close (fd);
903 return rc;
906 rc = pwmd_command (pwm, result, len, inquire_cb, inq, p);
907 free_inquire (inq);
908 return rc;
911 static gpg_error_t
912 redir_command (const char *line)
914 const char *p = line;
915 int fd;
916 gpg_error_t rc = GPG_ERR_SYNTAX;
917 char *filename = NULL;
918 struct inquire_s *inq = NULL;
919 char *result = NULL;
920 size_t len = 0;
922 if (p && *p && *++p)
924 char filebuf[ASSUAN_LINELENGTH];
926 filename = parse_arg (p, filebuf, sizeof (filebuf));
927 if (filename && *filename)
929 p += strlen (filename) + 1;
931 while (*p && isspace (*p))
932 p++;
934 if (*p)
935 rc = 0;
939 if (rc)
941 fprintf (stderr, N_("Usage: .redir <filename> <command> [args]\n"));
942 return rc;
945 fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
946 if (fd == -1)
947 return gpg_error_from_syserror ();
949 #ifdef HAVE_LIBREADLINE
950 rc = set_inquire (interactive ? STDIN_FILENO : inquirefd, NULL, &inq);
951 #else
952 rc = set_inquire (inquirefd, NULL, &inq);
953 #endif
954 if (rc)
956 close (fd);
957 return rc;
960 rc = parse_dotcommand (p, &result, &len, inq);
961 if (!rc && result && len--)
962 { // null byte which is always appended
963 if (write (fd, result, len) != len)
964 rc = GPG_ERR_TOO_SHORT;
965 pwmd_free (result);
968 free_inquire (inq);
969 close (fd);
970 return rc;
973 static gpg_error_t
974 help_command (const char *line)
976 fprintf (stderr,
977 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
978 " .redir <filename> <command>\n"
979 " redirect the output of a command to the specified file\n"
980 "\n"
981 " .open <filename>\n"
982 " open the specified filename losing any changes to the current one\n"
983 "\n"
984 " .read [--prefix <string>] <filename> <command> [args]\n"
985 " obtain data from the specified filename for an inquire command\n"
986 "\n"
987 " .set help | <name> [<value>]\n"
988 " set option <name> to <value>\n"
989 "\n"
990 " .save [args]\n"
991 " write changes of the file to disk\n"
992 "\n"
993 " .passwd [args]\n"
994 " change the passphrase of a data file\n"
995 "\n"
996 " .help\n"
997 " this help text\n"));
998 return 0;
1001 static gpg_error_t
1002 open_command (const char *line)
1004 struct inquire_s *inq = NULL;
1005 const char *filename = line;
1006 gpg_error_t rc;
1008 while (filename && isspace (*filename))
1009 filename++;
1011 if (!filename || !*filename)
1013 fprintf (stderr, N_("Usage: .open <filename>\n"));
1014 return GPG_ERR_SYNTAX;
1017 #ifdef HAVE_LIBREADLINE
1018 if (interactive || !quiet)
1019 #else
1020 if (!quiet)
1021 #endif
1022 fprintf (stderr, N_("Opening data file \"%s\" ...\n"), filename);
1024 #ifdef HAVE_LIBREADLINE
1025 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1026 #else
1027 rc = set_inquire (-1, NULL, &inq);
1028 #endif
1029 if (rc)
1030 return rc;
1032 if (keyfile)
1033 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1034 else
1035 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1037 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1038 rc = pwmd_open (pwm, filename, inquire_cb, inq);
1039 free_inquire (inq);
1040 return rc;
1043 static gpg_error_t
1044 set_command (const char *line)
1046 gpg_error_t rc = 0;
1047 char name[256] = { 0 };
1048 char value[512] = { 0 };
1049 char *namep;
1050 char *valuep;
1051 const char *p = line;
1053 while (p && *p && isspace (*p))
1054 p++;
1056 namep = parse_arg (p, name, sizeof (name));
1057 if (!namep || !*namep)
1059 fprintf (stderr, N_("Usage: .set help | <name> [<value>]\n"));
1060 return GPG_ERR_SYNTAX;
1063 p += strlen (namep);
1064 while (p && *p && isspace (*p))
1065 p++;
1067 valuep = parse_arg (p, value, sizeof (value));
1069 if (!strcmp (name, "keyfile") || !strcmp (name, "new-keyfile"))
1071 int is_newkeyfile = 1;
1073 if (!strcmp (name, "keyfile"))
1074 is_newkeyfile = 0;
1076 if (is_newkeyfile)
1078 pwmd_free (new_keyfile);
1079 new_keyfile = NULL;
1081 else
1083 pwmd_free (keyfile);
1084 keyfile = NULL;
1087 p += strlen (valuep);
1088 while (p && *p && isspace (*p))
1089 p++;
1091 valuep = (char *) p;
1092 if (!rc && *valuep)
1094 if (is_newkeyfile)
1095 new_keyfile = pwmd_strdup (value);
1096 else
1097 keyfile = pwmd_strdup (value);
1099 if (!rc)
1101 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 1);
1102 if (!rc)
1103 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1106 else if (!local_pin && !no_pinentry)
1108 pwmd_socket_t t;
1110 pwmd_socket_type (pwm, &t);
1111 if (t == PWMD_SOCKET_LOCAL)
1113 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 0);
1114 if (!rc)
1115 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1119 else if (!strcmp(name, "pinentry-timeout"))
1121 char *e = NULL;
1122 int n = strtol(valuep, &e, 10);
1124 if (e && *e)
1125 return gpg_error (GPG_ERR_INV_VALUE);
1127 if (!valuep || !*valuep)
1128 n = DEFAULT_PIN_TIMEOUT;
1130 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, n);
1132 else if (!strcmp (name, "help"))
1134 fprintf (stderr,
1136 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1137 "delimited. When no value is specified the option is unset.\n\n"
1138 "keyfile <datafile> [<filename>]\n"
1139 " set or unset the keyfile to be used when a passphrase is required (*)\n"
1140 "\n"
1141 "new-keyfile <datafile> [<filename>]\n"
1142 " set or unset the keyfile to be used when a new passphrase is required (*)\n"
1143 "\n"
1144 "pinentry-timeout <seconds>\n"
1145 " the amount of seconds before pinentry gives up waiting for input\n"
1146 "\n"
1147 "* = the next protocol command will unset this value\n"
1150 else
1151 rc = GPG_ERR_UNKNOWN_OPTION;
1153 return rc;
1156 static gpg_error_t
1157 save_command (const char *line)
1159 struct inquire_s *inq = NULL;
1160 gpg_error_t rc;
1162 #ifdef HAVE_LIBREADLINE
1163 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1164 #else
1165 rc = set_inquire (-1, NULL, &inq);
1166 #endif
1167 if (rc)
1168 return rc;
1170 if (new_keyfile || keyfile)
1171 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1173 rc = pwmd_save (pwm, line, inquire_cb, inq);
1174 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1175 free_inquire (inq);
1176 return rc;
1179 static gpg_error_t
1180 do_save_passwd_command (const char *line, int save)
1182 struct inquire_s *inq = NULL;
1183 gpg_error_t rc;
1185 #ifdef HAVE_LIBREADLINE
1186 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1187 #else
1188 rc = set_inquire (-1, NULL, &inq);
1189 #endif
1190 if (rc)
1191 return rc;
1193 if (new_keyfile || keyfile)
1194 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1196 if (save)
1197 rc = pwmd_save (pwm, line, inquire_cb, inq);
1198 else
1199 rc = pwmd_passwd (pwm, line, inquire_cb, inq);
1201 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1202 free_inquire (inq);
1203 return rc;
1206 static gpg_error_t
1207 parse_dotcommand (const char *line, char **result,
1208 size_t * len, struct inquire_s *inq)
1210 const char *p = line;
1211 gpg_error_t rc = 0;
1213 if (!strncmp (p, ".read", 5))
1214 rc = read_command (p + 5, result, len);
1215 else if (!strncmp (p, ".redir", 6))
1216 rc = redir_command (p + 6);
1217 else if (!strncmp (p, ".help", 5))
1218 rc = help_command (p + 5);
1219 else if (!strncmp (p, ".open", 5))
1220 rc = open_command (p + 5);
1221 else if (!strncmp (p, ".set", 4))
1222 rc = set_command (p + 4);
1223 else if (!strncmp (p, ".save", 5))
1224 rc = do_save_passwd_command (p + 5, 1);
1225 else if (!strncmp (p, ".passwd", 7))
1226 rc = do_save_passwd_command (p + 7, 0);
1227 else
1229 rc = pwmd_command (pwm, result, len, inquire_cb, inq, line);
1230 #ifdef HAVE_LIBREADLINE
1231 if (interactive)
1233 #endif
1234 pwmd_free (keyfile);
1235 pwmd_free (new_keyfile);
1236 keyfile = new_keyfile = NULL;
1237 #ifdef HAVE_LIBREADLINE
1239 #endif
1242 return FINISH (rc);
1245 #ifdef HAVE_LIBREADLINE
1246 static gpg_error_t
1247 do_interactive ()
1249 gpg_error_t rc;
1250 struct inquire_s *inq = NULL;
1252 rl_initialize ();
1253 rc = process_cmd ();
1254 if (rc)
1255 return rc;
1257 rc = set_inquire (STDIN_FILENO, NULL, &inq);
1258 if (rc)
1259 return rc;
1261 fprintf (stderr,
1262 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1263 print_help ();
1264 rl_event_hook = &interactive_hook;
1265 rl_set_keyboard_input_timeout (100000);
1267 for (;;)
1269 char *line;
1270 char *result = NULL;
1271 size_t len;
1273 rc = 0;
1274 line = readline ("pwm> ");
1275 if (interactive_error)
1277 free (line);
1278 rc = interactive_error;
1279 break;
1282 if (!line)
1284 rc = finalize ();
1285 if (!rc)
1286 break;
1288 if (gpg_err_code (rc) != GPG_ERR_CANCELED &&
1289 gpg_err_code (rc) != GPG_ERR_EOF)
1290 fprintf (stderr, "ERR %i: %s\n", rc, gpg_strerror (rc));
1292 continue;
1294 else if (!*line)
1296 free (line);
1297 continue;
1300 #ifdef HAVE_READLINE_HISTORY
1301 add_history (line);
1302 #endif
1303 rc = parse_dotcommand (line, &result, &len, inq);
1304 free (line);
1305 if (rc)
1307 char *tmp = NULL;
1309 if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
1310 (void) pwmd_command (pwm, &tmp, NULL, NULL, NULL,
1311 "GETINFO last_error");
1313 show_error (pwm, rc, tmp);
1314 pwmd_free (tmp);
1316 else if (result && len)
1317 printf ("%s%s", result, result[len - 1] != '\n' ? "\n" : "");
1319 pwmd_free (result);
1322 free_inquire (inq);
1323 return rc;
1325 #endif
1327 static gpg_error_t
1328 finalize ()
1330 gpg_error_t rc = 0;
1331 #ifdef HAVE_LIBREADLINE
1332 int quit = 0;
1334 if (interactive)
1336 int finished = 0;
1338 fprintf (stderr, "\n");
1342 char *p, buf[16];
1344 fprintf (stderr,
1346 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1347 p = fgets (buf, sizeof (buf), stdin);
1349 if (feof (stdin))
1351 clearerr (stdin);
1352 return GPG_ERR_EOF;
1355 switch (*p)
1357 case 'h':
1358 print_help ();
1359 break;
1360 case 'c':
1361 return GPG_ERR_CANCELED;
1362 case 'Q':
1363 return 0;
1364 case 'f':
1365 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1366 "CLEARCACHE %s", filename);
1367 if (rc)
1368 return rc;
1370 interactive_hook ();
1371 break;
1372 case 'S':
1373 quit = 1;
1374 case 's':
1375 save = 1;
1376 finished = 1;
1377 break;
1378 default:
1379 break;
1382 while (!finished);
1384 #endif
1386 if (save && !filename)
1388 fprintf (stderr,
1390 ("No filename was specified on the command line. Aborting.\n"));
1391 return GPG_ERR_CANCELED;
1394 if (save && filename)
1396 char *args =
1397 pwmd_strdup_printf ("%s%s %s%s %s",
1398 keyid ? "--keyid=" : "",
1399 keyid ? keyid : "",
1400 sign_keyid ? "--sign-keyid=" : "",
1401 sign_keyid ? sign_keyid : "",
1402 keyparams ? "--inquire-keyparam" : "");
1404 #ifdef HAVE_LIBREADLINE
1405 if (!quiet || interactive)
1407 #else
1408 if (!quiet)
1410 #endif
1411 fprintf (stderr, "\n");
1412 fprintf (stderr, N_("Saving changes ...\n"));
1415 rc = save_command (args);
1416 pwmd_free (args);
1419 #ifdef HAVE_LIBREADLINE
1420 if (interactive)
1421 return rc ? rc : quit ? 0 : GPG_ERR_CANCELED;
1422 #endif
1424 return rc;
1428 main (int argc, char *argv[])
1430 int connected = 0;
1431 gpg_error_t rc;
1432 int opt;
1433 char command[ASSUAN_LINELENGTH], *p = NULL;
1434 char *result = NULL;
1435 size_t len = 0;
1436 char *pinentry_path = NULL;
1437 char *display = NULL, *tty = NULL, *ttytype = NULL;
1438 char *lcctype = NULL, *lcmessages = NULL;
1439 int outfd = STDOUT_FILENO;
1440 FILE *outfp = stdout;
1441 FILE *inquirefp = stdin;
1442 int show_status = 1;
1443 char *clientname = "pwmc";
1444 char *inquire = NULL;
1445 char *inquire_line = NULL;
1446 int timeout = 0;
1447 #ifdef WITH_SSH
1448 int use_ssh_agent = 1;
1449 char *knownhosts = NULL;
1450 char *identity = NULL;
1451 #endif
1452 #ifdef WITH_GNUTLS
1453 char *cacert = NULL;
1454 char *clientcert = NULL;
1455 char *clientkey = NULL;
1456 char *prio = NULL;
1457 int tls_verify = 0;
1458 char *tls_fingerprint = NULL;
1459 #endif
1460 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1461 pwmd_socket_t socktype;
1462 long socket_timeout = 300;
1463 int connect_timeout = 120;
1464 #endif
1465 int lock_on_open = 1;
1466 long lock_timeout = 50;
1467 char *url = NULL;
1468 /* The order is important. */
1469 enum
1471 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1472 OPT_SOCKET_TIMEOUT, OPT_CONNECT_TIMEOUT,
1473 #endif
1474 #ifdef WITH_SSH
1475 OPT_USE_SSH_AGENT, OPT_IDENTITY, OPT_KNOWNHOSTS,
1476 #endif
1477 #ifdef WITH_GNUTLS
1478 OPT_CACERT, OPT_CLIENTCERT, OPT_CLIENTKEY, OPT_PRIORITY, OPT_VERIFY,
1479 OPT_SERVER_FP,
1480 #endif
1481 OPT_URL, OPT_LOCAL, OPT_TTYNAME, OPT_TTYTYPE,
1482 OPT_DISPLAY, OPT_LC_CTYPE, OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES,
1483 OPT_PINENTRY, OPT_KEYFILE, OPT_NEW_KEYFILE, OPT_NOLOCK,
1484 OPT_LOCK_TIMEOUT, OPT_SAVE, OPT_OUTPUT_FD, OPT_INQUIRE,
1485 OPT_INQUIRE_FD, OPT_INQUIRE_FILE, OPT_INQUIRE_LINE, OPT_NO_STATUS,
1486 OPT_statusfd, OPT_NAME, OPT_VERSION, OPT_HELP, OPT_KEYID, OPT_SIGN_KEYID,
1487 OPT_KEYPARAMS, OPT_NO_PINENTRY, OPT_QUIET,
1488 #ifdef HAVE_LIBREADLINE
1489 OPT_INTERACTIVE,
1490 #endif
1492 const struct option long_opts[] = {
1493 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1494 {"socket-timeout", 1, 0, 0},
1495 {"connect-timeout", 1, 0, 0},
1496 #endif
1498 #ifdef WITH_SSH
1499 {"no-ssh-agent", 0, 0, 0},
1500 {"identity", 1, 0, 'i'},
1501 {"knownhosts", 1, 0, 'k'},
1502 #endif
1503 #ifdef WITH_GNUTLS
1504 {"ca-cert", 1, 0, 0},
1505 {"client-cert", 1, 0, 0},
1506 {"client-key", 1, 0, 0},
1507 {"tls-priority", 1, 0, 0},
1508 {"tls-verify", 0, 0, 0},
1509 {"tls-fingerprint", 1, 0, 0},
1510 #endif
1511 {"url", 1, 0, 0},
1512 {"local-pinentry", 0, 0},
1513 {"ttyname", 1, 0, 'y'},
1514 {"ttytype", 1, 0, 't'},
1515 {"display", 1, 0, 'd'},
1516 {"lc-ctype", 1, 0, 0},
1517 {"lc-messages", 1, 0, 0},
1518 {"timeout", 1, 0, 0},
1519 {"tries", 1, 0, 0},
1520 {"pinentry", 1, 0, 0},
1521 {"key-file", 1, 0, 0},
1522 {"new-key-file", 1, 0, 0},
1523 {"no-lock", 0, 0, 0},
1524 {"lock-timeout", 1, 0, 0},
1525 {"save", 0, 0, 'S'},
1526 {"output-fd", 1, 0, 0},
1527 {"inquire", 1, 0, 0},
1528 {"inquire-fd", 1, 0, 0},
1529 {"inquire-file", 1, 0, 0},
1530 {"inquire-line", 1, 0, 'L'},
1531 {"no-status", 0, 0, 0},
1532 {"status-fd", 1, 0, 0},
1533 {"name", 1, 0, 'n'},
1534 {"version", 0, 0, 0},
1535 {"help", 0, 0, 0},
1536 {"keyid", 1, 0, 0},
1537 {"sign-keyid", 1, 0, 0},
1538 {"key-params", 1, 0, 0},
1539 {"no-pinentry", 0, 0, 0},
1540 {"quiet", 0, 0, 0},
1541 #ifdef HAVE_LIBREADLINE
1542 {"interactive", 0, 0},
1543 #endif
1544 {0, 0, 0, 0}
1546 #ifdef WITH_SSH
1547 const char *optstring = "L:y:t:d:P:I:Sn:i:k:";
1548 #else
1549 const char *optstring = "L:y:t:d:P:I:Sn:";
1550 #endif
1551 int opt_index = 0;
1553 #ifdef ENABLE_NLS
1554 setlocale (LC_ALL, "");
1555 bindtextdomain ("libpwmd", LOCALEDIR);
1556 #endif
1558 tries = DEFAULT_PIN_TRIES;
1559 inquirefd = STDIN_FILENO;
1560 statusfd = STDERR_FILENO;
1561 statusfp = fdopen (statusfd, "w");
1563 while ((opt =
1564 getopt_long (argc, argv, optstring, long_opts, &opt_index)) != -1)
1566 switch (opt)
1568 /* Handle long options without a short option part. */
1569 case 0:
1570 switch (opt_index)
1572 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1573 case OPT_SOCKET_TIMEOUT:
1574 socket_timeout = strtol (optarg, &p, 10);
1575 break;
1576 case OPT_CONNECT_TIMEOUT:
1577 connect_timeout = strtol (optarg, &p, 10);
1578 break;
1579 #endif
1580 #ifdef WITH_SSH
1581 case OPT_USE_SSH_AGENT:
1582 use_ssh_agent = 0;
1583 break;
1584 #endif
1585 #ifdef WITH_GNUTLS
1586 case OPT_CACERT:
1587 cacert = optarg;
1588 break;
1589 case OPT_CLIENTCERT:
1590 clientcert = optarg;
1591 break;
1592 case OPT_CLIENTKEY:
1593 clientkey = optarg;
1594 break;
1595 case OPT_PRIORITY:
1596 prio = optarg;
1597 break;
1598 case OPT_VERIFY:
1599 tls_verify = 1;
1600 break;
1601 case OPT_SERVER_FP:
1602 tls_fingerprint = optarg;
1603 break;
1604 #endif
1605 case OPT_KEYPARAMS:
1606 keyparams = optarg;
1607 break;
1608 case OPT_KEYFILE:
1609 keyfile = pwmd_strdup (optarg);
1610 break;
1611 case OPT_NEW_KEYFILE:
1612 new_keyfile = pwmd_strdup (optarg);
1613 break;
1614 case OPT_NOLOCK:
1615 lock_on_open = 0;
1616 break;
1617 case OPT_LOCK_TIMEOUT:
1618 lock_timeout = strtol (optarg, &p, 10);
1619 break;
1620 case OPT_URL:
1621 url = optarg;
1622 break;
1623 case OPT_LOCAL:
1624 local_pin = 1;
1625 break;
1626 case OPT_LC_CTYPE:
1627 lcctype = pwmd_strdup (optarg);
1628 break;
1629 case OPT_LC_MESSAGES:
1630 lcmessages = pwmd_strdup (optarg);
1631 break;
1632 case OPT_TIMEOUT:
1633 timeout = strtol (optarg, &p, 10);
1634 break;
1635 case OPT_TRIES:
1636 tries = strtol (optarg, &p, 10);
1637 break;
1638 case OPT_INQUIRE:
1639 inquire = escape (optarg);
1640 break;
1641 case OPT_INQUIRE_FD:
1642 inquirefd = strtol (optarg, &p, 10);
1643 if (!p)
1645 inquirefp = fdopen (inquirefd, "r");
1646 if (!inquirefp)
1647 err (EXIT_FAILURE, "%i", inquirefd);
1649 break;
1650 case OPT_INQUIRE_FILE:
1651 inquirefd = open (optarg, O_RDONLY);
1652 if (inquirefd == -1)
1653 err (EXIT_FAILURE, "%s", optarg);
1654 inquirefp = fdopen (inquirefd, "r");
1655 break;
1656 case OPT_OUTPUT_FD:
1657 outfd = strtol (optarg, &p, 10);
1658 if (!p || !*p)
1660 outfp = fdopen (outfd, "w");
1661 if (!outfp)
1662 err (EXIT_FAILURE, "%i", outfd);
1664 break;
1665 case OPT_NO_STATUS:
1666 show_status = 0;
1667 break;
1668 case OPT_statusfd:
1669 statusfd = strtol (optarg, &p, 10);
1670 if (!p || !*p)
1672 statusfp = fdopen (statusfd, "w");
1673 if (!statusfp)
1674 err (EXIT_FAILURE, "%i", statusfd);
1676 break;
1677 case OPT_VERSION:
1678 printf ("%s (pwmc)\n\n"
1679 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014\n"
1680 "%s\n"
1681 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1682 "Compile-time features:\n"
1683 #ifdef HAVE_LIBREADLINE
1684 "+INTERACTIVE "
1685 #else
1686 "-INTERACTIVE "
1687 #endif
1688 #ifdef WITH_SSH
1689 "+SSH "
1690 #else
1691 "-SSH "
1692 #endif
1693 #ifdef WITH_GNUTLS
1694 "+GNUTLS "
1695 #else
1696 "-GNUTLS "
1697 #endif
1698 #ifdef WITH_PINENTRY
1699 "+PINENTRY "
1700 #else
1701 "-PINENTRY "
1702 #endif
1703 #ifdef WITH_QUALITY
1704 "+CRACK "
1705 #else
1706 "-CRACK "
1707 #endif
1708 #ifdef MEM_DEBUG
1709 "+MEM_DEBUG "
1710 #else
1711 "-MEM_DEBUG "
1712 #endif
1713 "\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1714 exit (EXIT_SUCCESS);
1715 case OPT_PINENTRY:
1716 pinentry_path = optarg;
1717 break;
1718 case OPT_HELP:
1719 usage (argv[0], EXIT_SUCCESS);
1720 case OPT_KEYID:
1721 keyid = optarg;
1722 break;
1723 case OPT_SIGN_KEYID:
1724 sign_keyid = optarg;
1725 break;
1726 case OPT_QUIET:
1727 quiet = 1;
1728 show_status = 0;
1729 break;
1730 case OPT_NO_PINENTRY:
1731 no_pinentry = 1;
1732 break;
1733 #ifdef HAVE_LIBREADLINE
1734 case OPT_INTERACTIVE:
1735 interactive = 1;
1736 break;
1737 #endif
1738 default:
1739 usage (argv[0], EXIT_FAILURE);
1742 if (p && *p)
1744 fprintf (stderr, N_("%s: invalid argument for option '--%s'\n"),
1745 argv[0], long_opts[opt_index].name);
1746 usage (argv[0], EXIT_FAILURE);
1749 break;
1750 #ifdef WITH_SSH
1751 case 'i':
1752 identity = optarg;
1753 break;
1754 case 'k':
1755 knownhosts = optarg;
1756 break;
1757 #endif
1758 case 'L':
1759 inquire_line = optarg;
1760 break;
1761 case 'y':
1762 tty = optarg;
1763 break;
1764 case 't':
1765 ttytype = optarg;
1766 break;
1767 case 'd':
1768 display = optarg;
1769 break;
1770 case 'S':
1771 save = 1;
1772 break;
1773 case 'n':
1774 clientname = optarg;
1775 break;
1776 default:
1777 usage (argv[0], EXIT_FAILURE);
1781 #ifdef HAVE_LIBREADLINE
1782 if (interactive && !isatty (STDIN_FILENO))
1783 usage (argv[0], EXIT_FAILURE);
1784 else if (isatty (STDIN_FILENO) && !inquire && !inquire_line)
1785 interactive = 1;
1786 #endif
1788 filename = argv[optind];
1789 #ifdef WITH_GNUTLS
1790 gnutls_global_set_mem_functions (pwmd_malloc, pwmd_malloc, NULL,
1791 pwmd_realloc, pwmd_free);
1792 #endif
1793 pwmd_init ();
1794 rc = pwmd_new (clientname, &pwm);
1795 if (rc)
1796 goto done;
1798 pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
1799 if (!quiet)
1800 fprintf (stderr, N_("Connecting ...\n"));
1802 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1803 socktype = is_remote_url (url);
1804 if (socktype != PWMD_SOCKET_LOCAL)
1806 local_pin = 1;
1807 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1808 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, connect_timeout);
1809 if (rc)
1810 goto done;
1811 #endif
1813 if (socktype == PWMD_SOCKET_SSH)
1815 #ifdef WITH_SSH
1816 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_CB, knownhost_cb);
1817 if (rc)
1818 goto done;
1820 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_DATA, clientname);
1821 if (rc)
1822 goto done;
1824 if (!getenv ("SSH_AUTH_SOCK") || identity)
1825 use_ssh_agent = 0;
1827 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_AGENT, use_ssh_agent);
1828 if (rc)
1829 goto done;
1831 rc = pwmd_connect (pwm, url, identity, knownhosts);
1832 #endif
1834 #ifdef WITH_GNUTLS
1835 else
1837 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_VERIFY, tls_verify);
1838 if (rc)
1839 goto done;
1841 rc = pwmd_connect (pwm, url, clientcert, clientkey, cacert, prio,
1842 tls_fingerprint);
1844 #endif
1846 else
1847 rc = pwmd_connect (pwm, url);
1848 #else
1849 rc = pwmd_connect (pwm, url);
1850 #endif
1851 if (rc)
1852 goto done;
1854 if (!quiet)
1855 fprintf (stderr, N_("Connected.\n"));
1857 connected = 1;
1858 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1859 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, socket_timeout);
1860 if (rc)
1861 goto done;
1862 #endif
1864 if (lock_timeout)
1866 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1867 "OPTION LOCK-TIMEOUT=%li", lock_timeout);
1868 if (rc)
1869 goto done;
1872 if (lock_on_open)
1874 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCK_ON_OPEN, 1);
1875 if (rc)
1876 goto done;
1879 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, NULL, NULL);
1880 if (rc)
1881 goto done;
1883 if (timeout > 0)
1885 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
1886 if (rc)
1887 goto done;
1890 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1891 if (rc)
1892 goto done;
1894 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY,
1895 (local_pin || keyfile || new_keyfile));
1896 if (rc)
1897 goto done;
1899 if (pinentry_path)
1901 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
1902 if (rc)
1903 goto done;
1906 if (display)
1908 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
1909 if (rc)
1910 goto done;
1913 if (tty)
1915 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, tty);
1916 if (rc)
1917 goto done;
1920 if (ttytype)
1922 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
1923 if (rc)
1924 goto done;
1927 if (lcctype)
1929 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
1930 if (rc)
1931 goto done;
1934 if (lcmessages)
1936 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES, lcmessages);
1937 if (rc)
1938 goto done;
1941 if (show_status)
1943 rc = pwmd_setopt (pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
1944 if (rc)
1945 goto done;
1948 if (filename)
1950 rc = open_command (filename);
1951 if (rc)
1952 goto done;
1955 #ifdef HAVE_LIBREADLINE
1956 if (interactive)
1958 rc = do_interactive ();
1959 result = NULL;
1960 goto do_exit;
1962 #endif
1964 if (inquire)
1966 struct inquire_s *inq = NULL;
1968 rc = set_inquire (inquirefd, inquire_line, &inq);
1969 if (!rc)
1970 rc = pwmd_command (pwm, &result, &len, inquire_cb, inq, inquire);
1972 free_inquire (inq);
1973 goto done;
1976 fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK);
1977 ssize_t n;
1979 for (;;)
1981 rc = process_cmd ();
1983 if (rc)
1984 goto done;
1986 n = read (STDIN_FILENO, command, sizeof (command));
1987 if (n == -1)
1989 if (errno == EAGAIN)
1991 usleep (100000);
1992 continue;
1995 rc = gpg_error_from_errno (errno);
1996 goto done;
1998 else if (!n)
1999 goto done;
2001 p = command;
2002 command[n] = 0;
2003 break;
2006 if (!p || !*p || !strcasecmp (p, "BYE"))
2007 goto done;
2010 struct inquire_s *inq = NULL;
2011 rc = set_inquire (inquirefd, inquire_line, &inq);
2012 if (!rc)
2014 rc = parse_dotcommand (command, &result, &len, inq);
2015 free_inquire (inq);
2018 if (rc)
2019 goto done;
2021 done:
2022 if (result)
2024 fwrite (result, 1, result[len - 1] == 0 ? len - 1 : len, outfp);
2025 fflush (outfp);
2026 pwmd_free (result);
2029 result = NULL;
2030 if (!rc)
2031 rc = finalize ();
2032 else if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
2033 (void) pwmd_command (pwm, &result, NULL, NULL, NULL,
2034 "GETINFO last_error");
2036 #ifdef HAVE_LIBREADLINE
2037 do_exit:
2038 #endif
2039 memset (command, 0, sizeof (command));
2041 if (rc && !quiet)
2042 show_error (pwm, rc, result);
2044 pwmd_close (pwm);
2045 pwmd_free (keyfile);
2046 pwmd_free (new_keyfile);
2047 pwmd_deinit ();
2048 pwmd_free (result);
2049 if (connected && !quiet)
2050 fprintf (stderr, N_("Connection closed.\n"));
2052 exit (rc ? EXIT_FAILURE : EXIT_SUCCESS);