Add -fsanitize=undefined to CFLAGS.
[libpwmd.git] / src / pwmc.c
blobf24b9b785a4aa062d462eb157ed63d08f86182e5
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 quiet;
104 struct inquire_s
106 int fd;
107 char *line;
108 size_t len;
109 size_t size; // from stat(2).
110 char *last_keyword;
113 static gpg_error_t finalize ();
114 static gpg_error_t set_inquire (int fd, const char *line,
115 struct inquire_s **result);
116 static gpg_error_t parse_dotcommand (const char *line, char **result,
117 size_t * len, struct inquire_s *inq);
118 static gpg_error_t open_command (const char *line);
119 #ifdef WITH_SSH
120 static gpg_error_t get_password (char **result, pwmd_pinentry_t w, int echo);
121 #endif
123 static void
124 show_error (pwm_t *pwm, gpg_error_t rc, const char *str)
126 #ifdef WITH_GNUTLS
127 if (pwmd_tls_error (pwm))
128 fprintf(stderr, "TLS: %s\n", gnutls_strerror(pwmd_tls_error(pwm)));
129 #endif
130 fprintf (stderr, "ERR %i: %s%s%s%s", rc, gpg_strerror (rc),
131 str ? ": " : "", str ? str : "", str ? "" : "\n");
134 static void
135 usage (const char *pn, int status)
137 fprintf (status == EXIT_FAILURE ? stderr : stdout,
138 N_("Usage: pwmc [options] [file]\n"
139 " --url <string>\n"
140 " a url string to connect to (%s, see below)\n"
141 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
142 " --connect-timeout <seconds>\n"
143 " seconds before connecting to a remote host fails (0=disabled, 120)\n"
144 " --socket-timeout <seconds>\n"
145 " seconds before a remote command fails (0=disabled, 300)\n"
146 #endif
147 #ifdef WITH_GNUTLS
148 " --ca-cert <filename>\n"
149 " certificate authority (CA) used to sign the server cert\n"
150 " --client-cert <filename>\n"
151 " client certificate to use for authentication\n"
152 " --client-key <filename>\n"
153 " key file used to protect the client certificate\n"
154 " --tls-priority <string>\n"
155 " compression, cipher and hash algorithm string (SECURE256)\n"
156 " --tls-verify\n"
157 " verify the hostname against the server certificate\n"
158 " --tls-fingerprint <string>\n"
159 " a SHA-256 hash of the server fingerprint to verify against\n"
160 #endif
161 #ifdef WITH_SSH
162 " --no-ssh-agent\n"
163 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
164 " --identity, -i <filename>\n"
165 " the ssh identity file to use for authentication\n"
166 " --knownhosts, -k <filename>\n"
167 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
168 #endif
169 " --no-lock\n"
170 " do not lock the data file upon opening it\n"
171 " --lock-timeout <N>\n"
172 " time in tenths of a second to wait for a locked data file (50)\n"
173 " --name, -n <string>\n"
174 " set the client name\n"
175 " --pinentry <path>\n"
176 " the full path to the pinentry binary\n"
177 " --local-pinentry\n"
178 " force using a local pinentry\n"
179 " --no-pinentry\n"
180 " disable pinentry both remotely and locally\n"
181 " --ttyname, -y <path>\n"
182 " tty that pinentry will use\n"
183 " --ttytype, -t <string>\n"
184 " pinentry terminal type (default is $TERM)\n"
185 " --display, -d\n"
186 " pinentry display (default is $DISPLAY)\n"
187 " --lc-ctype <string>\n"
188 " locale setting for pinentry\n"
189 " --lc-messages <string>\n"
190 " locale setting for pinentry\n"
191 " --tries <N>\n"
192 " number of pinentry tries before failing (3)\n"
193 " --timeout <seconds>\n"
194 " pinentry timeout\n"
195 " --inquire <COMMAND>\n"
196 " the specified command (with any options) uses a server inquire while\n"
197 " command data is read via the inquire file descriptor (stdin)\n"
198 " --inquire-line, -L <STRING>\n"
199 " the initial line to send (i.e., element path) before the inquire data\n"
200 " --inquire-fd <FD>\n"
201 " read inquire data from the specified file descriptor (stdin)\n"
202 " --inquire-file <filename>\n"
203 " read inquire data from the specified filename\n"
204 " --output-fd <FD>\n"
205 " redirect command output to the specified file descriptor\n"
206 " --save, -S\n"
207 " send the SAVE command before exiting\n"
208 " --key-file <filename>\n"
209 " obtain the passphrase from the specified filename\n"
210 " --new-key-file <filename>\n"
211 " obtain the passphrase to save with from the specified filename\n"
212 " --key-params <string>\n"
213 " the key parameters to use when saving a new file (pwmd default)\n"
214 " --keyid <recipient>[,<recipient>]\n"
215 " the public key ID to u\n"
216 " --sign-keyid <string>\n"
217 " the key ID to sign the data file with\n"
218 " --no-status\n"
219 " disable showing of status messages from the server\n"
220 " --quiet\n"
221 " disable showing of extra messages (implies --no-status)\n"
222 #ifdef HAVE_LIBREADLINE
223 " --interactive\n"
224 " use a shell like interface to pwmd (allows more than one command)\n"
225 #endif
226 " --version\n"
227 " --help\n"),
228 #ifdef DEFAULT_PWMD_SOCKET
229 DEFAULT_PWMD_SOCKET
230 #else
231 "~/.pwmd/socket"
232 #endif
234 fprintf (status == EXIT_FAILURE ? stderr : stdout,
235 N_("\n"
236 "An optional url may be in the form of:\n"
237 " --url /path/to/socket\n"
238 " --url file://[path/to/socket]\n"
239 #ifdef WITH_SSH
240 " or\n"
241 " --url ssh[46]://[username@]hostname[:port]\n"
242 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
243 #endif
244 #ifdef WITH_GNUTLS
245 " or\n"
246 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
247 " --client-key filename\n"
248 #endif
249 #ifdef HAVE_LIBREADLINE
250 "\n"
251 "Interactive mode is used when input is from a terminal.\n"
252 #endif
254 exit (status);
257 static gpg_error_t
258 inquire_cb (void *user, const char *keyword, gpg_error_t rc,
259 char **data, size_t * size)
261 struct inquire_s *inq = user;
262 int is_password = 0;
263 int is_newpassword = 0;
265 *data = NULL;
266 *size = 0;
268 if (rc)
269 return rc;
271 if (!strcmp (keyword, "PASSPHRASE"))
272 is_password = 1;
273 else if (!strcmp (keyword, "NEW_PASSPHRASE"))
274 is_newpassword = 1;
275 #ifdef HAVE_LIBREADLINE
276 else if (!strcmp (keyword, "KEYPARAM") && !interactive)
278 #else
279 else if (!strcmp (keyword, "KEYPARAM"))
281 #endif
282 if (!keyparams || !*keyparams)
283 return gpg_error (GPG_ERR_INV_PARAMETER);
285 *data = keyparams;
286 *size = strlen (keyparams);
287 return gpg_error (GPG_ERR_EOF);
290 if ((is_newpassword && new_keyfile) || (is_password && keyfile))
292 int fd = open (is_password ? keyfile : new_keyfile, O_RDONLY);
294 if (fd == -1)
296 fprintf (stderr, "%s: %s\n", is_newpassword ? new_keyfile : keyfile,
297 strerror (errno));
298 return gpg_error_from_syserror ();
301 rc = set_inquire (fd, NULL, &inq);
302 if (rc)
304 close (fd);
305 return rc;
308 if (!quiet)
309 fprintf (stderr, N_("Using keyfile '%s' as %s.\n"),
310 is_newpassword ? new_keyfile : keyfile, keyword);
312 if (!new_keyfile || is_newpassword)
314 pwmd_socket_t t;
316 pwmd_socket_type (pwm, &t);
317 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
318 if (!no_pinentry && t == PWMD_SOCKET_LOCAL)
319 pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 0);
322 else if ((is_password && !keyfile) || (is_newpassword && !new_keyfile))
324 char *tmp;
326 rc = pwmd_password (pwm, keyword, &tmp, &inq->len);
327 if (rc && gpg_err_code (rc) != GPG_ERR_EOF)
328 return rc;
330 pwmd_free (inq->line);
331 inq->line = tmp;
332 *data = inq->line;
333 *size = inq->len;
334 return gpg_error (GPG_ERR_EOF);
336 #ifdef HAVE_LIBREADLINE
337 else if ((!inq->last_keyword || strcmp (keyword, inq->last_keyword))
338 && interactive)
340 fprintf (stderr,
342 ("%sPress CTRL-D to send the current line. Press twice to end. %s:\n"),
343 inq->last_keyword ? "\n" : "", keyword);
344 pwmd_free (inq->last_keyword);
345 inq->last_keyword = pwmd_strdup (keyword);
347 #endif
349 /* The first part of the command data. */
350 if (inq->len)
352 *data = inq->line;
353 *size = inq->len;
354 inq->len = 0;
355 return inq->fd == -1 ? gpg_error (GPG_ERR_EOF) : 0;
358 *size = read (inq->fd, inq->line, ASSUAN_LINELENGTH);
359 if (*size == -1)
361 *size = 0;
362 return gpg_error (gpg_error_from_syserror ());
364 else if (*size)
365 *data = inq->line;
366 else if (inq->fd != STDIN_FILENO && (is_newpassword || is_password))
368 *inq->line = 0;
369 inq->size = 1;
370 *data = inq->line;
371 *size = 1;
374 if (((is_newpassword && new_keyfile) || (is_password && keyfile))
375 && *size == inq->size)
376 return gpg_error (GPG_ERR_EOF);
378 return *size ? 0 : gpg_error (GPG_ERR_EOF);
381 static int
382 status_msg_cb (void *data, const char *line)
384 char *p = strchr (line, ' ');
386 if (!strcmp (line, "KEEPALIVE"))
387 return 0;
388 else if (!strncmp (line, "GPGME", 5))
389 return 0;
390 else if (!strncmp (line, "PASSPHRASE_HINT", 15))
391 return 0;
392 else if (!strncmp (line, "PASSPHRASE_INFO", 15))
393 return 0;
395 if (*line != '#' && p && strchr (p, ' ') && *++p)
397 char *p1 = strchr (p, ' ');
398 int a = strtol (p, NULL, 10);
400 if (isdigit (*p) && p1)
402 int b = strtol (p1, NULL, 10);
403 char l[64] = { 0 };
404 int t = a && b ? a * 100 / b : 0;
406 strncpy (l, line, strlen (line) - strlen (p) - 1);
407 fprintf (stderr, "\r%s %i/%i %i%%%s", l, a, b, t,
408 a == b ? "\n" : "");
409 fflush (stderr);
410 return 0;
414 fprintf (stderr, "%s\n", line);
415 fflush (stderr);
416 #ifdef HAVE_LIBREADLINE
417 rl_on_new_line ();
418 #endif
419 return 0;
422 static gpg_error_t
423 process_cmd ()
425 return pwmd_process (pwm);
428 #ifdef WITH_SSH
429 static gpg_error_t
430 get_password (char **result, pwmd_pinentry_t w, int echo)
432 char buf[LINE_MAX] = { 0 }, *p;
433 struct termios told, tnew;
434 char *key = NULL;
436 *result = NULL;
438 if (!isatty (STDIN_FILENO))
440 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
441 return GPG_ERR_ENOTTY;
444 if (!echo)
446 if (tcgetattr (STDIN_FILENO, &told) == -1)
447 return gpg_error_from_syserror ();
449 memcpy (&tnew, &told, sizeof (struct termios));
450 tnew.c_lflag &= ~(ECHO);
451 tnew.c_lflag |= ICANON | ECHONL;
453 if (tcsetattr (STDIN_FILENO, TCSANOW, &tnew) == -1)
455 int n = errno;
457 tcsetattr (STDIN_FILENO, TCSANOW, &told);
458 return gpg_error_from_errno (n);
462 switch (w)
464 case PWMD_PINENTRY_OPEN:
465 fprintf (stderr, N_("Password for %s: "), filename);
466 break;
467 case PWMD_PINENTRY_OPEN_FAILED:
468 fprintf (stderr, N_("Invalid password. Password for %s: "), filename);
469 break;
470 case PWMD_PINENTRY_SAVE:
471 fprintf (stderr, N_("New password for %s: "), filename);
472 break;
473 case PWMD_PINENTRY_SAVE_CONFIRM:
474 fprintf (stderr, N_("Confirm password: "));
475 break;
476 default:
477 break;
480 if ((p = fgets (buf, sizeof (buf), stdin)) == NULL)
482 tcsetattr (STDIN_FILENO, TCSANOW, &told);
483 return 0;
486 if (!echo)
487 tcsetattr (STDIN_FILENO, TCSANOW, &told);
489 if (feof (stdin))
491 clearerr (stdin);
492 return GPG_ERR_CANCELED;
495 p[strlen (p) - 1] = 0;
497 if (buf[0])
499 key = pwmd_strdup_printf ("%s", p);
500 memset (&buf, 0, sizeof (buf));
502 if (!key)
503 return GPG_ERR_ENOMEM;
506 *result = key;
507 return 0;
510 static gpg_error_t
511 knownhost_cb (void *data, const char *host, const char *key, size_t len)
513 gpg_error_t rc;
514 char *buf =
515 pwmd_strdup_printf (N_
516 ("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?"),
517 (char *) data, host, host);
519 if (no_pinentry && !isatty (STDIN_FILENO))
521 fprintf (stderr, N_("Input is not from a terminal! Failing.\n"));
522 pwmd_free (buf);
523 return GPG_ERR_ENOTTY;
525 else if (no_pinentry)
527 for (char *p = buf, len = 0; *p; p++, len++)
529 if (*p == '\n')
530 len = 0;
532 if (len == 78)
534 char *t = p;
536 while (!isspace (*(--p)));
537 *p = '\n';
538 p = t;
539 len = 0;
543 fprintf (stderr, "%s\n\n", buf);
544 pwmd_free (buf);
548 char *result;
550 fprintf (stderr, N_("Trust this connection [y/N]: "));
551 fflush (stderr);
552 rc = get_password (&result, PWMD_PINENTRY_CONFIRM, 1);
554 if (rc)
555 return rc;
557 if (!result || !*result || *result == 'n' || *result == 'N')
559 if (result && *result)
560 pwmd_free (result);
562 return GPG_ERR_NOT_CONFIRMED;
565 if ((*result == 'y' || *result == 'Y') && *(result + 1) == 0)
567 pwmd_free (result);
568 return 0;
571 while (1);
574 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, buf);
575 pwmd_free (buf);
577 if (rc)
578 return rc;
580 return pwmd_getpin (pwm, NULL, NULL, NULL, PWMD_PINENTRY_CONFIRM);
582 #endif
584 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
585 static pwmd_socket_t
586 is_remote_url (const char *str)
588 if (!str)
589 return PWMD_SOCKET_LOCAL;
591 #ifdef WITH_SSH
592 if (strstr (str, "ssh://") || strstr (str, "ssh4://")
593 || strstr (str, "ssh6://"))
594 return PWMD_SOCKET_SSH;
595 #endif
597 #ifdef WITH_GNUTLS
598 if (strstr (str, "tls://") || strstr (str, "tls4://")
599 || strstr (str, "tls6://"))
600 return PWMD_SOCKET_TLS;
601 #endif
603 return PWMD_SOCKET_LOCAL;
605 #endif
607 static char *
608 escape (const char *str)
610 const char *p;
611 char *buf = pwmd_malloc (ASSUAN_LINELENGTH + 1), *b = buf;
612 size_t len = 0;
614 for (p = str; *p; p++, len++)
616 if (len == ASSUAN_LINELENGTH)
617 break;
619 if (*p == '\\')
621 switch (*++p)
623 case 't':
624 *b++ = '\t';
625 break;
626 case 'n':
627 *b++ = '\n';
628 break;
629 case 'v':
630 *b++ = '\v';
631 break;
632 case 'b':
633 *b++ = '\b';
634 break;
635 case 'f':
636 *b++ = '\f';
637 break;
638 case 'r':
639 *b++ = '\r';
640 break;
641 default:
642 *b++ = *p;
643 break;
646 if (!*p)
647 break;
649 continue;
652 *b++ = *p;
655 *b = 0;
656 return buf;
659 static void
660 free_inquire (struct inquire_s *inq)
662 if (!inq)
663 return;
665 pwmd_free (inq->line);
667 if (inq->fd != -1 && inq->fd != STDIN_FILENO)
668 close (inq->fd);
670 pwmd_free (inq->last_keyword);
671 pwmd_free (inq);
674 /* When *result is not NULL it is updated to the new values and not
675 * reallocated. */
676 static gpg_error_t
677 set_inquire (int fd, const char *line, struct inquire_s **result)
679 struct inquire_s inq = { 0 };
680 struct stat st = { 0 };
681 gpg_error_t rc;
683 if (fd != -1)
685 if (fstat (fd, &st) == -1)
686 return gpg_error_from_syserror ();
688 inq.size = st.st_size;
691 inq.fd = fd;
692 inq.line = pwmd_calloc (1, ASSUAN_LINELENGTH);
693 if (!inq.line)
694 return GPG_ERR_ENOMEM;
696 if (line)
698 char *s = escape (line);
700 if (!s)
702 pwmd_free (inq.line);
703 return GPG_ERR_ENOMEM;
706 if (strlen (s) >= ASSUAN_LINELENGTH)
708 pwmd_free (inq.line);
709 pwmd_free (s);
710 return GPG_ERR_LINE_TOO_LONG;
713 strncpy (inq.line, s, ASSUAN_LINELENGTH - 1);
714 inq.len = strlen (s);
715 pwmd_free (s);
718 rc = pwmd_setopt (pwm, PWMD_OPTION_INQUIRE_TOTAL,
719 st.st_size ? st.st_size + strlen (inq.line) : 0);
720 if (rc)
722 pwmd_free (inq.line);
723 return rc;
726 if (*result == NULL)
727 *result = pwmd_malloc (sizeof (struct inquire_s));
728 else
730 if ((*result)->fd != -1 && (*result)->fd != STDIN_FILENO)
731 close ((*result)->fd);
733 pwmd_free ((*result)->line);
734 (*result)->line = NULL;
735 (*result)->fd = -1;
736 (*result)->len = 0;
739 memcpy (*result, &inq, sizeof (struct inquire_s));
740 memset (&inq, 0, sizeof (struct inquire_s));
741 return rc;
744 #ifdef HAVE_LIBREADLINE
745 static int
746 interactive_hook (void)
748 interactive_error = process_cmd ();
750 if (interactive_error)
751 rl_event_hook = NULL;
753 return 0;
756 static void
757 print_help ()
759 fprintf (stderr,
761 ("------------------------------------------------------------------------------\n"
762 "Elements are TAB delimited. Press CTRL-V then TAB to insert from the prompt.\n"
763 "\n"
764 "Type HELP for protocol commands. Type .help for pwmc commands. Press CTRL-D\n"
765 "to quit.\n"
766 "------------------------------------------------------------------------------\n"));
768 #endif
770 static char *
771 parse_arg (const char *src, char *dst, size_t len)
773 char *p = dst;
774 const char *s = src;
775 size_t n = 0;
777 for (; s && *s && *s != ' ' && n < len; s++, n++)
778 *p++ = *s;
780 *p = 0;
781 return dst;
784 static char *
785 parse_opt (char **line, const char *opt, gpg_error_t * rc)
787 static char result[ASSUAN_LINELENGTH] = { 0 }, *r = result;
788 char *s = strstr (*line, opt);
790 *rc = 0;
791 result[0] = 0;
792 r = result;
794 if (s)
796 size_t len = 0;
797 int quote = 0;
798 size_t rlen = strlen (opt);
799 char *p = s + rlen;
800 int lastc = 0;
802 while (*p && *p == ' ')
804 rlen++;
805 p++;
808 for (; *p && len < sizeof (result) - 1; p++, rlen++)
810 if (isspace (*p) && !quote)
811 break;
813 if (*p == '\"' && lastc != '\\')
815 quote = !quote;
816 lastc = *p;
817 continue;
820 *r++ = lastc = *p;
821 len++;
824 *r = 0;
826 if (len >= sizeof (result) - 1)
827 *rc = GPG_ERR_LINE_TOO_LONG;
828 else
830 p = s + rlen;
832 while (*p && *p == ' ')
833 p++;
835 *line = p;
839 return result;
842 static gpg_error_t
843 read_command (const char *line, char **result, size_t * len)
845 int fd;
846 gpg_error_t rc = 0;
847 char *filename = NULL;
848 struct inquire_s *inq = NULL;
849 char *p = (char *) line;
850 const char *prefix = parse_opt (&p, "--prefix", &rc);
852 if (rc)
853 return rc;
855 rc = GPG_ERR_SYNTAX;
857 if (p && *p)
859 char filebuf[ASSUAN_LINELENGTH];
861 while (*p && isspace (*p))
862 p++;
864 filename = parse_arg (p, filebuf, sizeof (filebuf));
865 if (filename && *filename)
867 p += strlen (filename) + 1;
869 while (*p && isspace (*p))
870 p++;
872 if (*p)
873 rc = 0;
877 if (rc)
879 fprintf (stderr,
881 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
882 fprintf (stderr,
884 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\" = \")\n"));
885 return rc;
888 fd = open (filename, O_RDONLY);
889 if (fd == -1)
890 return gpg_error_from_syserror ();
892 rc = set_inquire (fd, prefix && *prefix ? prefix : NULL, &inq);
893 if (rc)
895 close (fd);
896 return rc;
899 rc = pwmd_command (pwm, result, len, inquire_cb, inq, p);
900 free_inquire (inq);
901 return rc;
904 static gpg_error_t
905 redir_command (const char *line)
907 const char *p = line;
908 int fd;
909 gpg_error_t rc = GPG_ERR_SYNTAX;
910 char *filename = NULL;
911 struct inquire_s *inq = NULL;
912 char *result = NULL;
913 size_t len = 0;
915 if (p && *p && *++p)
917 char filebuf[ASSUAN_LINELENGTH];
919 filename = parse_arg (p, filebuf, sizeof (filebuf));
920 if (filename && *filename)
922 p += strlen (filename) + 1;
924 while (*p && isspace (*p))
925 p++;
927 if (*p)
928 rc = 0;
932 if (rc)
934 fprintf (stderr, N_("Usage: .redir <filename> <command> [args]\n"));
935 return rc;
938 fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
939 if (fd == -1)
940 return gpg_error_from_syserror ();
942 #ifdef HAVE_LIBREADLINE
943 rc = set_inquire (interactive ? STDIN_FILENO : inquirefd, NULL, &inq);
944 #else
945 rc = set_inquire (inquirefd, NULL, &inq);
946 #endif
947 if (rc)
949 close (fd);
950 return rc;
953 rc = parse_dotcommand (p, &result, &len, inq);
954 if (!rc && result && len--)
955 { // null byte which is always appended
956 if (write (fd, result, len) != len)
957 rc = GPG_ERR_TOO_SHORT;
958 pwmd_free (result);
961 free_inquire (inq);
962 close (fd);
963 return rc;
966 static gpg_error_t
967 help_command (const char *line)
969 fprintf (stderr,
970 N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
971 " .redir <filename> <command>\n"
972 " redirect the output of a command to the specified file\n"
973 "\n"
974 " .open <filename>\n"
975 " open the specified filename losing any changes to the current one\n"
976 "\n"
977 " .read [--prefix <string>] <filename> <command> [args]\n"
978 " obtain data from the specified filename for an inquire command\n"
979 "\n"
980 " .set help | <name> [<value>]\n"
981 " set option <name> to <value>\n"
982 "\n"
983 " .save [args]\n"
984 " write changes of the file to disk\n"
985 "\n"
986 " .passwd [args]\n"
987 " change the passphrase of a data file\n"
988 "\n"
989 " .help\n"
990 " this help text\n"));
991 return 0;
994 static gpg_error_t
995 open_command (const char *line)
997 struct inquire_s *inq = NULL;
998 const char *filename = line;
999 gpg_error_t rc;
1001 while (filename && isspace (*filename))
1002 filename++;
1004 if (!filename || !*filename)
1006 fprintf (stderr, N_("Usage: .open <filename>\n"));
1007 return GPG_ERR_SYNTAX;
1010 #ifdef HAVE_LIBREADLINE
1011 if (interactive || !quiet)
1012 #else
1013 if (!quiet)
1014 #endif
1015 fprintf (stderr, N_("Opening data file \"%s\" ...\n"), filename);
1017 #ifdef HAVE_LIBREADLINE
1018 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1019 #else
1020 rc = set_inquire (-1, NULL, &inq);
1021 #endif
1022 if (rc)
1023 return rc;
1025 if (keyfile)
1026 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1027 else
1028 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1030 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1031 rc = pwmd_open (pwm, filename, inquire_cb, inq);
1032 free_inquire (inq);
1033 return rc;
1036 static gpg_error_t
1037 set_command (const char *line)
1039 gpg_error_t rc = 0;
1040 char name[256] = { 0 };
1041 char value[512] = { 0 };
1042 char *namep;
1043 char *valuep;
1044 const char *p = line;
1046 while (p && *p && isspace (*p))
1047 p++;
1049 namep = parse_arg (p, name, sizeof (name));
1050 if (!namep || !*namep)
1052 fprintf (stderr, N_("Usage: .set help | <name> [<value>]\n"));
1053 return GPG_ERR_SYNTAX;
1056 p += strlen (namep);
1057 while (p && *p && isspace (*p))
1058 p++;
1060 valuep = parse_arg (p, value, sizeof (value));
1062 if (!strcmp (name, "keyfile") || !strcmp (name, "new-keyfile"))
1064 int is_newkeyfile = 1;
1066 if (!strcmp (name, "keyfile"))
1067 is_newkeyfile = 0;
1069 if (is_newkeyfile)
1071 pwmd_free (new_keyfile);
1072 new_keyfile = NULL;
1074 else
1076 pwmd_free (keyfile);
1077 keyfile = NULL;
1080 p += strlen (valuep);
1081 while (p && *p && isspace (*p))
1082 p++;
1084 valuep = (char *) p;
1085 if (!rc && *valuep)
1087 if (is_newkeyfile)
1088 new_keyfile = pwmd_strdup (value);
1089 else
1090 keyfile = pwmd_strdup (value);
1092 if (!rc)
1094 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 1);
1095 if (!rc)
1096 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1099 else if (!local_pin && !no_pinentry)
1101 pwmd_socket_t t;
1103 pwmd_socket_type (pwm, &t);
1104 if (t == PWMD_SOCKET_LOCAL)
1106 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, 0);
1107 if (!rc)
1108 rc = pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1112 else if (!strcmp(name, "pinentry-timeout"))
1114 char *e = NULL;
1115 int n = strtol(valuep, &e, 10);
1117 if (e && *e)
1118 return gpg_error (GPG_ERR_INV_VALUE);
1120 if (!valuep || !*valuep)
1121 n = DEFAULT_PIN_TIMEOUT;
1123 rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, n);
1125 else if (!strcmp (name, "help"))
1127 fprintf (stderr,
1129 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1130 "delimited. When no value is specified the option is unset.\n\n"
1131 "keyfile <datafile> [<filename>]\n"
1132 " set or unset the keyfile to be used when a passphrase is required (*)\n"
1133 "\n"
1134 "new-keyfile <datafile> [<filename>]\n"
1135 " set or unset the keyfile to be used when a new passphrase is required (*)\n"
1136 "\n"
1137 "pinentry-timeout <seconds>\n"
1138 " the amount of seconds before pinentry gives up waiting for input\n"
1139 "\n"
1140 "* = the next protocol command will unset this value\n"
1143 else
1144 rc = GPG_ERR_UNKNOWN_OPTION;
1146 return rc;
1149 static gpg_error_t
1150 save_command (const char *line)
1152 struct inquire_s *inq = NULL;
1153 gpg_error_t rc;
1155 #ifdef HAVE_LIBREADLINE
1156 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1157 #else
1158 rc = set_inquire (-1, NULL, &inq);
1159 #endif
1160 if (rc)
1161 return rc;
1163 if (new_keyfile || keyfile)
1164 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1166 rc = pwmd_save (pwm, line, inquire_cb, inq);
1167 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1168 free_inquire (inq);
1169 return rc;
1172 static gpg_error_t
1173 do_save_passwd_command (const char *line, int save)
1175 struct inquire_s *inq = NULL;
1176 gpg_error_t rc;
1178 #ifdef HAVE_LIBREADLINE
1179 rc = set_inquire (interactive ? STDIN_FILENO : -1, NULL, &inq);
1180 #else
1181 rc = set_inquire (-1, NULL, &inq);
1182 #endif
1183 if (rc)
1184 return rc;
1186 if (new_keyfile || keyfile)
1187 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 1);
1189 if (save)
1190 rc = pwmd_save (pwm, line, inquire_cb, inq);
1191 else
1192 rc = pwmd_passwd (pwm, line, inquire_cb, inq);
1194 pwmd_setopt (pwm, PWMD_OPTION_OVERRIDE_INQUIRE, 0);
1195 free_inquire (inq);
1196 return rc;
1199 static gpg_error_t
1200 parse_dotcommand (const char *line, char **result,
1201 size_t * len, struct inquire_s *inq)
1203 const char *p = line;
1204 gpg_error_t rc = 0;
1206 if (!strncmp (p, ".read", 5))
1207 rc = read_command (p + 5, result, len);
1208 else if (!strncmp (p, ".redir", 6))
1209 rc = redir_command (p + 6);
1210 else if (!strncmp (p, ".help", 5))
1211 rc = help_command (p + 5);
1212 else if (!strncmp (p, ".open", 5))
1213 rc = open_command (p + 5);
1214 else if (!strncmp (p, ".set", 4))
1215 rc = set_command (p + 4);
1216 else if (!strncmp (p, ".save", 5))
1217 rc = do_save_passwd_command (p + 5, 1);
1218 else if (!strncmp (p, ".passwd", 7))
1219 rc = do_save_passwd_command (p + 7, 0);
1220 else
1222 rc = pwmd_command (pwm, result, len, inquire_cb, inq, line);
1223 #ifdef HAVE_LIBREADLINE
1224 if (interactive)
1226 #endif
1227 pwmd_free (keyfile);
1228 pwmd_free (new_keyfile);
1229 keyfile = new_keyfile = NULL;
1230 #ifdef HAVE_LIBREADLINE
1232 #endif
1235 return FINISH (rc);
1238 #ifdef HAVE_LIBREADLINE
1239 static gpg_error_t
1240 do_interactive ()
1242 gpg_error_t rc;
1243 struct inquire_s *inq = NULL;
1245 rl_initialize ();
1246 rc = process_cmd ();
1247 if (rc)
1248 return rc;
1250 rc = set_inquire (STDIN_FILENO, NULL, &inq);
1251 if (rc)
1252 return rc;
1254 fprintf (stderr,
1255 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1256 print_help ();
1257 rl_event_hook = &interactive_hook;
1258 rl_set_keyboard_input_timeout (100000);
1260 for (;;)
1262 char *line;
1263 char *result = NULL;
1264 size_t len;
1266 rc = 0;
1267 line = readline ("pwm> ");
1268 if (interactive_error)
1270 free (line);
1271 rc = interactive_error;
1272 break;
1275 if (!line)
1277 rc = finalize ();
1278 if (!rc)
1279 break;
1281 if (gpg_err_code (rc) != GPG_ERR_CANCELED &&
1282 gpg_err_code (rc) != GPG_ERR_EOF)
1283 fprintf (stderr, "ERR %i: %s\n", rc, gpg_strerror (rc));
1285 continue;
1287 else if (!*line)
1289 free (line);
1290 continue;
1293 #ifdef HAVE_READLINE_HISTORY
1294 add_history (line);
1295 #endif
1296 rc = parse_dotcommand (line, &result, &len, inq);
1297 free (line);
1298 if (rc)
1300 char *tmp = NULL;
1302 if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
1303 (void) pwmd_command (pwm, &tmp, NULL, NULL, NULL,
1304 "GETINFO last_error");
1306 show_error (pwm, rc, tmp);
1307 pwmd_free (tmp);
1309 else if (result && len)
1310 printf ("%s%s", result, result[len - 1] != '\n' ? "\n" : "");
1312 pwmd_free (result);
1315 free_inquire (inq);
1316 return rc;
1318 #endif
1320 static gpg_error_t
1321 finalize ()
1323 gpg_error_t rc = 0;
1324 #ifdef HAVE_LIBREADLINE
1325 int quit = 0;
1327 if (interactive)
1329 int finished = 0;
1331 fprintf (stderr, "\n");
1335 char *p, buf[16];
1337 fprintf (stderr,
1339 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1340 p = fgets (buf, sizeof (buf), stdin);
1342 if (feof (stdin))
1344 clearerr (stdin);
1345 return GPG_ERR_EOF;
1348 switch (*p)
1350 case 'h':
1351 print_help ();
1352 break;
1353 case 'c':
1354 return GPG_ERR_CANCELED;
1355 case 'Q':
1356 return 0;
1357 case 'f':
1358 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1359 "CLEARCACHE %s", filename);
1360 if (rc)
1361 return rc;
1363 interactive_hook ();
1364 break;
1365 case 'S':
1366 quit = 1;
1367 case 's':
1368 save = 1;
1369 finished = 1;
1370 break;
1371 default:
1372 break;
1375 while (!finished);
1377 #endif
1379 if (save && !filename)
1381 fprintf (stderr,
1383 ("No filename was specified on the command line. Aborting.\n"));
1384 return GPG_ERR_CANCELED;
1387 if (save && filename)
1389 char *args =
1390 pwmd_strdup_printf ("%s%s %s%s %s",
1391 keyid ? "--keyid=" : "",
1392 keyid ? keyid : "",
1393 sign_keyid ? "--sign-keyid=" : "",
1394 sign_keyid ? sign_keyid : "",
1395 keyparams ? "--inquire-keyparam" : "");
1397 #ifdef HAVE_LIBREADLINE
1398 if (!quiet || interactive)
1400 #else
1401 if (!quiet)
1403 #endif
1404 fprintf (stderr, "\n");
1405 fprintf (stderr, N_("Saving changes ...\n"));
1408 rc = save_command (args);
1409 pwmd_free (args);
1412 #ifdef HAVE_LIBREADLINE
1413 if (interactive)
1414 return rc ? rc : quit ? 0 : GPG_ERR_CANCELED;
1415 #endif
1417 return rc;
1421 main (int argc, char *argv[])
1423 int connected = 0;
1424 gpg_error_t rc;
1425 int opt;
1426 char command[ASSUAN_LINELENGTH], *p = NULL;
1427 char *result = NULL;
1428 size_t len = 0;
1429 char *pinentry_path = NULL;
1430 char *display = NULL, *tty = NULL, *ttytype = NULL;
1431 char *lcctype = NULL, *lcmessages = NULL;
1432 int outfd = STDOUT_FILENO;
1433 FILE *outfp = stdout;
1434 FILE *inquirefp = stdin;
1435 int show_status = 1;
1436 char *clientname = "pwmc";
1437 char *inquire = NULL;
1438 char *inquire_line = NULL;
1439 int timeout = 0;
1440 #ifdef WITH_SSH
1441 int use_ssh_agent = 1;
1442 char *knownhosts = NULL;
1443 char *identity = NULL;
1444 #endif
1445 #ifdef WITH_GNUTLS
1446 char *cacert = NULL;
1447 char *clientcert = NULL;
1448 char *clientkey = NULL;
1449 char *prio = NULL;
1450 int tls_verify = 0;
1451 char *tls_fingerprint = NULL;
1452 #endif
1453 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1454 pwmd_socket_t socktype;
1455 long socket_timeout = 300;
1456 int connect_timeout = 120;
1457 #endif
1458 int lock_on_open = 1;
1459 long lock_timeout = 50;
1460 char *url = NULL;
1461 /* The order is important. */
1462 enum
1464 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1465 OPT_SOCKET_TIMEOUT, OPT_CONNECT_TIMEOUT,
1466 #endif
1467 #ifdef WITH_SSH
1468 OPT_USE_SSH_AGENT, OPT_IDENTITY, OPT_KNOWNHOSTS,
1469 #endif
1470 #ifdef WITH_GNUTLS
1471 OPT_CACERT, OPT_CLIENTCERT, OPT_CLIENTKEY, OPT_PRIORITY, OPT_VERIFY,
1472 OPT_SERVER_FP,
1473 #endif
1474 OPT_URL, OPT_LOCAL, OPT_TTYNAME, OPT_TTYTYPE,
1475 OPT_DISPLAY, OPT_LC_CTYPE, OPT_LC_MESSAGES, OPT_TIMEOUT, OPT_TRIES,
1476 OPT_PINENTRY, OPT_KEYFILE, OPT_NEW_KEYFILE, OPT_NOLOCK,
1477 OPT_LOCK_TIMEOUT, OPT_SAVE, OPT_OUTPUT_FD, OPT_INQUIRE,
1478 OPT_INQUIRE_FD, OPT_INQUIRE_FILE, OPT_INQUIRE_LINE, OPT_NO_STATUS,
1479 OPT_NAME, OPT_VERSION, OPT_HELP, OPT_KEYID, OPT_SIGN_KEYID,
1480 OPT_KEYPARAMS, OPT_NO_PINENTRY, OPT_QUIET,
1481 #ifdef HAVE_LIBREADLINE
1482 OPT_INTERACTIVE,
1483 #endif
1485 const struct option long_opts[] = {
1486 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1487 {"socket-timeout", 1, 0, 0},
1488 {"connect-timeout", 1, 0, 0},
1489 #endif
1491 #ifdef WITH_SSH
1492 {"no-ssh-agent", 0, 0, 0},
1493 {"identity", 1, 0, 'i'},
1494 {"knownhosts", 1, 0, 'k'},
1495 #endif
1496 #ifdef WITH_GNUTLS
1497 {"ca-cert", 1, 0, 0},
1498 {"client-cert", 1, 0, 0},
1499 {"client-key", 1, 0, 0},
1500 {"tls-priority", 1, 0, 0},
1501 {"tls-verify", 0, 0, 0},
1502 {"tls-fingerprint", 1, 0, 0},
1503 #endif
1504 {"url", 1, 0, 0},
1505 {"local-pinentry", 0, 0},
1506 {"ttyname", 1, 0, 'y'},
1507 {"ttytype", 1, 0, 't'},
1508 {"display", 1, 0, 'd'},
1509 {"lc-ctype", 1, 0, 0},
1510 {"lc-messages", 1, 0, 0},
1511 {"timeout", 1, 0, 0},
1512 {"tries", 1, 0, 0},
1513 {"pinentry", 1, 0, 0},
1514 {"key-file", 1, 0, 0},
1515 {"new-key-file", 1, 0, 0},
1516 {"no-lock", 0, 0, 0},
1517 {"lock-timeout", 1, 0, 0},
1518 {"save", 0, 0, 'S'},
1519 {"output-fd", 1, 0, 0},
1520 {"inquire", 1, 0, 0},
1521 {"inquire-fd", 1, 0, 0},
1522 {"inquire-file", 1, 0, 0},
1523 {"inquire-line", 1, 0, 'L'},
1524 {"no-status", 0, 0, 0},
1525 {"name", 1, 0, 'n'},
1526 {"version", 0, 0, 0},
1527 {"help", 0, 0, 0},
1528 {"keyid", 1, 0, 0},
1529 {"sign-keyid", 1, 0, 0},
1530 {"key-params", 1, 0, 0},
1531 {"no-pinentry", 0, 0, 0},
1532 {"quiet", 0, 0, 0},
1533 #ifdef HAVE_LIBREADLINE
1534 {"interactive", 0, 0},
1535 #endif
1536 {0, 0, 0, 0}
1538 #ifdef WITH_SSH
1539 const char *optstring = "L:y:t:d:P:I:Sn:i:k:";
1540 #else
1541 const char *optstring = "L:y:t:d:P:I:Sn:";
1542 #endif
1543 int opt_index = 0;
1545 #ifdef ENABLE_NLS
1546 setlocale (LC_ALL, "");
1547 bindtextdomain ("libpwmd", LOCALEDIR);
1548 #endif
1550 tries = DEFAULT_PIN_TRIES;
1551 inquirefd = STDIN_FILENO;
1553 while ((opt =
1554 getopt_long (argc, argv, optstring, long_opts, &opt_index)) != -1)
1556 switch (opt)
1558 /* Handle long options without a short option part. */
1559 case 0:
1560 switch (opt_index)
1562 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1563 case OPT_SOCKET_TIMEOUT:
1564 socket_timeout = strtol (optarg, &p, 10);
1565 break;
1566 case OPT_CONNECT_TIMEOUT:
1567 connect_timeout = strtol (optarg, &p, 10);
1568 break;
1569 #endif
1570 #ifdef WITH_SSH
1571 case OPT_USE_SSH_AGENT:
1572 use_ssh_agent = 0;
1573 break;
1574 #endif
1575 #ifdef WITH_GNUTLS
1576 case OPT_CACERT:
1577 cacert = optarg;
1578 break;
1579 case OPT_CLIENTCERT:
1580 clientcert = optarg;
1581 break;
1582 case OPT_CLIENTKEY:
1583 clientkey = optarg;
1584 break;
1585 case OPT_PRIORITY:
1586 prio = optarg;
1587 break;
1588 case OPT_VERIFY:
1589 tls_verify = 1;
1590 break;
1591 case OPT_SERVER_FP:
1592 tls_fingerprint = optarg;
1593 break;
1594 #endif
1595 case OPT_KEYPARAMS:
1596 keyparams = optarg;
1597 break;
1598 case OPT_KEYFILE:
1599 keyfile = pwmd_strdup (optarg);
1600 break;
1601 case OPT_NEW_KEYFILE:
1602 new_keyfile = pwmd_strdup (optarg);
1603 break;
1604 case OPT_NOLOCK:
1605 lock_on_open = 0;
1606 break;
1607 case OPT_LOCK_TIMEOUT:
1608 lock_timeout = strtol (optarg, &p, 10);
1609 break;
1610 case OPT_URL:
1611 url = optarg;
1612 break;
1613 case OPT_LOCAL:
1614 local_pin = 1;
1615 break;
1616 case OPT_LC_CTYPE:
1617 lcctype = pwmd_strdup (optarg);
1618 break;
1619 case OPT_LC_MESSAGES:
1620 lcmessages = pwmd_strdup (optarg);
1621 break;
1622 case OPT_TIMEOUT:
1623 timeout = strtol (optarg, &p, 10);
1624 break;
1625 case OPT_TRIES:
1626 tries = strtol (optarg, &p, 10);
1627 break;
1628 case OPT_INQUIRE:
1629 inquire = escape (optarg);
1630 break;
1631 case OPT_INQUIRE_FD:
1632 inquirefd = strtol (optarg, &p, 10);
1633 if (!p)
1635 inquirefp = fdopen (inquirefd, "r");
1636 if (!inquirefp)
1637 err (EXIT_FAILURE, "%i", inquirefd);
1639 break;
1640 case OPT_INQUIRE_FILE:
1641 inquirefd = open (optarg, O_RDONLY);
1642 if (inquirefd == -1)
1643 err (EXIT_FAILURE, "%s", optarg);
1644 inquirefp = fdopen (inquirefd, "r");
1645 break;
1646 case OPT_OUTPUT_FD:
1647 outfd = strtol (optarg, &p, 10);
1648 if (!p)
1650 outfp = fdopen (outfd, "w");
1651 if (!outfp)
1652 err (EXIT_FAILURE, "%i", outfd);
1654 break;
1655 case OPT_NO_STATUS:
1656 show_status = 0;
1657 break;
1658 case OPT_VERSION:
1659 printf ("%s (pwmc)\n\n"
1660 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014\n"
1661 "%s\n"
1662 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1663 "Compile-time features:\n"
1664 #ifdef HAVE_LIBREADLINE
1665 "+INTERACTIVE "
1666 #else
1667 "-INTERACTIVE "
1668 #endif
1669 #ifdef WITH_SSH
1670 "+SSH "
1671 #else
1672 "-SSH "
1673 #endif
1674 #ifdef WITH_GNUTLS
1675 "+GNUTLS "
1676 #else
1677 "-GNUTLS "
1678 #endif
1679 #ifdef WITH_PINENTRY
1680 "+PINENTRY "
1681 #else
1682 "-PINENTRY "
1683 #endif
1684 #ifdef WITH_QUALITY
1685 "+CRACK "
1686 #else
1687 "-CRACK "
1688 #endif
1689 #ifdef MEM_DEBUG
1690 "+MEM_DEBUG "
1691 #else
1692 "-MEM_DEBUG "
1693 #endif
1694 "\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1695 exit (EXIT_SUCCESS);
1696 case OPT_PINENTRY:
1697 pinentry_path = optarg;
1698 break;
1699 case OPT_HELP:
1700 usage (argv[0], EXIT_SUCCESS);
1701 case OPT_KEYID:
1702 keyid = optarg;
1703 break;
1704 case OPT_SIGN_KEYID:
1705 sign_keyid = optarg;
1706 break;
1707 case OPT_QUIET:
1708 quiet = 1;
1709 show_status = 0;
1710 break;
1711 case OPT_NO_PINENTRY:
1712 no_pinentry = 1;
1713 break;
1714 #ifdef HAVE_LIBREADLINE
1715 case OPT_INTERACTIVE:
1716 interactive = 1;
1717 break;
1718 #endif
1719 default:
1720 usage (argv[0], EXIT_FAILURE);
1723 if (p && *p)
1725 fprintf (stderr, N_("%s: invalid argument for option '--%s'\n"),
1726 argv[0], long_opts[opt_index].name);
1727 usage (argv[0], EXIT_FAILURE);
1730 break;
1731 #ifdef WITH_SSH
1732 case 'i':
1733 identity = optarg;
1734 break;
1735 case 'k':
1736 knownhosts = optarg;
1737 break;
1738 #endif
1739 case 'L':
1740 inquire_line = optarg;
1741 break;
1742 case 'y':
1743 tty = optarg;
1744 break;
1745 case 't':
1746 ttytype = optarg;
1747 break;
1748 case 'd':
1749 display = optarg;
1750 break;
1751 case 'S':
1752 save = 1;
1753 break;
1754 case 'n':
1755 clientname = optarg;
1756 break;
1757 default:
1758 usage (argv[0], EXIT_FAILURE);
1762 #ifdef HAVE_LIBREADLINE
1763 if (interactive && !isatty (STDIN_FILENO))
1764 usage (argv[0], EXIT_FAILURE);
1765 else if (isatty (STDIN_FILENO) && !inquire && !inquire_line)
1766 interactive = 1;
1767 #endif
1769 filename = argv[optind];
1770 #ifdef WITH_GNUTLS
1771 gnutls_global_set_mem_functions (pwmd_malloc, pwmd_malloc, NULL,
1772 pwmd_realloc, pwmd_free);
1773 #endif
1774 pwmd_init ();
1775 rc = pwmd_new (clientname, &pwm);
1776 if (rc)
1777 goto done;
1779 pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
1780 if (!quiet)
1781 fprintf (stderr, N_("Connecting ...\n"));
1783 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1784 socktype = is_remote_url (url);
1785 if (socktype != PWMD_SOCKET_LOCAL)
1787 local_pin = 1;
1788 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1789 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, connect_timeout);
1790 if (rc)
1791 goto done;
1792 #endif
1794 if (socktype == PWMD_SOCKET_SSH)
1796 #ifdef WITH_SSH
1797 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_CB, knownhost_cb);
1798 if (rc)
1799 goto done;
1801 rc = pwmd_setopt (pwm, PWMD_OPTION_KNOWNHOST_DATA, clientname);
1802 if (rc)
1803 goto done;
1805 if (!getenv ("SSH_AUTH_SOCK") || identity)
1806 use_ssh_agent = 0;
1808 rc = pwmd_setopt (pwm, PWMD_OPTION_SSH_AGENT, use_ssh_agent);
1809 if (rc)
1810 goto done;
1812 rc = pwmd_connect (pwm, url, identity, knownhosts);
1813 #endif
1815 #ifdef WITH_GNUTLS
1816 else
1818 rc = pwmd_setopt (pwm, PWMD_OPTION_TLS_VERIFY, tls_verify);
1819 if (rc)
1820 goto done;
1822 rc = pwmd_connect (pwm, url, clientcert, clientkey, cacert, prio,
1823 tls_fingerprint);
1825 #endif
1827 else
1828 rc = pwmd_connect (pwm, url);
1829 #else
1830 rc = pwmd_connect (pwm, url);
1831 #endif
1832 if (rc)
1833 goto done;
1835 if (!quiet)
1836 fprintf (stderr, N_("Connected.\n"));
1838 connected = 1;
1839 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1840 rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, socket_timeout);
1841 if (rc)
1842 goto done;
1843 #endif
1845 if (lock_timeout)
1847 rc = pwmd_command (pwm, NULL, NULL, NULL, NULL,
1848 "OPTION LOCK-TIMEOUT=%li", lock_timeout);
1849 if (rc)
1850 goto done;
1853 if (lock_on_open)
1855 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCK_ON_OPEN, 1);
1856 if (rc)
1857 goto done;
1860 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DESC, NULL, NULL);
1861 if (rc)
1862 goto done;
1864 if (timeout > 0)
1866 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
1867 if (rc)
1868 goto done;
1871 rc = pwmd_setopt (pwm, PWMD_OPTION_NO_PINENTRY, no_pinentry);
1872 if (rc)
1873 goto done;
1875 rc = pwmd_setopt (pwm, PWMD_OPTION_LOCAL_PINENTRY,
1876 (local_pin || keyfile || new_keyfile));
1877 if (rc)
1878 goto done;
1880 if (pinentry_path)
1882 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
1883 if (rc)
1884 goto done;
1887 if (display)
1889 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
1890 if (rc)
1891 goto done;
1894 if (tty)
1896 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TTY, tty);
1897 if (rc)
1898 goto done;
1901 if (ttytype)
1903 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
1904 if (rc)
1905 goto done;
1908 if (lcctype)
1910 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
1911 if (rc)
1912 goto done;
1915 if (lcmessages)
1917 rc = pwmd_setopt (pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES, lcmessages);
1918 if (rc)
1919 goto done;
1922 if (show_status)
1924 rc = pwmd_setopt (pwm, PWMD_OPTION_STATUS_CB, status_msg_cb);
1925 if (rc)
1926 goto done;
1929 if (filename)
1931 rc = open_command (filename);
1932 if (rc)
1933 goto done;
1936 #ifdef HAVE_LIBREADLINE
1937 if (interactive)
1939 rc = do_interactive ();
1940 result = NULL;
1941 goto do_exit;
1943 #endif
1945 if (inquire)
1947 struct inquire_s *inq = NULL;
1949 rc = set_inquire (inquirefd, inquire_line, &inq);
1950 if (!rc)
1951 rc = pwmd_command (pwm, &result, &len, inquire_cb, inq, inquire);
1953 free_inquire (inq);
1954 goto done;
1957 fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK);
1958 ssize_t n;
1960 for (;;)
1962 rc = process_cmd ();
1964 if (rc)
1965 goto done;
1967 n = read (STDIN_FILENO, command, sizeof (command));
1968 if (n == -1)
1970 if (errno == EAGAIN)
1972 usleep (100000);
1973 continue;
1976 rc = gpg_error_from_errno (errno);
1977 goto done;
1979 else if (!n)
1980 goto done;
1982 p = command;
1983 command[n] = 0;
1984 break;
1987 if (!p || !*p || !strcasecmp (p, "BYE"))
1988 goto done;
1991 struct inquire_s *inq = NULL;
1992 rc = set_inquire (inquirefd, inquire_line, &inq);
1993 if (!rc)
1995 rc = parse_dotcommand (command, &result, &len, inq);
1996 free_inquire (inq);
1999 if (rc)
2000 goto done;
2002 done:
2003 if (result)
2005 fwrite (result, 1, result[len - 1] == 0 ? len - 1 : len, outfp);
2006 fflush (outfp);
2007 pwmd_free (result);
2010 result = NULL;
2011 if (!rc)
2012 rc = finalize ();
2013 else if (gpg_err_code (rc) == GPG_ERR_BAD_DATA)
2014 (void) pwmd_command (pwm, &result, NULL, NULL, NULL,
2015 "GETINFO last_error");
2017 #ifdef HAVE_LIBREADLINE
2018 do_exit:
2019 #endif
2020 memset (command, 0, sizeof (command));
2022 if (rc && !quiet)
2023 show_error (pwm, rc, result);
2025 pwmd_close (pwm);
2026 pwmd_free (keyfile);
2027 pwmd_free (new_keyfile);
2028 pwmd_deinit ();
2029 pwmd_free (result);
2030 if (connected && !quiet)
2031 fprintf (stderr, N_("Connection closed.\n"));
2033 exit (rc ? EXIT_FAILURE : EXIT_SUCCESS);