Fix Coverity issue #101137.
[libpwmd.git] / src / pwmc.c
blobed016cc223c8148d4130459616cbef3d32488150
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;
926 char filebuf[ASSUAN_LINELENGTH];
928 if (p && *p && *++p)
930 filename = parse_arg (p, filebuf, sizeof (filebuf));
931 if (filename && *filename)
933 p += strlen (filename) + 1;
935 while (*p && isspace (*p))
936 p++;
938 if (*p)
939 rc = 0;
943 if (rc)
945 fprintf (stderr, N_("Usage: .redir <filename> <command> [args]\n"));
946 return rc;
949 fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
950 if (fd == -1)
951 return gpg_error_from_syserror ();
953 #ifdef HAVE_LIBREADLINE
954 rc = set_inquire (interactive ? STDIN_FILENO : inquirefd, NULL, &inq);
955 #else
956 rc = set_inquire (inquirefd, NULL, &inq);
957 #endif
958 if (rc)
960 close (fd);
961 return rc;
964 rc = parse_dotcommand (p, &result, &len, inq);
965 if (!rc && result && len--)
966 { // null byte which is always appended
967 if (write (fd, result, len) != len)
968 rc = GPG_ERR_TOO_SHORT;
969 pwmd_free (result);
972 free_inquire (inq);
973 close (fd);
974 return rc;
977 static gpg_error_t
978 help_command (const char *line)
980 fprintf (stderr,
981 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
982 " .redir <filename> <command>\n"
983 " redirect the output of a command to the specified file\n"
984 "\n"
985 " .open <filename>\n"
986 " open the specified filename losing any changes to the current one\n"
987 "\n"
988 " .read [--prefix <string>] <filename> <command> [args]\n"
989 " obtain data from the specified filename for an inquire command\n"
990 "\n"
991 " .set help | <name> [<value>]\n"
992 " set option <name> to <value>\n"
993 "\n"
994 " .save [args]\n"
995 " write changes of the file to disk\n"
996 "\n"
997 " .passwd [args]\n"
998 " change the passphrase of a data file\n"
999 "\n"
1000 " .help\n"
1001 " this help text\n"));
1002 return 0;
1005 static gpg_error_t
1006 open_command (const char *line)
1008 struct inquire_s *inq = NULL;
1009 const char *filename = line;
1010 gpg_error_t rc;
1012 while (filename && isspace (*filename))
1013 filename++;
1015 if (!filename || !*filename)
1017 fprintf (stderr, N_("Usage: .open <filename>\n"));
1018 return GPG_ERR_SYNTAX;
1021 #ifdef HAVE_LIBREADLINE
1022 if (interactive || !quiet)
1023 #else
1024 if (!quiet)
1025 #endif
1026 fprintf (stderr, N_("Opening data file \"%s\" ...\n"), filename);
1028 #ifdef HAVE_LIBREADLINE
1029 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1030 #else
1031 rc = set_inquire (-1, NULL, &inq);
1032 #endif
1033 if (rc)
1034 return rc;
1036 if (keyfile)
1037 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1038 else
1039 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1041 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1042 rc = pwmd_open (pwm, filename, inquire_cb, inq);
1043 free_inquire (inq);
1044 return rc;
1047 static gpg_error_t
1048 set_command (const char *line)
1050 gpg_error_t rc = 0;
1051 char name[256] = { 0 };
1052 char value[512] = { 0 };
1053 char *namep;
1054 char *valuep;
1055 const char *p = line;
1057 while (p && *p && isspace (*p))
1058 p++;
1060 namep = parse_arg (p, name, sizeof (name));
1061 if (!namep || !*namep)
1063 fprintf (stderr, N_("Usage: .set help | <name> [<value>]\n"));
1064 return GPG_ERR_SYNTAX;
1067 p += strlen (namep);
1068 while (p && *p && isspace (*p))
1069 p++;
1071 valuep = parse_arg (p, value, sizeof (value));
1073 if (!strcmp (name, "keyfile") || !strcmp (name, "new-keyfile"))
1075 int is_newkeyfile = 1;
1077 if (!strcmp (name, "keyfile"))
1078 is_newkeyfile = 0;
1080 if (is_newkeyfile)
1082 pwmd_free (new_keyfile);
1083 new_keyfile = NULL;
1085 else
1087 pwmd_free (keyfile);
1088 keyfile = NULL;
1091 p += strlen (valuep);
1092 while (p && *p && isspace (*p))
1093 p++;
1095 valuep = (char *) p;
1096 if (!rc && *valuep)
1098 if (is_newkeyfile)
1099 new_keyfile = pwmd_strdup (value);
1100 else
1101 keyfile = pwmd_strdup (value);
1103 if (!rc)
1105 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 1);
1106 if (!rc)
1107 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1110 else if (!local_pin && !no_pinentry)
1112 pwmd_socket_t t;
1114 pwmd_socket_type (pwm, &t);
1115 if (t == PWMD_SOCKET_LOCAL)
1117 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 0);
1118 if (!rc)
1119 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1123 else if (!strcmp(name, "pinentry-timeout"))
1125 char *e = NULL;
1126 int n = strtol(valuep, &e, 10);
1128 if (e && *e)
1129 return gpg_error (GPG_ERR_INV_VALUE);
1131 if (!*valuep)
1132 n = DEFAULT_PIN_TIMEOUT;
1134 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, n);
1136 else if (!strcmp (name, "help"))
1138 fprintf (stderr,
1140 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1141 "delimited. When no value is specified the option is unset.\n\n"
1142 "keyfile <datafile> [<filename>]\n"
1143 " set or unset the keyfile to be used when a passphrase is required (*)\n"
1144 "\n"
1145 "new-keyfile <datafile> [<filename>]\n"
1146 " set or unset the keyfile to be used when a new passphrase is required (*)\n"
1147 "\n"
1148 "pinentry-timeout <seconds>\n"
1149 " the amount of seconds before pinentry gives up waiting for input\n"
1150 "\n"
1151 "* = the next protocol command will unset this value\n"
1154 else
1155 rc = GPG_ERR_UNKNOWN_OPTION;
1157 return rc;
1160 static gpg_error_t
1161 save_command (const char *line)
1163 struct inquire_s *inq = NULL;
1164 gpg_error_t rc;
1166 #ifdef HAVE_LIBREADLINE
1167 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1168 #else
1169 rc = set_inquire (-1, NULL, &inq);
1170 #endif
1171 if (rc)
1172 return rc;
1174 if (new_keyfile || keyfile)
1175 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1177 rc = pwmd_save (pwm, line, inquire_cb, inq);
1178 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1179 free_inquire (inq);
1180 return rc;
1183 static gpg_error_t
1184 do_save_passwd_command (const char *line, int save)
1186 struct inquire_s *inq = NULL;
1187 gpg_error_t rc;
1189 #ifdef HAVE_LIBREADLINE
1190 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1191 #else
1192 rc = set_inquire (-1, NULL, &inq);
1193 #endif
1194 if (rc)
1195 return rc;
1197 if (new_keyfile || keyfile)
1198 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1200 if (save)
1201 rc = pwmd_save (pwm, line, inquire_cb, inq);
1202 else
1203 rc = pwmd_passwd (pwm, line, inquire_cb, inq);
1205 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1206 free_inquire (inq);
1207 return rc;
1210 static gpg_error_t
1211 parse_dotcommand (const char *line, char **result,
1212 size_t * len, struct inquire_s *inq)
1214 const char *p = line;
1215 gpg_error_t rc = 0;
1217 if (!strncmp (p, ".read", 5))
1218 rc = read_command (p + 5, result, len);
1219 else if (!strncmp (p, ".redir", 6))
1220 rc = redir_command (p + 6);
1221 else if (!strncmp (p, ".help", 5))
1222 rc = help_command (p + 5);
1223 else if (!strncmp (p, ".open", 5))
1224 rc = open_command (p + 5);
1225 else if (!strncmp (p, ".set", 4))
1226 rc = set_command (p + 4);
1227 else if (!strncmp (p, ".save", 5))
1228 rc = do_save_passwd_command (p + 5, 1);
1229 else if (!strncmp (p, ".passwd", 7))
1230 rc = do_save_passwd_command (p + 7, 0);
1231 else
1233 rc = pwmd_command (pwm, result, len, inquire_cb, inq, "%s", line);
1234 #ifdef HAVE_LIBREADLINE
1235 if (interactive)
1237 #endif
1238 pwmd_free (keyfile);
1239 pwmd_free (new_keyfile);
1240 keyfile = new_keyfile = NULL;
1241 #ifdef HAVE_LIBREADLINE
1243 #endif
1246 return FINISH (rc);
1249 #ifdef HAVE_LIBREADLINE
1250 static gpg_error_t
1251 do_interactive ()
1253 gpg_error_t rc;
1254 struct inquire_s *inq = NULL;
1256 rl_initialize ();
1257 rc = process_cmd ();
1258 if (rc)
1259 return rc;
1261 rc = set_inquire (STDIN_FILENO, NULL, &inq);
1262 if (rc)
1263 return rc;
1265 fprintf (stderr,
1266 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1267 print_help ();
1268 rl_event_hook = &interactive_hook;
1269 rl_set_keyboard_input_timeout (100000);
1271 for (;;)
1273 char *line;
1274 char *result = NULL;
1275 size_t len;
1277 rc = 0;
1278 line = readline ("pwm> ");
1279 if (interactive_error)
1281 free (line);
1282 rc = interactive_error;
1283 break;
1286 if (!line)
1288 rc = finalize ();
1289 if (!rc)
1290 break;
1292 if (gpg_err_code (rc) != GPG_ERR_CANCELED &&
1293 gpg_err_code (rc) != GPG_ERR_EOF)
1294 fprintf (stderr, "ERR %i: %s\n", rc, gpg_strerror (rc));
1296 continue;
1298 else if (!*line)
1300 free (line);
1301 continue;
1304 #ifdef HAVE_READLINE_HISTORY
1305 add_history (line);
1306 #endif
1307 rc = parse_dotcommand (line, &result, &len, inq);
1308 free (line);
1309 if (rc)
1311 char *tmp = NULL;
1313 if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
1314 (void) pwmd_command (pwm, &tmp, NULL, NULL, NULL,
1315 "GETINFO last_error");
1317 show_error (pwm, rc, tmp);
1318 pwmd_free (tmp);
1320 else if (result && len)
1321 printf ("%s%s", result, result[len - 1] != '\n' ? "\n" : "");
1323 pwmd_free (result);
1326 free_inquire (inq);
1327 return rc;
1329 #endif
1331 static gpg_error_t
1332 finalize ()
1334 gpg_error_t rc = 0;
1335 #ifdef HAVE_LIBREADLINE
1336 int quit = 0;
1338 if (interactive)
1340 int finished = 0;
1342 fprintf (stderr, "\n");
1346 char *p, buf[16];
1348 fprintf (stderr,
1350 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1351 p = fgets (buf, sizeof (buf), stdin);
1353 if (feof (stdin))
1355 clearerr (stdin);
1356 return GPG_ERR_EOF;
1359 switch (*p)
1361 case 'h':
1362 print_help ();
1363 break;
1364 case 'c':
1365 return GPG_ERR_CANCELED;
1366 case 'Q':
1367 return 0;
1368 case 'f':
1369 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1370 "CLEARCACHE %s", filename);
1371 if (rc)
1372 return rc;
1374 interactive_hook ();
1375 break;
1376 case 'S':
1377 quit = 1;
1378 case 's':
1379 save = 1;
1380 finished = 1;
1381 break;
1382 default:
1383 break;
1386 while (!finished);
1388 #endif
1390 if (save && !filename)
1392 fprintf (stderr,
1394 ("No filename was specified on the command line. Aborting.\n"));
1395 return GPG_ERR_CANCELED;
1398 if (save && filename)
1400 char *args =
1401 pwmd_strdup_printf ("%s%s %s%s %s",
1402 keyid ? "--keyid=" : "",
1403 keyid ? keyid : "",
1404 sign_keyid ? "--sign-keyid=" : "",
1405 sign_keyid ? sign_keyid : "",
1406 keyparams ? "--inquire-keyparam" : "");
1408 #ifdef HAVE_LIBREADLINE
1409 if (!quiet || interactive)
1411 #else
1412 if (!quiet)
1414 #endif
1415 fprintf (stderr, "\n");
1416 fprintf (stderr, N_("Saving changes ...\n"));
1419 rc = save_command (args);
1420 pwmd_free (args);
1423 #ifdef HAVE_LIBREADLINE
1424 if (interactive)
1425 return rc ? rc : quit ? 0 : GPG_ERR_CANCELED;
1426 #endif
1428 return rc;
1431 static void
1432 parse_status_ignore (char *str)
1434 size_t n = 0;
1435 char **p, *s;
1437 for (p = status_ignore; p && *p; p++)
1438 pwmd_free (*p);
1440 pwmd_free (status_ignore);
1441 status_ignore = NULL;
1442 if (!str || !*str)
1443 return;
1445 while ((s = strsep (&str, ",")))
1447 p = pwmd_realloc (status_ignore, (n + 2) * sizeof (char **));
1448 p[n++] = pwmd_strdup (s);
1449 p[n] = NULL;
1450 status_ignore = p;
1455 main (int argc, char *argv[])
1457 int connected = 0;
1458 gpg_error_t rc;
1459 int opt;
1460 char command[ASSUAN_LINELENGTH], *p = NULL;
1461 char *result = NULL;
1462 size_t len = 0;
1463 char *pinentry_path = NULL;
1464 char *display = NULL, *tty = NULL, *ttytype = NULL;
1465 char *lcctype = NULL, *lcmessages = NULL;
1466 int outfd = STDOUT_FILENO;
1467 FILE *outfp = stdout;
1468 FILE *inquirefp = stdin;
1469 int show_status = 1;
1470 char *clientname = "pwmc";
1471 char *inquire = NULL;
1472 char *inquire_line = NULL;
1473 int timeout = 0;
1474 #ifdef WITH_SSH
1475 int use_ssh_agent = 1;
1476 char *knownhosts = NULL;
1477 char *identity = NULL;
1478 #endif
1479 #ifdef WITH_GNUTLS
1480 char *cacert = NULL;
1481 char *clientcert = NULL;
1482 char *clientkey = NULL;
1483 char *prio = NULL;
1484 int tls_verify = 0;
1485 char *tls_fingerprint = NULL;
1486 #endif
1487 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1488 pwmd_socket_t socktype;
1489 long socket_timeout = 300;
1490 int connect_timeout = 120;
1491 #endif
1492 int lock_on_open = 1;
1493 long lock_timeout = 50;
1494 char *url = NULL;
1495 char *tmp = NULL;
1496 /* The order is important. */
1497 enum
1499 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1500 OPT_SOCKET_TIMEOUT, OPT_CONNECT_TIMEOUT,
1501 #endif
1502 #ifdef WITH_SSH
1503 OPT_USE_SSH_AGENT, OPT_IDENTITY, OPT_KNOWNHOSTS,
1504 #endif
1505 #ifdef WITH_GNUTLS
1506 OPT_CACERT, OPT_CLIENTCERT, OPT_CLIENTKEY, OPT_PRIORITY, OPT_VERIFY,
1507 OPT_SERVER_FP,
1508 #endif
1509 OPT_URL, OPT_LOCAL, OPT_TTYNAME, OPT_TTYTYPE,
1510 OPT_DISPLAY, OPT_LC_CTYPE, OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES,
1511 OPT_PINENTRY, OPT_KEYFILE, OPT_NEW_KEYFILE, OPT_NOLOCK,
1512 OPT_LOCK_TIMEOUT, OPT_SAVE, OPT_OUTPUT_FD, OPT_INQUIRE,
1513 OPT_INQUIRE_FD, OPT_INQUIRE_FILE, OPT_INQUIRE_LINE, OPT_NO_STATUS,
1514 OPT_STATUS_IGNORE,
1515 OPT_STATUSFD, OPT_NAME, OPT_VERSION, OPT_HELP, OPT_KEYID, OPT_SIGN_KEYID,
1516 OPT_KEYPARAMS, OPT_NO_PINENTRY, OPT_QUIET,
1517 #ifdef HAVE_LIBREADLINE
1518 OPT_INTERACTIVE,
1519 #endif
1521 const struct option long_opts[] = {
1522 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1523 {"socket-timeout", 1, 0, 0},
1524 {"connect-timeout", 1, 0, 0},
1525 #endif
1527 #ifdef WITH_SSH
1528 {"no-ssh-agent", 0, 0, 0},
1529 {"identity", 1, 0, 'i'},
1530 {"knownhosts", 1, 0, 'k'},
1531 #endif
1532 #ifdef WITH_GNUTLS
1533 {"ca-cert", 1, 0, 0},
1534 {"client-cert", 1, 0, 0},
1535 {"client-key", 1, 0, 0},
1536 {"tls-priority", 1, 0, 0},
1537 {"tls-verify", 0, 0, 0},
1538 {"tls-fingerprint", 1, 0, 0},
1539 #endif
1540 {"url", 1, 0, 0},
1541 {"local-pinentry", 0, 0},
1542 {"ttyname", 1, 0, 'y'},
1543 {"ttytype", 1, 0, 't'},
1544 {"display", 1, 0, 'd'},
1545 {"lc-ctype", 1, 0, 0},
1546 {"lc-messages", 1, 0, 0},
1547 {"timeout", 1, 0, 0},
1548 {"tries", 1, 0, 0},
1549 {"pinentry", 1, 0, 0},
1550 {"key-file", 1, 0, 0},
1551 {"new-key-file", 1, 0, 0},
1552 {"no-lock", 0, 0, 0},
1553 {"lock-timeout", 1, 0, 0},
1554 {"save", 0, 0, 'S'},
1555 {"output-fd", 1, 0, 0},
1556 {"inquire", 1, 0, 0},
1557 {"inquire-fd", 1, 0, 0},
1558 {"inquire-file", 1, 0, 0},
1559 {"inquire-line", 1, 0, 'L'},
1560 {"no-status", 0, 0, 0},
1561 {"status-ignore", 1, 0, 0},
1562 {"status-fd", 1, 0, 0},
1563 {"name", 1, 0, 'n'},
1564 {"version", 0, 0, 0},
1565 {"help", 0, 0, 0},
1566 {"keyid", 1, 0, 0},
1567 {"sign-keyid", 1, 0, 0},
1568 {"key-params", 1, 0, 0},
1569 {"no-pinentry", 0, 0, 0},
1570 {"quiet", 0, 0, 0},
1571 #ifdef HAVE_LIBREADLINE
1572 {"interactive", 0, 0},
1573 #endif
1574 {0, 0, 0, 0}
1576 #ifdef WITH_SSH
1577 const char *optstring = "L:y:t:d:P:I:Sn:i:k:";
1578 #else
1579 const char *optstring = "L:y:t:d:P:I:Sn:";
1580 #endif
1581 int opt_index = 0;
1583 #ifdef ENABLE_NLS
1584 setlocale (LC_ALL, "");
1585 bindtextdomain ("libpwmd", LOCALEDIR);
1586 #endif
1588 tries = DEFAULT_PIN_TRIES;
1589 inquirefd = STDIN_FILENO;
1590 statusfd = STDERR_FILENO;
1591 statusfp = fdopen (statusfd, "w");
1592 tmp = pwmd_strdup (DEFAULT_STATUS_IGNORE);
1593 parse_status_ignore (tmp);
1594 pwmd_free (tmp);
1596 while ((opt =
1597 getopt_long (argc, argv, optstring, long_opts, &opt_index)) != -1)
1599 switch (opt)
1601 /* Handle long options without a short option part. */
1602 case 0:
1603 switch (opt_index)
1605 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1606 case OPT_SOCKET_TIMEOUT:
1607 socket_timeout = strtol (optarg, &p, 10);
1608 break;
1609 case OPT_CONNECT_TIMEOUT:
1610 connect_timeout = strtol (optarg, &p, 10);
1611 break;
1612 #endif
1613 #ifdef WITH_SSH
1614 case OPT_USE_SSH_AGENT:
1615 use_ssh_agent = 0;
1616 break;
1617 #endif
1618 #ifdef WITH_GNUTLS
1619 case OPT_CACERT:
1620 cacert = optarg;
1621 break;
1622 case OPT_CLIENTCERT:
1623 clientcert = optarg;
1624 break;
1625 case OPT_CLIENTKEY:
1626 clientkey = optarg;
1627 break;
1628 case OPT_PRIORITY:
1629 prio = optarg;
1630 break;
1631 case OPT_VERIFY:
1632 tls_verify = 1;
1633 break;
1634 case OPT_SERVER_FP:
1635 tls_fingerprint = optarg;
1636 break;
1637 #endif
1638 case OPT_KEYPARAMS:
1639 keyparams = optarg;
1640 break;
1641 case OPT_KEYFILE:
1642 keyfile = pwmd_strdup (optarg);
1643 break;
1644 case OPT_NEW_KEYFILE:
1645 new_keyfile = pwmd_strdup (optarg);
1646 break;
1647 case OPT_NOLOCK:
1648 lock_on_open = 0;
1649 break;
1650 case OPT_LOCK_TIMEOUT:
1651 lock_timeout = strtol (optarg, &p, 10);
1652 break;
1653 case OPT_URL:
1654 url = optarg;
1655 break;
1656 case OPT_LOCAL:
1657 local_pin = 1;
1658 break;
1659 case OPT_LC_CTYPE:
1660 lcctype = pwmd_strdup (optarg);
1661 break;
1662 case OPT_LC_MESSAGES:
1663 lcmessages = pwmd_strdup (optarg);
1664 break;
1665 case OPT_TIMEOUT:
1666 timeout = strtol (optarg, &p, 10);
1667 break;
1668 case OPT_TRIES:
1669 tries = strtol (optarg, &p, 10);
1670 break;
1671 case OPT_INQUIRE:
1672 inquire = escape (optarg);
1673 break;
1674 case OPT_INQUIRE_FD:
1675 inquirefd = strtol (optarg, &p, 10);
1676 if (!p)
1678 inquirefp = fdopen (inquirefd, "r");
1679 if (!inquirefp)
1680 err (EXIT_FAILURE, "%i", inquirefd);
1682 break;
1683 case OPT_INQUIRE_FILE:
1684 inquirefd = open (optarg, O_RDONLY);
1685 if (inquirefd == -1)
1686 err (EXIT_FAILURE, "%s", optarg);
1687 inquirefp = fdopen (inquirefd, "r");
1688 break;
1689 case OPT_OUTPUT_FD:
1690 outfd = strtol (optarg, &p, 10);
1691 if (!p || !*p)
1693 outfp = fdopen (outfd, "w");
1694 if (!outfp)
1695 err (EXIT_FAILURE, "%i", outfd);
1697 break;
1698 case OPT_NO_STATUS:
1699 show_status = 0;
1700 break;
1701 case OPT_STATUSFD:
1702 statusfd = strtol (optarg, &p, 10);
1703 if (!p || !*p)
1705 statusfp = fdopen (statusfd, "w");
1706 if (!statusfp)
1707 err (EXIT_FAILURE, "%i", statusfd);
1709 break;
1710 case OPT_STATUS_IGNORE:
1711 parse_status_ignore (optarg);
1712 break;
1713 case OPT_VERSION:
1714 printf ("%s (pwmc)\n\n"
1715 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015\n"
1716 "%s\n"
1717 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1718 "Compile-time features:\n"
1719 #ifdef HAVE_LIBREADLINE
1720 "+INTERACTIVE "
1721 #else
1722 "-INTERACTIVE "
1723 #endif
1724 #ifdef WITH_SSH
1725 "+SSH "
1726 #else
1727 "-SSH "
1728 #endif
1729 #ifdef WITH_GNUTLS
1730 "+GNUTLS "
1731 #else
1732 "-GNUTLS "
1733 #endif
1734 #ifdef WITH_PINENTRY
1735 "+PINENTRY "
1736 #else
1737 "-PINENTRY "
1738 #endif
1739 #ifdef WITH_QUALITY
1740 "+CRACK "
1741 #else
1742 "-CRACK "
1743 #endif
1744 #ifdef MEM_DEBUG
1745 "+MEM_DEBUG "
1746 #else
1747 "-MEM_DEBUG "
1748 #endif
1749 "\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1750 exit (EXIT_SUCCESS);
1751 case OPT_PINENTRY:
1752 pinentry_path = optarg;
1753 break;
1754 case OPT_HELP:
1755 usage (argv[0], EXIT_SUCCESS);
1756 case OPT_KEYID:
1757 keyid = optarg;
1758 break;
1759 case OPT_SIGN_KEYID:
1760 sign_keyid = optarg;
1761 break;
1762 case OPT_QUIET:
1763 quiet = 1;
1764 show_status = 0;
1765 break;
1766 case OPT_NO_PINENTRY:
1767 no_pinentry = 1;
1768 break;
1769 #ifdef HAVE_LIBREADLINE
1770 case OPT_INTERACTIVE:
1771 interactive = 1;
1772 break;
1773 #endif
1774 default:
1775 usage (argv[0], EXIT_FAILURE);
1778 if (p && *p)
1780 fprintf (stderr, N_("%s: invalid argument for option '--%s'\n"),
1781 argv[0], long_opts[opt_index].name);
1782 usage (argv[0], EXIT_FAILURE);
1785 break;
1786 #ifdef WITH_SSH
1787 case 'i':
1788 identity = optarg;
1789 break;
1790 case 'k':
1791 knownhosts = optarg;
1792 break;
1793 #endif
1794 case 'L':
1795 inquire_line = optarg;
1796 break;
1797 case 'y':
1798 tty = optarg;
1799 break;
1800 case 't':
1801 ttytype = optarg;
1802 break;
1803 case 'd':
1804 display = optarg;
1805 break;
1806 case 'S':
1807 save = 1;
1808 break;
1809 case 'n':
1810 clientname = optarg;
1811 break;
1812 default:
1813 usage (argv[0], EXIT_FAILURE);
1817 #ifdef HAVE_LIBREADLINE
1818 if (interactive && !isatty (STDIN_FILENO))
1819 usage (argv[0], EXIT_FAILURE);
1820 else if (isatty (STDIN_FILENO) && !inquire && !inquire_line)
1821 interactive = 1;
1822 #endif
1824 filename = argv[optind];
1825 #ifdef WITH_GNUTLS
1826 gnutls_global_set_mem_functions (pwmd_malloc, pwmd_malloc, NULL,
1827 pwmd_realloc, pwmd_free);
1828 #endif
1829 pwmd_init ();
1830 rc = pwmd_new (clientname, &pwm);
1831 if (rc)
1832 goto done;
1834 pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
1835 if (!quiet)
1836 fprintf (stderr, N_("Connecting ...\n"));
1838 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1839 socktype = is_remote_url (url);
1840 if (socktype != PWMD_SOCKET_LOCAL)
1842 local_pin = 1;
1843 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1844 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, connect_timeout);
1845 if (rc)
1846 goto done;
1847 #endif
1849 if (socktype == PWMD_SOCKET_SSH)
1851 #ifdef WITH_SSH
1852 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_CB, knownhost_cb);
1853 if (rc)
1854 goto done;
1856 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_DATA, clientname);
1857 if (rc)
1858 goto done;
1860 if (!getenv ("SSH_AUTH_SOCK") || identity)
1861 use_ssh_agent = 0;
1863 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_AGENT, use_ssh_agent);
1864 if (rc)
1865 goto done;
1867 rc = pwmd_connect (pwm, url, identity, knownhosts);
1868 #endif
1870 #ifdef WITH_GNUTLS
1871 else
1873 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_VERIFY, tls_verify);
1874 if (rc)
1875 goto done;
1877 rc = pwmd_connect (pwm, url, clientcert, clientkey, cacert, prio,
1878 tls_fingerprint);
1880 #endif
1882 else
1883 rc = pwmd_connect (pwm, url);
1884 #else
1885 rc = pwmd_connect (pwm, url);
1886 #endif
1887 if (rc)
1888 goto done;
1890 if (!quiet)
1891 fprintf (stderr, N_("Connected.\n"));
1893 connected = 1;
1894 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1895 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, socket_timeout);
1896 if (rc)
1897 goto done;
1898 #endif
1900 if (lock_timeout)
1902 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1903 "OPTION LOCK-TIMEOUT=%li", lock_timeout);
1904 if (rc)
1905 goto done;
1908 if (lock_on_open)
1910 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCK_ON_OPEN, 1);
1911 if (rc)
1912 goto done;
1915 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, NULL, NULL);
1916 if (rc)
1917 goto done;
1919 if (timeout > 0)
1921 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
1922 if (rc)
1923 goto done;
1926 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1927 if (rc)
1928 goto done;
1930 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY,
1931 (local_pin || keyfile || new_keyfile));
1932 if (rc)
1933 goto done;
1935 if (pinentry_path)
1937 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
1938 if (rc)
1939 goto done;
1942 if (display)
1944 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
1945 if (rc)
1946 goto done;
1949 if (tty)
1951 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, tty);
1952 if (rc)
1953 goto done;
1956 if (ttytype)
1958 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
1959 if (rc)
1960 goto done;
1963 if (lcctype)
1965 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
1966 if (rc)
1967 goto done;
1970 if (lcmessages)
1972 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES, lcmessages);
1973 if (rc)
1974 goto done;
1977 if (show_status)
1979 rc = pwmd_setopt (pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
1980 if (rc)
1981 goto done;
1984 if (filename)
1986 rc = open_command (filename);
1987 if (rc)
1988 goto done;
1991 #ifdef HAVE_LIBREADLINE
1992 if (interactive)
1994 rc = do_interactive ();
1995 result = NULL;
1996 goto do_exit;
1998 #endif
2000 if (inquire)
2002 struct inquire_s *inq = NULL;
2004 rc = set_inquire (inquirefd, inquire_line, &inq);
2005 if (!rc)
2006 rc = pwmd_command (pwm, &result, &len, inquire_cb, inq, inquire);
2008 free_inquire (inq);
2009 goto done;
2012 if (fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1)
2014 rc = gpg_error_from_errno (errno);
2015 goto done;
2018 ssize_t n;
2020 for (;;)
2022 rc = process_cmd ();
2024 if (rc)
2025 goto done;
2027 n = read (STDIN_FILENO, command, sizeof (command)-1);
2028 if (n == -1)
2030 if (errno == EAGAIN)
2032 usleep (100000);
2033 continue;
2036 rc = gpg_error_from_errno (errno);
2037 goto done;
2039 else if (!n)
2040 goto done;
2042 p = command;
2043 command[n] = 0;
2044 break;
2047 if (!p || !*p || !strcasecmp (p, "BYE"))
2048 goto done;
2051 struct inquire_s *inq = NULL;
2052 rc = set_inquire (inquirefd, inquire_line, &inq);
2053 if (!rc)
2055 rc = parse_dotcommand (command, &result, &len, inq);
2056 free_inquire (inq);
2059 if (rc)
2060 goto done;
2062 done:
2063 if (result)
2065 fwrite (result, 1, result[len - 1] == 0 ? len - 1 : len, outfp);
2066 fflush (outfp);
2067 pwmd_free (result);
2070 result = NULL;
2071 if (!rc)
2072 rc = finalize ();
2073 else if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
2074 (void) pwmd_command (pwm, &result, NULL, NULL, NULL,
2075 "GETINFO last_error");
2077 #ifdef HAVE_LIBREADLINE
2078 do_exit:
2079 #endif
2080 memset (command, 0, sizeof (command));
2082 if (rc && !quiet)
2083 show_error (pwm, rc, result);
2085 pwmd_close (pwm);
2086 pwmd_free (keyfile);
2087 pwmd_free (new_keyfile);
2088 pwmd_deinit ();
2089 pwmd_free (result);
2090 parse_status_ignore (NULL);
2091 if (connected && !quiet)
2092 fprintf (stderr, N_("Connection closed.\n"));
2094 exit (rc ? EXIT_FAILURE : EXIT_SUCCESS);