2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015,
4 Ben Kibbey <bjk@luxsci.net>
6 This file is part of libpwmd.
8 Libpwmd is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
13 Libpwmd is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Libpwmd. If not, see <http://www.gnu.org/licenses/>.
34 #include <sys/select.h>
36 #include <sys/types.h>
44 #include <gnutls/gnutls.h>
51 #ifdef HAVE_GETOPT_LONG
56 #include "getopt_long.h"
59 #ifdef HAVE_LIBREADLINE
60 #if defined(HAVE_READLINE_READLINE_H)
61 #include <readline/readline.h>
62 #elif defined(HAVE_READLINE_H)
64 #endif /* !defined(HAVE_READLINE_H) */
65 static int interactive_error
;
66 static int interactive
;
67 #endif /* HAVE_LIBREADLINE */
69 #ifdef HAVE_READLINE_HISTORY
70 #if defined(HAVE_READLINE_HISTORY_H)
71 #include <readline/history.h>
72 #elif defined(HAVE_HISTORY_H)
75 #endif /* HAVE_READLINE_HISTORY */
82 #define N_(msgid) gettext(msgid)
87 #define DEFAULT_STATUS_IGNORE "KEEPALIVE,STATE,GPGME,PASSPHRASE_INFO,PASSPHRASE_HINT"
88 #define DEFAULT_PIN_TIMEOUT 30
89 #define DEFAULT_PIN_TRIES 3
90 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
93 static int no_pinentry
;
95 static char *filename
;
98 static char *sign_keyid
;
100 static char *keyparams
;
101 static char *keyfile
;
102 static char *new_keyfile
;
103 static char *sign_keyfile
;
105 static int local_pin
;
106 static int inquirefd
;
110 static char **status_ignore
;
117 size_t size
; // from stat(2).
121 static gpg_error_t
finalize ();
122 static gpg_error_t
set_inquire (int fd
, const char *line
,
123 struct inquire_s
**result
);
124 static gpg_error_t
parse_dotcommand (const char *line
, char **result
,
125 size_t * len
, struct inquire_s
*inq
);
126 static gpg_error_t
open_command (char *line
);
129 show_error (pwm_t
*pwm
, gpg_error_t rc
, const char *str
)
133 int e
= pwmd_gnutls_error (pwm
, &tlsstr
);
136 fprintf(stderr
, "TLS: %s\n", tlsstr
);
138 fprintf (stderr
, "ERR %i: %s%s%s%s", rc
, gpg_strerror (rc
),
139 str
? ": " : "", str
? str
: "", str
? "" : "\n");
146 pwmd_free (new_keyfile
);
147 pwmd_free (sign_keyfile
);
148 keyfile
= new_keyfile
= sign_keyfile
= NULL
;
152 usage (const char *pn
, int status
)
154 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
155 N_("Usage: pwmc [options] [file]\n"
157 " a url string to connect to (%s, see below)\n"
158 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
159 " --connect-timeout <seconds>\n"
160 " seconds before connecting to a remote host fails (0=disabled, 120)\n"
161 " --socket-timeout <seconds>\n"
162 " seconds before a remote command fails (0=disabled, 300)\n"
165 " --ca-cert <filename>\n"
166 " certificate authority (CA) used to sign the server cert\n"
167 " --client-cert <filename>\n"
168 " client certificate to use for authentication\n"
169 " --client-key <filename>\n"
170 " key file used to protect the client certificate\n"
171 " --tls-priority <string>\n"
172 " compression, cipher and hash algorithm string\n"
173 " (SECURE256:SECURE192:SECURE128:-VERS-SSL3.0)\n"
175 " verify the hostname against the server certificate\n"
176 " --tls-fingerprint <string>\n"
177 " a SHA-256 hash of the server fingerprint to verify against\n"
181 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
182 " --identity, -i <filename>\n"
183 " the ssh identity file to use for authentication\n"
184 " --knownhosts, -k <filename>\n"
185 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
186 " --ssh-needs-passphrase\n"
187 " prompt for a passphrase for the SSH identity file\n"
188 " --ssh-passphrase-file <filename>\n"
189 " read the SSH private key passphrase from filename\n"
192 " do not lock the data file upon opening it\n"
193 " --lock-timeout <N>\n"
194 " time in tenths of a second to wait for a locked data file (50)\n"
195 " --name, -n <string>\n"
196 " set the client name\n"
197 " --pinentry <path>\n"
198 " the full path to the pinentry binary\n"
199 " --local-pinentry\n"
200 " force using a local pinentry\n"
202 " disable pinentry both remotely and locally\n"
203 " --ttyname, -y <path>\n"
204 " tty that pinentry will use\n"
205 " --ttytype, -t <string>\n"
206 " pinentry terminal type (default is $TERM)\n"
208 " pinentry display (default is $DISPLAY)\n"
209 " --lc-ctype <string>\n"
210 " locale setting for pinentry\n"
211 " --lc-messages <string>\n"
212 " locale setting for pinentry\n"
214 " number of pinentry tries before failing (3)\n"
215 " --timeout <seconds>\n"
216 " pinentry timeout\n"
217 " --inquire <COMMAND>\n"
218 " the specified command (with any options) uses a server inquire while\n"
219 " command data is read via the inquire file descriptor (stdin)\n"
220 " --inquire-line, -L <STRING>\n"
221 " the initial line to send (i.e., element path) before the inquire data\n"
222 " --inquire-fd <FD>\n"
223 " read inquire data from the specified file descriptor (stdin)\n"
224 " --inquire-file <filename>\n"
225 " read inquire data from the specified filename\n"
226 " --output-fd <FD>\n"
227 " redirect command output to the specified file descriptor\n"
229 " send the SAVE command before exiting\n"
230 " --passphrase-file <filename>\n"
231 " obtain the passphrase from the specified filename\n"
232 " --new-passphrase-file <filename>\n"
233 " obtain the passphrase to save with from the specified filename\n"
234 " --sign-passphrase-file <filename>\n"
235 " obtain the passphrase to sign with (symmetric) from the specified filename\n"
236 " --key-params <filename>\n"
237 " key parameters to use for key generation (pwmd default)\n"
238 " --keyid <recipient>[,<recipient>]\n"
239 " the public key ID to u\n"
240 " --sign-keyid <string>\n"
241 " the key ID to sign the data file with\n"
243 " use conventional encryption with optional signer(s) for new files\n"
245 " disable showing of status messages from the server\n"
246 " --status-fd <FD>\n"
247 " redirect status messages to the specified file descriptor\n"
248 " --status-ignore <string[,...]>\n"
249 " prevent parsing of the specified status message keywords\n"
251 " disable showing of extra messages (implies --no-status)\n"
252 #ifdef HAVE_LIBREADLINE
253 " --no-interactive\n"
254 " disable interactive mode\n"
258 #ifdef DEFAULT_PWMD_SOCKET
264 fprintf (status
== EXIT_FAILURE
? stderr
: stdout
,
266 "An optional url may be in the form of:\n"
267 " --url /path/to/socket\n"
268 " --url file://[path/to/socket]\n"
271 " --url ssh[46]://[username@]hostname[:port]\n"
272 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
276 " --url tls[46]://hostname[:port] --ca-cert filename --client-cert filename\n"
277 " --client-key filename\n"
279 #ifdef HAVE_LIBREADLINE
281 "Interactive mode is used when input is from a terminal.\n"
288 inquire_cb (void *user
, const char *keyword
, gpg_error_t rc
,
289 char **data
, size_t * size
)
291 struct inquire_s
*inq
= user
;
293 int is_newpassword
= 0;
303 if (!strcmp (keyword
, "PASSPHRASE"))
305 else if (!strcmp (keyword
, "SIGN_PASSPHRASE"))
307 else if (!strcmp (keyword
, "NEW_PASSPHRASE"))
309 #ifdef HAVE_LIBREADLINE
310 else if (!strcmp (keyword
, "KEYPARAM") && !interactive
)
313 else if (!strcmp (keyword
, "KEYPARAM"))
317 if (!keyparams
|| !*keyparams
)
318 return gpg_error (GPG_ERR_INV_PARAMETER
);
320 fd
= open (keyparams
, O_RDONLY
);
323 fprintf (stderr
, "%s: %s\n", keyparams
, strerror (errno
));
324 return gpg_error_from_syserror ();
327 rc
= set_inquire (fd
, NULL
, &inq
);
335 fprintf (stderr
, N_("Using file '%s' as %s.\n"), keyparams
, keyword
);
340 if ((is_password
&& !keyfile
) || (is_newpassword
&& !new_keyfile
)
341 || (sign
&& !sign_keyfile
))
346 /* Try to use the local pinentry between inquires (new/sign/passphrase).
347 * If --no-pinentry was specified then the passphrase is read from the
348 * terminal as usual. */
349 pwmd_getopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, &local
);
350 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, 1);
351 rc
= pwmd_password (pwm
, keyword
, &tmp
, &inq
->len
);
352 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local
);
353 if (rc
&& gpg_err_code (rc
) != GPG_ERR_EOF
)
356 pwmd_free (inq
->line
);
360 return gpg_error (GPG_ERR_EOF
);
362 else if ((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
)
363 || (sign
&& sign_keyfile
))
368 fd
= open (sign_keyfile
, O_RDONLY
);
370 fd
= open (is_password
|| sign
? keyfile
: new_keyfile
, O_RDONLY
);
375 fprintf (stderr
, "%s: %s\n", sign_keyfile
, strerror (errno
));
377 fprintf (stderr
, "%s: %s\n", is_newpassword
? new_keyfile
378 : keyfile
, strerror (errno
));
379 return gpg_error_from_syserror ();
382 rc
= set_inquire (fd
, NULL
, &inq
);
390 fprintf (stderr
, N_("Using keyfile '%s' as %s.\n"),
391 sign
? sign_keyfile
: is_newpassword
? new_keyfile
394 #ifdef HAVE_LIBREADLINE
395 else if ((!inq
->last_keyword
|| strcmp (keyword
, inq
->last_keyword
))
396 && interactive
&& inq
->fd
== STDIN_FILENO
)
400 ("%sPress CTRL-D to send the current line. Press twice to end. %s:\n"),
401 inq
->last_keyword
? "\n" : "", keyword
);
402 pwmd_free (inq
->last_keyword
);
403 inq
->last_keyword
= pwmd_strdup (keyword
);
407 /* The first part of the command data. */
413 return inq
->fd
== -1 ? gpg_error (GPG_ERR_EOF
) : 0;
416 *size
= read (inq
->fd
, inq
->line
, ASSUAN_LINELENGTH
);
420 return gpg_error (gpg_error_from_syserror ());
424 else if (inq
->fd
!= STDIN_FILENO
&&
425 (is_newpassword
|| is_password
|| sign
|| is_keyparam
))
433 if (((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
)
434 || (sign
&& sign_keyfile
) || (keyparams
&& is_keyparam
))
435 && *size
== inq
->size
)
436 return gpg_error (GPG_ERR_EOF
);
438 return *size
? 0 : gpg_error (GPG_ERR_EOF
);
442 status_msg_cb (void *data
, const char *line
)
444 char *p
= strchr (line
, ' ');
447 /* Ignore status messages specified by the client via --status-ignore. */
448 for (s
= status_ignore
; s
&& *s
; s
++)
450 char *tmp
= strchr (line
, ' ');
451 size_t len
= tmp
? strlen (line
) - strlen (tmp
) : strlen (line
);
453 if (!strncmp (line
, *s
, len
) && len
== strlen (*s
))
457 #ifdef HAVE_LIBREADLINE
458 if (interactive
&& !strncmp (line
, "XFER ", 5)
460 if (!strncmp (line
, "XFER ", 5)
462 && *line
!= '#' && p
&& strchr (p
, ' ') && *++p
)
464 char *p1
= strchr (p
, ' ');
465 int a
= strtol (p
, NULL
, 10);
467 if (isdigit (*p
) && p1
)
469 int b
= strtol (p1
, NULL
, 10);
471 int t
= a
&& b
? a
* 100 / b
: 0;
473 strncpy (l
, line
, strlen (line
) - strlen (p
) - 1);
474 fprintf (statusfp
, "\rS:%s %i/%i %i%%%s", l
, a
, b
, t
,
481 fprintf (statusfp
, "S:%s\n", line
);
483 #ifdef HAVE_LIBREADLINE
492 return pwmd_process (pwm
);
497 knownhost_cb (void *data
, const char *host
, const char *key
, size_t len
)
501 pwmd_strdup_printf (N_
502 ("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?\n"),
503 (char *) data
, host
, host
);
505 if (no_pinentry
&& !isatty (STDIN_FILENO
))
507 fprintf (stderr
, N_("Input is not from a terminal! Failing.\n"));
509 return GPG_ERR_ENOTTY
;
511 else if (no_pinentry
)
513 for (char *p
= buf
, len
= 0; *p
; p
++, len
++)
522 while (len
&& !isspace (*(--p
)))
531 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_PROMPT
, N_("Accept [y/N]:"));
535 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, buf
);
541 return pwmd_getpin (pwm
, NULL
, NULL
, NULL
, PWMD_PINENTRY_CONFIRM
);
545 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
547 is_remote_url (const char *str
)
550 return PWMD_SOCKET_LOCAL
;
553 if (strstr (str
, "ssh://") || strstr (str
, "ssh4://")
554 || strstr (str
, "ssh6://"))
555 return PWMD_SOCKET_SSH
;
559 if (strstr (str
, "tls://") || strstr (str
, "tls4://")
560 || strstr (str
, "tls6://"))
561 return PWMD_SOCKET_TLS
;
564 return PWMD_SOCKET_LOCAL
;
569 escape (const char *str
)
572 char *buf
= pwmd_malloc (ASSUAN_LINELENGTH
+ 1), *b
= buf
;
575 for (p
= str
; *p
; p
++, len
++)
577 if (len
== ASSUAN_LINELENGTH
)
621 free_inquire (struct inquire_s
*inq
)
626 pwmd_free (inq
->line
);
628 if (inq
->fd
!= -1 && inq
->fd
!= STDIN_FILENO
)
631 pwmd_free (inq
->last_keyword
);
635 /* When *result is not NULL it is updated to the new values and not
638 set_inquire (int fd
, const char *line
, struct inquire_s
**result
)
640 struct inquire_s inq
= { 0 };
641 struct stat st
= { 0 };
646 if (fstat (fd
, &st
) == -1)
647 return gpg_error_from_syserror ();
649 inq
.size
= st
.st_size
;
653 inq
.line
= pwmd_calloc (1, ASSUAN_LINELENGTH
);
655 return GPG_ERR_ENOMEM
;
659 char *s
= escape (line
);
663 pwmd_free (inq
.line
);
664 return GPG_ERR_ENOMEM
;
667 if (strlen (s
) >= ASSUAN_LINELENGTH
)
669 pwmd_free (inq
.line
);
671 return GPG_ERR_LINE_TOO_LONG
;
674 strncpy (inq
.line
, s
, ASSUAN_LINELENGTH
- 1);
675 inq
.len
= strlen (s
);
679 rc
= pwmd_setopt (pwm
, PWMD_OPTION_INQUIRE_TOTAL
,
680 st
.st_size
? st
.st_size
+ strlen (inq
.line
) : 0);
683 pwmd_free (inq
.line
);
688 *result
= pwmd_malloc (sizeof (struct inquire_s
));
691 if ((*result
)->fd
!= -1 && (*result
)->fd
!= STDIN_FILENO
)
692 close ((*result
)->fd
);
694 pwmd_free ((*result
)->line
);
695 (*result
)->line
= NULL
;
700 memcpy (*result
, &inq
, sizeof (struct inquire_s
));
701 memset (&inq
, 0, sizeof (struct inquire_s
));
705 #ifdef HAVE_LIBREADLINE
707 interactive_hook (void)
709 interactive_error
= process_cmd ();
711 if (interactive_error
)
712 rl_event_hook
= NULL
;
718 get_readline_char (FILE *fp
)
721 && (!strncmp (rl_line_buffer
, ".set passphrase-file ", 16)
722 || !strncmp (rl_line_buffer
, ".set new-passphrase-file ", 20)
723 || !strncmp (rl_line_buffer
, ".set sign-passphrase-file ", 21)))
724 rl_inhibit_completion
= 0;
725 else if (rl_line_buffer
726 && !strncmp (rl_line_buffer
, ".redir ", 7))
728 char *p
= strchr (rl_line_buffer
, ' ');
730 if (strchr (++p
, ' '))
731 rl_inhibit_completion
= 1;
733 rl_inhibit_completion
= 0;
735 else if (rl_line_buffer
736 && !strncmp (rl_line_buffer
, ".read ", 6))
738 char *p
= rl_line_buffer
+ 6;
740 if (strstr (p
, "--prefix "))
742 p
= strstr (p
, "--prefix ");
749 if (!p
|| strchr (p
, ' '))
750 rl_inhibit_completion
= 1;
752 rl_inhibit_completion
= 0;
755 rl_inhibit_completion
= 1;
765 ("------------------------------------------------------------\n"
766 "Elements are TAB delimited. Type HELP for protocol commands.\n"
767 "Type .help for pwmc commands. Press CTRL-D to quit.\n"
768 "------------------------------------------------------------\n"));
773 parse_arg (const char *src
, char *dst
, size_t len
)
779 for (; s
&& *s
&& *s
!= ' ' && n
< len
; s
++, n
++)
787 parse_opt (char **line
, const char *opt
, gpg_error_t
* rc
)
789 static char result
[ASSUAN_LINELENGTH
] = { 0 }, *r
= result
;
790 char *s
= strstr (*line
, opt
);
800 size_t rlen
= strlen (opt
);
804 while (*p
&& *p
== ' ')
810 for (; *p
&& len
< sizeof (result
) - 1; p
++, rlen
++)
812 if (isspace (*p
) && !quote
)
815 if (*p
== '\"' && lastc
!= '\\')
828 if (len
>= sizeof (result
) - 1)
829 *rc
= GPG_ERR_LINE_TOO_LONG
;
834 while (*p
&& *p
== ' ')
845 read_command (const char *line
, char **result
, size_t * len
)
850 struct inquire_s
*inq
= NULL
;
851 char *p
= (char *) line
;
852 const char *prefix
= parse_opt (&p
, "--prefix", &rc
);
853 char filebuf
[ASSUAN_LINELENGTH
];
862 while (*p
&& isspace (*p
))
865 file
= parse_arg (p
, filebuf
, sizeof (filebuf
));
868 p
+= strlen (file
) + 1;
870 while (*p
&& isspace (*p
))
882 ("Usage: .read [--prefix <string>] <filename> <command> [args]\n"));
885 ("Use '\\' to escape special characters in the --prefix (\\t = TAB, \\\\ = \\)\n"));
889 fd
= open (file
, O_RDONLY
);
891 return gpg_error_from_syserror ();
893 rc
= set_inquire (fd
, prefix
&& *prefix
? prefix
: NULL
, &inq
);
900 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, "%s", p
);
906 redir_command (const char *line
)
908 const char *p
= line
;
910 gpg_error_t rc
= GPG_ERR_SYNTAX
;
912 struct inquire_s
*inq
= NULL
;
915 char filebuf
[ASSUAN_LINELENGTH
];
919 file
= parse_arg (p
, filebuf
, sizeof (filebuf
));
922 p
+= strlen (file
) + 1;
924 while (*p
&& isspace (*p
))
934 fprintf (stderr
, N_("Usage: .redir <filename> <command> [args]\n"));
938 fd
= open (file
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600);
940 return gpg_error_from_syserror ();
942 #ifdef HAVE_LIBREADLINE
943 rc
= set_inquire (interactive
? STDIN_FILENO
: inquirefd
, NULL
, &inq
);
945 rc
= set_inquire (inquirefd
, NULL
, &inq
);
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
;
967 help_command (const char *line
)
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"
974 " .open <filename>\n"
975 " open the specified filename losing any changes to the current one\n"
977 " .read [--prefix <string>] <filename> <command> [args]\n"
978 " obtain data from the specified filename for an inquire command\n"
980 " .set help | <name> [<value>]\n"
981 " set option <name> to <value>\n"
984 " write changes of the file to disk\n"
987 " change the passphrase of a data file\n"
990 " this help text\n"));
995 open_command (char *line
)
997 struct inquire_s
*inq
= NULL
;
998 const char *file
= line
;
1002 while (file
&& isspace (*file
))
1005 if (!file
|| !*file
)
1007 fprintf (stderr
, N_("Usage: .open <filename>\n"));
1008 return GPG_ERR_SYNTAX
;
1011 #ifdef HAVE_LIBREADLINE
1012 if (interactive
|| !quiet
)
1016 fprintf (stderr
, N_("Opening data file \"%s\" ...\n"), file
);
1018 #ifdef HAVE_LIBREADLINE
1019 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1021 rc
= set_inquire (-1, NULL
, &inq
);
1026 pwmd_getopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, &local
);
1030 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1032 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, 1);
1035 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1038 rc
= pwmd_open (pwm
, file
, inquire_cb
, inq
);
1040 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local
);
1042 #ifdef HAVE_LIBREADLINE
1048 if (!rc
&& file
!= filename
)
1050 pwmd_free (filename
);
1051 filename
= pwmd_strdup (file
);
1058 set_command (const char *line
)
1061 char name
[256] = { 0 };
1062 char value
[512] = { 0 };
1065 const char *p
= line
;
1067 while (p
&& *p
&& isspace (*p
))
1070 namep
= parse_arg (p
, name
, sizeof (name
));
1071 if (!namep
|| !*namep
)
1073 fprintf (stderr
, N_("Usage: .set help | <name> [<value>]\n"));
1074 return GPG_ERR_SYNTAX
;
1077 p
+= strlen (namep
);
1078 while (p
&& *p
&& isspace (*p
))
1081 valuep
= parse_arg (p
, value
, sizeof (value
));
1083 if (!strcmp (name
, "passphrase-file") || !strcmp (name
, "new-passphrase-file")
1084 || !strcmp (name
, "sign-passphrase-file"))
1086 int is_newkeyfile
= 1;
1087 int sign
= !strcmp (name
, "sign-passphrase-file");
1089 if (!strcmp (name
, "passphrase-file") || sign
)
1094 pwmd_free (new_keyfile
);
1099 pwmd_free (sign_keyfile
);
1100 sign_keyfile
= NULL
;
1104 pwmd_free (keyfile
);
1111 new_keyfile
= pwmd_strdup (value
);
1113 sign_keyfile
= pwmd_strdup (value
);
1115 keyfile
= pwmd_strdup (value
);
1117 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1119 else if (!local_pin
&& !no_pinentry
)
1123 pwmd_socket_type (pwm
, &t
);
1124 if (t
== PWMD_SOCKET_LOCAL
)
1125 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1128 else if (!strcmp(name
, "pinentry-timeout"))
1131 int n
= strtol(valuep
, &e
, 10);
1134 return gpg_error (GPG_ERR_INV_VALUE
);
1137 n
= DEFAULT_PIN_TIMEOUT
;
1139 rc
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, n
);
1141 else if (!strcmp (name
, "help"))
1145 ("Set a libpwmd or pwmc option. The option name and optional value is space\n"
1146 "delimited. When no value is specified the option is unset.\n\n"
1147 "passphrase-file [<filename>]\n"
1148 " set or unset the file to be used when a passphrase is required (*)\n"
1150 "new-passphrase-file [<filename>]\n"
1151 " set or unset the file to be used when a new passphrase is required (*)\n"
1153 "sign-passphrase-file [<filename>]\n"
1154 " set or unset the file to be used when a passphrase is required for\n"
1155 " signing (symmetric) (*)\n"
1157 "pinentry-timeout <seconds>\n"
1158 " the amount of seconds before pinentry gives up waiting for input\n"
1160 "* = the next protocol command will unset this value\n"
1164 rc
= GPG_ERR_UNKNOWN_OPTION
;
1170 do_save_passwd_command (const char *line
, int save
)
1172 struct inquire_s
*inq
= NULL
;
1176 #ifdef HAVE_LIBREADLINE
1177 rc
= set_inquire (interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
1179 rc
= set_inquire (-1, NULL
, &inq
);
1184 pwmd_getopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, &local
);
1186 if (new_keyfile
|| keyfile
|| sign_keyfile
)
1188 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
1190 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, 1);
1193 rc
= pwmd_setopt (pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1198 rc
= pwmd_save (pwm
, line
, inquire_cb
, inq
);
1200 rc
= pwmd_passwd (pwm
, line
, inquire_cb
, inq
);
1203 pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local
);
1205 #ifdef HAVE_LIBREADLINE
1215 save_command (const char *line
)
1217 return do_save_passwd_command (line
, 1);
1221 parse_dotcommand (const char *line
, char **result
,
1222 size_t * len
, struct inquire_s
*inq
)
1224 const char *p
= line
;
1227 if (!strncmp (p
, ".read", 5))
1228 rc
= read_command (p
+ 5, result
, len
);
1229 else if (!strncmp (p
, ".redir", 6))
1230 rc
= redir_command (p
+ 6);
1231 else if (!strncmp (p
, ".help", 5))
1232 rc
= help_command (p
+ 5);
1233 else if (!strncmp (p
, ".open", 5))
1234 rc
= open_command ((char *)p
+ 5);
1235 else if (!strncmp (p
, ".set", 4))
1236 rc
= set_command (p
+ 4);
1237 else if (!strncmp (p
, ".save", 5))
1238 rc
= do_save_passwd_command (p
+ 5, 1);
1239 else if (!strncmp (p
, ".passwd", 7))
1240 rc
= do_save_passwd_command (p
+ 7, 0);
1243 rc
= pwmd_command (pwm
, result
, len
, inquire_cb
, inq
, "%s", line
);
1244 #ifdef HAVE_LIBREADLINE
1249 #ifdef HAVE_LIBREADLINE
1253 if (!rc
&& !strncasecmp (line
, "RESET", 5))
1255 pwmd_free (filename
);
1263 #ifdef HAVE_LIBREADLINE
1264 #ifdef HAVE_READLINE_HISTORY
1266 add_history_item (const char *line
)
1268 HIST_ENTRY
**list
, *p
= NULL
;
1271 list
= history_list ();
1272 for (i
= 0; list
&& list
[i
]; i
++)
1274 if (!strcmp (list
[i
]->line
, line
))
1285 p
= remove_history (i
);
1286 s
= free_history_entry (p
);
1298 struct inquire_s
*inq
= NULL
;
1301 rc
= process_cmd ();
1305 rc
= set_inquire (STDIN_FILENO
, NULL
, &inq
);
1310 N_("WARNING: interactive mode doesn't use secure memory!\n"));
1312 rl_event_hook
= &interactive_hook
;
1313 rl_getc_function
= get_readline_char
;
1314 rl_set_keyboard_input_timeout (100000);
1319 char *result
= NULL
;
1324 snprintf (buf
, sizeof (buf
), "pwmc%s%s> ",
1325 filename
? ":" : "", filename
? filename
: "");
1326 line
= readline (buf
);
1327 if (interactive_error
)
1330 rc
= interactive_error
;
1340 if (gpg_err_code (rc
) != GPG_ERR_CANCELED
&&
1341 gpg_err_code (rc
) != GPG_ERR_EOF
)
1342 fprintf (stderr
, "ERR %i: %s\n", rc
, gpg_strerror (rc
));
1352 #ifdef HAVE_READLINE_HISTORY
1353 add_history_item (line
);
1355 rc
= parse_dotcommand (line
, &result
, &len
, inq
);
1361 if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
1362 (void) pwmd_command (pwm
, &tmp
, NULL
, NULL
, NULL
,
1363 "GETINFO last_error");
1365 show_error (pwm
, rc
, tmp
);
1368 else if (result
&& len
)
1369 printf ("%s%s", result
, result
[len
- 1] != '\n' ? "\n" : "");
1383 #ifdef HAVE_LIBREADLINE
1390 fprintf (stderr
, "\n");
1398 ("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1399 p
= fgets (buf
, sizeof (buf
), stdin
);
1413 return GPG_ERR_CANCELED
;
1417 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
1418 "CLEARCACHE %s", filename
);
1422 interactive_hook ();
1438 if (save
&& !filename
)
1442 ("No filename was specified on the command line. Aborting.\n"));
1443 return GPG_ERR_CANCELED
;
1446 if (save
&& filename
)
1449 pwmd_strdup_printf ("%s %s%s %s%s %s",
1450 symmetric
? "--symmetric" : "",
1451 keyid
? "--keyid=" : "",
1453 sign_keyid
? "--sign-keyid=" : "",
1454 sign_keyid
? sign_keyid
: "",
1455 keyparams
? "--inquire-keyparam" : "");
1457 #ifdef HAVE_LIBREADLINE
1458 if (!quiet
|| interactive
)
1464 fprintf (stderr
, "\n");
1465 fprintf (stderr
, N_("Saving changes ...\n"));
1468 rc
= save_command (args
);
1472 #ifdef HAVE_LIBREADLINE
1474 return rc
? rc
: quit
? 0 : GPG_ERR_CANCELED
;
1481 parse_status_ignore (char *str
)
1486 for (p
= status_ignore
; p
&& *p
; p
++)
1489 pwmd_free (status_ignore
);
1490 status_ignore
= NULL
;
1494 while ((s
= strsep (&str
, ",")))
1496 p
= pwmd_realloc (status_ignore
, (n
+ 2) * sizeof (char *));
1497 p
[n
++] = pwmd_strdup (s
);
1504 main (int argc
, char *argv
[])
1509 char command
[ASSUAN_LINELENGTH
], *p
= NULL
;
1510 char *result
= NULL
;
1512 char *pinentry_path
= NULL
;
1513 char *display
= NULL
, *tty
= NULL
, *ttytype
= NULL
;
1514 char *lcctype
= NULL
, *lcmessages
= NULL
;
1515 int outfd
= STDOUT_FILENO
;
1516 FILE *outfp
= stdout
;
1517 FILE *inquirefp
= stdin
;
1518 int show_status
= 1;
1519 char *clientname
= "pwmc";
1520 char *inquire
= NULL
;
1521 char *inquire_line
= NULL
;
1524 int use_ssh_agent
= 1;
1525 char *knownhosts
= NULL
;
1526 char *identity
= NULL
;
1527 int needs_passphrase
= 0;
1528 char *ssh_passphrase_file
= NULL
;
1531 char *cacert
= NULL
;
1532 char *clientcert
= NULL
;
1533 char *clientkey
= NULL
;
1536 char *tls_fingerprint
= NULL
;
1538 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1539 pwmd_socket_t socktype
;
1540 long socket_timeout
= 300;
1541 int connect_timeout
= 120;
1543 #ifdef HAVE_LIBREADLINE
1544 int no_interactive
= 0;
1546 int lock_on_open
= 1;
1547 long lock_timeout
= 50;
1550 /* The order is important. */
1553 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1554 OPT_SOCKET_TIMEOUT
, OPT_CONNECT_TIMEOUT
,
1557 OPT_USE_SSH_AGENT
, OPT_IDENTITY
, OPT_KNOWNHOSTS
, OPT_SSH_NEEDS_PASSPHRASE
,
1558 OPT_SSH_PASSPHRASE_FILE
,
1561 OPT_CACERT
, OPT_CLIENTCERT
, OPT_CLIENTKEY
, OPT_PRIORITY
, OPT_VERIFY
,
1564 OPT_URL
, OPT_LOCAL
, OPT_TTYNAME
, OPT_TTYTYPE
, OPT_DISPLAY
, OPT_LC_CTYPE
,
1565 OPT_LC_MESSAGES
, OPT_TIMEOUT
, OPT_TRIES
, OPT_PINENTRY
, OPT_KEYFILE
,
1566 OPT_PASSPHRASE_FILE
, OPT_NEW_KEYFILE
, OPT_NEW_PASSPHRASE_FILE
,
1567 OPT_SIGN_KEYFILE
, OPT_SIGN_PASSPHRASE_FILE
, OPT_NOLOCK
, OPT_LOCK_TIMEOUT
,
1568 OPT_SAVE
, OPT_OUTPUT_FD
, OPT_INQUIRE
, OPT_INQUIRE_FD
, OPT_INQUIRE_FILE
,
1569 OPT_INQUIRE_LINE
, OPT_NO_STATUS
, OPT_STATUS_IGNORE
, OPT_STATUSFD
, OPT_NAME
,
1570 OPT_VERSION
, OPT_HELP
, OPT_KEYID
, OPT_SIGN_KEYID
, OPT_SYMMETRIC
,
1571 OPT_KEYPARAMS
, OPT_NO_PINENTRY
, OPT_QUIET
,
1572 #ifdef HAVE_LIBREADLINE
1576 const struct option long_opts
[] = {
1577 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1578 {"socket-timeout", 1, 0, 0},
1579 {"connect-timeout", 1, 0, 0},
1583 {"no-ssh-agent", 0, 0, 0},
1584 {"identity", 1, 0, 'i'},
1585 {"knownhosts", 1, 0, 'k'},
1586 {"ssh-needs-passphrase", 0, 0, 0},
1587 {"ssh-passphrase-file", 1, 0, 0},
1590 {"ca-cert", 1, 0, 0},
1591 {"client-cert", 1, 0, 0},
1592 {"client-key", 1, 0, 0},
1593 {"tls-priority", 1, 0, 0},
1594 {"tls-verify", 0, 0, 0},
1595 {"tls-fingerprint", 1, 0, 0},
1598 {"local-pinentry", 0, 0},
1599 {"ttyname", 1, 0, 'y'},
1600 {"ttytype", 1, 0, 't'},
1601 {"display", 1, 0, 'd'},
1602 {"lc-ctype", 1, 0, 0},
1603 {"lc-messages", 1, 0, 0},
1604 {"timeout", 1, 0, 0},
1606 {"pinentry", 1, 0, 0},
1607 {"key-file", 1, 0, 0},
1608 {"passphrase-file", 1, 0, 0},
1609 {"new-key-file", 1, 0, 0},
1610 {"new-passphrase-file", 1, 0, 0},
1611 {"sign-key-file", 1, 0, 0},
1612 {"sign-passphrase-file", 1, 0, 0},
1613 {"no-lock", 0, 0, 0},
1614 {"lock-timeout", 1, 0, 0},
1615 {"save", 0, 0, 'S'},
1616 {"output-fd", 1, 0, 0},
1617 {"inquire", 1, 0, 0},
1618 {"inquire-fd", 1, 0, 0},
1619 {"inquire-file", 1, 0, 0},
1620 {"inquire-line", 1, 0, 'L'},
1621 {"no-status", 0, 0, 0},
1622 {"status-ignore", 1, 0, 0},
1623 {"status-fd", 1, 0, 0},
1624 {"name", 1, 0, 'n'},
1625 {"version", 0, 0, 0},
1628 {"sign-keyid", 1, 0, 0},
1629 {"symmetric", 0, 0, 0},
1630 {"key-params", 1, 0, 0},
1631 {"no-pinentry", 0, 0, 0},
1633 #ifdef HAVE_LIBREADLINE
1634 {"no-interactive", 0, 0},
1639 const char *optstring
= "L:y:t:d:P:I:Sn:i:k:s";
1641 const char *optstring
= "L:y:t:d:P:I:Sn:s";
1646 setlocale (LC_ALL
, "");
1647 bindtextdomain ("libpwmd", LOCALEDIR
);
1650 tries
= DEFAULT_PIN_TRIES
;
1651 inquirefd
= STDIN_FILENO
;
1652 statusfd
= STDERR_FILENO
;
1654 tmp
= pwmd_strdup (DEFAULT_STATUS_IGNORE
);
1655 parse_status_ignore (tmp
);
1659 getopt_long (argc
, argv
, optstring
, long_opts
, &opt_index
)) != -1)
1663 /* Handle long options without a short option part. */
1667 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1668 case OPT_SOCKET_TIMEOUT
:
1669 socket_timeout
= strtol (optarg
, &p
, 10);
1671 case OPT_CONNECT_TIMEOUT
:
1672 connect_timeout
= strtol (optarg
, &p
, 10);
1676 case OPT_USE_SSH_AGENT
:
1679 case OPT_SSH_NEEDS_PASSPHRASE
:
1680 needs_passphrase
= 1;
1682 case OPT_SSH_PASSPHRASE_FILE
:
1683 ssh_passphrase_file
= optarg
;
1690 case OPT_CLIENTCERT
:
1691 clientcert
= optarg
;
1703 tls_fingerprint
= optarg
;
1713 case OPT_PASSPHRASE_FILE
:
1714 keyfile
= pwmd_strdup (optarg
);
1716 case OPT_NEW_KEYFILE
:
1717 case OPT_NEW_PASSPHRASE_FILE
:
1718 new_keyfile
= pwmd_strdup (optarg
);
1720 case OPT_SIGN_KEYFILE
:
1721 case OPT_SIGN_PASSPHRASE_FILE
:
1722 sign_keyfile
= pwmd_strdup (optarg
);
1727 case OPT_LOCK_TIMEOUT
:
1728 lock_timeout
= strtol (optarg
, &p
, 10);
1737 lcctype
= pwmd_strdup (optarg
);
1739 case OPT_LC_MESSAGES
:
1740 lcmessages
= pwmd_strdup (optarg
);
1743 timeout
= strtol (optarg
, &p
, 10);
1746 tries
= strtol (optarg
, &p
, 10);
1749 inquire
= escape (optarg
);
1751 case OPT_INQUIRE_FD
:
1752 inquirefd
= strtol (optarg
, &p
, 10);
1755 inquirefp
= fdopen (inquirefd
, "r");
1757 err (EXIT_FAILURE
, "%i", inquirefd
);
1760 case OPT_INQUIRE_FILE
:
1761 inquirefd
= open (optarg
, O_RDONLY
);
1762 if (inquirefd
== -1)
1763 err (EXIT_FAILURE
, "%s", optarg
);
1764 inquirefp
= fdopen (inquirefd
, "r");
1767 outfd
= strtol (optarg
, &p
, 10);
1770 outfp
= fdopen (outfd
, "w");
1772 err (EXIT_FAILURE
, "%i", outfd
);
1779 statusfd
= strtol (optarg
, &p
, 10);
1782 statusfp
= fdopen (statusfd
, "w");
1784 err (EXIT_FAILURE
, "%i", statusfd
);
1787 case OPT_STATUS_IGNORE
:
1788 parse_status_ignore (optarg
);
1791 printf ("%s (pwmc)\n\n"
1792 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016\n"
1794 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1795 "Compile-time features:\n"
1796 #ifdef HAVE_LIBREADLINE
1811 #ifdef WITH_PINENTRY
1826 "\n", PACKAGE_STRING
, PACKAGE_BUGREPORT
);
1827 exit (EXIT_SUCCESS
);
1829 pinentry_path
= optarg
;
1832 usage (argv
[0], EXIT_SUCCESS
);
1836 case OPT_SIGN_KEYID
:
1837 sign_keyid
= optarg
;
1843 case OPT_NO_PINENTRY
:
1846 #ifdef HAVE_LIBREADLINE
1847 case OPT_NO_INTERACTIVE
:
1852 usage (argv
[0], EXIT_FAILURE
);
1857 fprintf (stderr
, N_("%s: invalid argument for option '--%s'\n"),
1858 argv
[0], long_opts
[opt_index
].name
);
1859 usage (argv
[0], EXIT_FAILURE
);
1868 knownhosts
= optarg
;
1872 inquire_line
= optarg
;
1887 clientname
= optarg
;
1890 usage (argv
[0], EXIT_FAILURE
);
1894 #ifdef HAVE_LIBREADLINE
1895 if (isatty (STDIN_FILENO
) && !inquire
&& !inquire_line
&& !no_interactive
)
1900 rc
= pwmd_new (clientname
, &pwm
);
1904 filename
= argv
[optind
] ? pwmd_strdup (argv
[optind
]) : NULL
;
1905 rc
= pwmd_setopt (pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
1909 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCAL_PINENTRY
, local_pin
);
1913 pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TRIES
, tries
);
1915 fprintf (stderr
, N_("Connecting ...\n"));
1917 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1918 socktype
= is_remote_url (url
);
1919 if (socktype
!= PWMD_SOCKET_LOCAL
)
1922 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
1923 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, connect_timeout
);
1928 if (socktype
== PWMD_SOCKET_SSH
)
1931 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_CB
, knownhost_cb
);
1935 rc
= pwmd_setopt (pwm
, PWMD_OPTION_KNOWNHOST_DATA
, clientname
);
1939 if (!getenv ("SSH_AUTH_SOCK") || identity
)
1942 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_AGENT
, use_ssh_agent
);
1946 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_NEEDS_PASSPHRASE
,
1951 if (ssh_passphrase_file
)
1956 if (stat (ssh_passphrase_file
, &st
) == -1)
1958 rc
= gpg_error_from_syserror ();
1959 fprintf(stderr
, "%s: %s\n", ssh_passphrase_file
,
1964 result
= pwmd_calloc (1, st
.st_size
+1);
1967 rc
= GPG_ERR_ENOMEM
;
1971 fd
= open (ssh_passphrase_file
, O_RDONLY
);
1974 len
= read (fd
, result
, st
.st_size
);
1975 if (len
== st
.st_size
)
1976 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SSH_PASSPHRASE
, result
);
1978 rc
= gpg_error_from_syserror ();
1983 rc
= gpg_error_from_syserror ();
1991 fprintf(stderr
, "%s: %s\n", ssh_passphrase_file
,
1997 rc
= pwmd_connect (pwm
, url
, identity
, knownhosts
);
2003 rc
= pwmd_setopt (pwm
, PWMD_OPTION_TLS_VERIFY
, tls_verify
);
2007 rc
= pwmd_connect (pwm
, url
, clientcert
, clientkey
, cacert
, prio
,
2013 rc
= pwmd_connect (pwm
, url
);
2015 rc
= pwmd_connect (pwm
, url
);
2021 fprintf (stderr
, N_("Connected.\n"));
2024 #if defined (WITH_SSH) || defined (WITH_GNUTLS)
2025 rc
= pwmd_setopt (pwm
, PWMD_OPTION_SOCKET_TIMEOUT
, socket_timeout
);
2032 rc
= pwmd_command (pwm
, NULL
, NULL
, NULL
, NULL
,
2033 "OPTION LOCK-TIMEOUT=%li", lock_timeout
);
2040 rc
= pwmd_setopt (pwm
, PWMD_OPTION_LOCK_ON_OPEN
, 1);
2045 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DESC
, NULL
, NULL
);
2051 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, timeout
);
2058 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_PATH
, pinentry_path
);
2065 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_DISPLAY
, display
);
2072 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TTY
, tty
);
2079 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_TERM
, ttytype
);
2086 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_CTYPE
, lcctype
);
2093 rc
= pwmd_setopt (pwm
, PWMD_OPTION_PINENTRY_LC_MESSAGES
, lcmessages
);
2100 rc
= pwmd_setopt (pwm
, PWMD_OPTION_STATUS_CB
, status_msg_cb
);
2107 rc
= open_command (filename
);
2112 #ifdef HAVE_LIBREADLINE
2115 rc
= do_interactive ();
2123 struct inquire_s
*inq
= NULL
;
2125 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2127 rc
= pwmd_command (pwm
, &result
, &len
, inquire_cb
, inq
, "%s", inquire
);
2133 if (fcntl (STDIN_FILENO
, F_SETFL
, O_NONBLOCK
) == -1)
2135 rc
= gpg_error_from_errno (errno
);
2143 rc
= process_cmd ();
2148 n
= read (STDIN_FILENO
, command
, sizeof (command
)-1);
2151 if (errno
== EAGAIN
)
2157 rc
= gpg_error_from_errno (errno
);
2168 if (!p
|| !*p
|| !strcasecmp (p
, "BYE"))
2172 struct inquire_s
*inq
= NULL
;
2173 rc
= set_inquire (inquirefd
, inquire_line
, &inq
);
2176 rc
= parse_dotcommand (command
, &result
, &len
, inq
);
2186 fwrite (result
, 1, result
[len
- 1] == 0 ? len
- 1 : len
, outfp
);
2194 else if (gpg_err_code (rc
) == GPG_ERR_BAD_DATA
)
2195 (void) pwmd_command (pwm
, &result
, NULL
, NULL
, NULL
,
2196 "GETINFO last_error");
2198 #ifdef HAVE_LIBREADLINE
2201 wipememory (command
, 0, sizeof (command
));
2204 show_error (pwm
, rc
, result
);
2210 pwmd_free (filename
);
2211 parse_status_ignore (NULL
);
2212 if (connected
&& !quiet
)
2213 fprintf (stderr
, N_("Connection closed.\n"));
2215 exit (rc
? EXIT_FAILURE
: EXIT_SUCCESS
);