1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
3 Copyright (C) 2007-2010 Ben Kibbey <bjk@luxsci.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110-1301 USA
31 #include <sys/select.h>
33 #include <sys/types.h>
43 #ifdef HAVE_GETOPT_LONG
48 #include "getopt_long.h"
51 #ifdef HAVE_LIBREADLINE
52 # if defined(HAVE_READLINE_READLINE_H)
53 # include <readline/readline.h>
54 # elif defined(HAVE_READLINE_H)
55 # include <readline.h>
56 # endif /* !defined(HAVE_READLINE_H) */
57 static int interactive_error
;
58 static int interactive
;
59 #endif /* HAVE_LIBREADLINE */
61 #ifdef HAVE_READLINE_HISTORY
62 # if defined(HAVE_READLINE_HISTORY_H)
63 # include <readline/history.h>
64 # elif defined(HAVE_HISTORY_H)
67 #endif /* HAVE_READLINE_HISTORY */
70 #define N_(msgid) gettext(msgid)
74 #define DEFAULT_PORT 22
76 static int in_keyfile
;
77 static int no_pinentry
;
79 static char *filename
;
82 static int force_save
;
85 static char *password
;
100 static gpg_error_t
finalize();
102 static void show_error(gpg_error_t error
)
104 fprintf(stderr
, "ERR %i %s\n", gpg_err_code(error
), pwmd_strerror(error
));
107 static void usage(const char *pn
, int status
)
109 fprintf(status
== EXIT_FAILURE
? stderr
: stdout
, N_(
110 "Read a PWMD protocol command from standard input.\n\n"
111 "Usage: pwmc [options] [file]\n"
114 " pinentry method (0=pwmd, 1=libpwmd, 2=pwmd async, "
119 " --host, -h <hostname>\n"
120 " connect to the specified hostname\n"
123 " alterate port (22)\n"
125 " --user <username>\n"
126 " SSH username (default is the invoking user)\n"
129 " disable SSH agent (enabled when SSH_AGENT_PID is set)\n"
131 " --identity, -i <filename>\n"
132 " SSH identity file (if not using the SSH agent)\n"
134 " --known-hosts, -k <filename>\n"
135 " known hosts file (~/.ssh/known_hosts)\n"
137 " --get-hostkey, -g\n"
138 " retrieve the remote SSH host key and exit\n"
141 " try connecting via IPv4 only\n"
144 " try connecting via IPv6 only\n"
148 " a url string to parse (see below)\n"
151 " disable showing of status messages from the server\n"
153 " --name, -n <string>\n"
154 " set the client name\n"
156 " --socket <filename>\n"
157 " local socket to connect to (~/.pwmd/socket)\n"
159 " --passphrase, -P <string>\n"
160 " passphrase to use (disables pinentry use)\n"
162 " --key-file <filename>\n"
163 " obtain the passphrase from the specified filename\n"
166 " the passphrase is base64 encoded\n"
168 " --timeout <seconds>\n"
169 " pinentry timeout\n"
172 " number of pinentry tries before failing (3)\n"
175 " disable pinentry both remotely and locally\n"
177 " --pinentry <path>\n"
178 " the full path to the pinentry binary (server default)\n"
180 " --ttyname, -y <path>\n"
181 " tty that pinentry will use\n"
183 " --ttytype, -t <string>\n"
184 " pinentry terminal type (default is $TERM)\n"
187 " pinentry display (default is $DISPLAY)\n"
189 " --lc-ctype <string>\n"
190 " locale setting for pinentry\n"
192 " --lc-messages <string>\n"
193 " locale setting for pinentry\n"
195 " --local-pinentry\n"
196 " force using a local pinentry\n"
199 " use a shell like interface to pwmd (allows more than one command)\n"
201 " --output-fd <FD>\n"
202 " redirect command output to the specified file descriptor\n"
204 " --inquire <COMMAND>\n"
205 " the specified command (with any options) uses a server inquire while\n"
206 " command data is read via the inquire file descriptor (stdin)\n"
208 " --inquire-fd <FD>\n"
209 " read inquire data from the specified file descriptor (stdin)\n"
211 " --inquire-line, -L <STRING>\n"
212 " the initial line to send (i.e., element path) before the inquire data\n"
214 " --cipher <string>\n"
215 " the cipher to use when saving (see pwmd(1))\n"
218 " send the SAVE command before exiting\n"
221 " like --save but always ask for a passphrase\n"
223 " --iterations, -I <N>\n"
224 " encrypt with the specified number of iterations\n"
228 fprintf(status
== EXIT_FAILURE
? stderr
: stdout
, N_(
230 "A url string (specified with --url) may be in the form of:\n"
231 " file://[path/to/socket]\n"
233 " ssh[46]://[username@]hostname[:port],identity[,known_hosts] --no-ssh-agent\n"
235 " ssh[46]://[username@]hostname[:port][,,known_hosts]\n"
241 static gpg_error_t
inquire_cb(void *user
, const char *cmd
, gpg_error_t rc
,
242 char **data
, size_t *len
)
244 struct inquire_s
*inq
= user
;
254 "------------------------------------------------------------------------------\n"
255 "Press CTRL-D to end. Press twice on a non-empty line. Pressing ENTER after\n"
256 "each line during the inquire will send that line including the newline\n"
258 "------------------------------------------------------------------------------\n"
262 /* The first part of the command data. */
270 *len
= read(inq
->fd
, inq
->line
, ASSUAN_LINELENGTH
);
273 return gpg_error_from_syserror();
278 return *len
? 0 : GPG_ERR_EOF
;
281 static int status_msg_cb(void *data
, const char *line
)
283 char *p
= strchr(line
, ' ');
285 if (p
&& strchr(p
, ' ') && *++p
) {
286 char *p1
= strchr(p
, ' ');
292 int t
= a
&& b
? a
*100/b
: 0;
294 strncpy(l
, line
, strlen(line
)-strlen(p
)-1);
295 fprintf(stderr
, "\r%s %i/%i %i%%%s", l
, a
, b
, t
, a
== b
? "\n" : "");
301 fprintf(stderr
, "%s\n", line
);
306 static gpg_error_t
process_cmd(pwm_t
*pwm
, char **result
, int input
, int once
)
315 pwmd_fd_t pfds
[nfds
];
316 struct timeval tv
= {0, 50000};
319 fprintf(stderr
, ".");
322 rc
= pwmd_get_fds(pwm
, pfds
, &nfds
);
328 s
= pwmd_process(pwm
, &rc
, result
);
332 for (i
= 0, n
= 0; i
< nfds
; i
++) {
333 FD_SET(pfds
[i
].fd
, &rfds
);
334 n
= pfds
[i
].fd
> n
? pfds
[i
].fd
: n
;
338 FD_SET(STDIN_FILENO
, &rfds
);
340 nfds
= select(n
+1, &rfds
, NULL
, NULL
, &tv
);
343 rc
= gpg_error_from_errno(errno
);
347 if (input
&& FD_ISSET(STDIN_FILENO
, &rfds
)) {
352 s
= pwmd_process(pwm
, &rc
, result
);
356 } while (s
== ASYNC_PROCESS
);
359 fprintf(stderr
, "\n");
364 static gpg_error_t
get_password(char **result
, pwmd_pinentry_t w
, int echo
)
366 char buf
[LINE_MAX
] = {0}, *p
;
367 struct termios told
, tnew
;
372 if (!isatty(STDIN_FILENO
)) {
373 fprintf(stderr
, N_("Input is not from a terminal! Failing.\n"));
374 return GPG_ERR_ENOTTY
;
378 if (tcgetattr(STDIN_FILENO
, &told
) == -1)
379 return gpg_error_from_syserror();
381 memcpy(&tnew
, &told
, sizeof(struct termios
));
382 tnew
.c_lflag
&= ~(ECHO
);
383 tnew
.c_lflag
|= ICANON
|ECHONL
;
385 if (tcsetattr(STDIN_FILENO
, TCSANOW
, &tnew
) == -1) {
388 tcsetattr(STDIN_FILENO
, TCSANOW
, &told
);
389 return gpg_error_from_errno(n
);
394 case PWMD_PINENTRY_OPEN
:
395 fprintf(stderr
, N_("Password for %s: "), filename
);
397 case PWMD_PINENTRY_OPEN_FAILED
:
398 fprintf(stderr
, N_("Invalid password. Password for %s: "), filename
);
400 case PWMD_PINENTRY_SAVE
:
401 fprintf(stderr
, N_("New password for %s: "), filename
);
403 case PWMD_PINENTRY_SAVE_CONFIRM
:
404 fprintf(stderr
, N_("Confirm password: "));
410 if ((p
= fgets(buf
, sizeof(buf
), stdin
)) == NULL
) {
411 tcsetattr(STDIN_FILENO
, TCSANOW
, &told
);
416 tcsetattr(STDIN_FILENO
, TCSANOW
, &told
);
420 return GPG_ERR_CANCELED
;
423 p
[strlen(p
) - 1] = 0;
426 key
= pwmd_strdup_printf("%s", p
);
427 memset(&buf
, 0, sizeof(buf
));
430 return GPG_ERR_ENOMEM
;
438 static gpg_error_t
knownhost_cb(void *data
, const char *host
, const char *key
,
442 char *buf
= pwmd_strdup_printf(N_("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?"), (char *)data
, host
, host
);
444 if (no_pinentry
&& !isatty(STDIN_FILENO
)) {
445 fprintf(stderr
, N_("Input is not from a terminal! Failing.\n"));
447 return GPG_ERR_ENOTTY
;
449 else if (no_pinentry
) {
450 for (char *p
= buf
, len
= 0; *p
; p
++, len
++) {
457 while (!isspace(*(--p
)));
464 fprintf(stderr
, "%s\n\n", buf
);
470 fprintf(stderr
, N_("Trust this connection [y/N]: "));
472 rc
= get_password(&result
, PWMD_PINENTRY_CONFIRM
, 1);
477 if (!result
|| !*result
|| *result
== 'n' || *result
== 'N') {
478 if (result
&& *result
)
481 return GPG_ERR_NOT_CONFIRMED
;
484 if ((*result
== 'y' || *result
== 'Y') && *(result
+1) == 0) {
491 rc
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TITLE
, buf
);
497 return pwmd_getpin(pwm
, NULL
, NULL
, PWMD_PINENTRY_CONFIRM
);
500 static int is_remote_url(const char *str
)
502 if (str
&& (strstr(str
, "file://") || strstr(str
, "local://")))
509 static char *escape(const char *str
)
512 char *buf
= pwmd_malloc(ASSUAN_LINELENGTH
+1), *b
= buf
;
515 for (p
= str
; *p
; p
++, len
++) {
516 if (len
== ASSUAN_LINELENGTH
)
557 static gpg_error_t
send_inquire(int fd
, const char *command
, const char *line
)
559 struct inquire_s inq
;
563 if (fstat(fd
, &st
) == -1)
564 return gpg_error_from_syserror();
566 memset(&inq
, 0, sizeof(inq
));
568 inq
.line
= pwmd_calloc(1, ASSUAN_LINELENGTH
);
572 return GPG_ERR_ENOMEM
;
575 char *s
= escape(line
);
577 strncpy(inq
.line
, s
, ASSUAN_LINELENGTH
-1);
582 rc
= pwmd_setopt(pwm
, PWMD_OPTION_INQUIRE_TOTAL
,
583 st
.st_size
? st
.st_size
+strlen(inq
.line
) : 0);
588 rc
= pwmd_inquire(pwm
, command
, inquire_cb
, &inq
);
593 #ifdef HAVE_LIBREADLINE
594 static int interactive_hook(void)
596 interactive_error
= process_cmd(pwm
, NULL
, 0, 1);
598 if (interactive_error
)
599 rl_event_hook
= NULL
;
604 static void print_help()
607 "------------------------------------------------------------------------------\n"
608 "Type HELP for protocol command help (since pwmd 2.19). Commands which use a\n"
609 "server inquire need a non-protocol command to send the data. These commands\n"
610 "including any options are:\n"
612 " INQUIRE <command> - to read from the terminal\n"
613 " INQUIRE_FILE <filename> <command> - to read the specified filename\n"
615 "Elements are TAB delimited. Press CTRL-V then TAB to insert from the prompt.\n"
617 "Press CTRL-D to quit.\n"
618 "------------------------------------------------------------------------------\n"
622 static gpg_error_t
do_interactive()
624 gpg_error_t rc
= process_cmd(pwm
, NULL
, 0, 1);
629 fprintf(stderr
, N_("WARNING: interactive mode doesn't use secure memory!\n"));
632 rl_event_hook
= &interactive_hook
;
633 rl_set_keyboard_input_timeout(100000);
639 line
= readline("pwm> ");
641 if (interactive_error
)
642 return interactive_error
;
650 if (rc
!= GPG_ERR_CANCELED
&& rc
!= GPG_ERR_EOF
)
651 fprintf(stderr
, "ERR %i: %s\n", rc
, pwmd_strerror(rc
));
660 #ifdef HAVE_READLINE_HISTORY
664 /* INQUIRE <COMMAND [options ...]> */
665 if (!strncasecmp(line
, "inquire ", 8))
666 rc
= send_inquire(STDIN_FILENO
, line
+8, NULL
);
667 /* INQUIRE_FILE <FILENAME> <COMMAND [options ...]> */
668 else if (!strncasecmp(line
, "inquire_file ", 13)) {
669 char *p
= strchr(line
+13, ' ');
670 char *f
= p
? line
+13 : NULL
;
673 if (!f
|| !*f
|| !*p
) {
674 fprintf(stderr
, N_("Syntax error. Usage: INQUIRE_FILE <filename> <command>\n"));
679 f
[strlen(f
) - strlen(p
++)] = 0;
680 fd
= open(f
, O_RDONLY
);
683 fprintf(stderr
, "%s\n", strerror(errno
));
688 rc
= send_inquire(fd
, p
, NULL
);
693 rc
= pwmd_command(pwm
, &result
, line
);
698 fprintf(stderr
, "ERR %i: %s\n", rc
, pwmd_strerror(rc
));
699 else if (result
&& *result
)
700 printf("%s%s", result
, result
[strlen(result
)-1] != '\n' ? "\n" : "");
710 static gpg_error_t
finalize()
715 #ifdef HAVE_LIBREADLINE
716 if (!force_save
&& interactive
) {
720 fprintf(stderr
, "\n");
723 fprintf(stderr
, N_("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
724 p
= fgets(buf
, sizeof(buf
), stdin
);
736 return GPG_ERR_CANCELED
;
740 rc
= pwmd_command(pwm
, NULL
, "CLEARCACHE %s", filename
);
760 if (save
&& !filename
) {
761 fprintf(stderr
, N_("No filename was specified on the command line. Aborting.\n"));
762 return GPG_ERR_CANCELED
;
765 if (save
&& filename
) {
766 fprintf(stderr
, "\n");
767 fprintf(stderr
, N_("Saving changes ...\n"));
770 rc
= pwmd_setopt(pwm
, PWMD_OPTION_ITERATIONS
, iter
);
777 rc
= pwmd_setopt(pwm
, PWMD_OPTION_CIPHER
, cipher
);
783 if ((local_pin
|| no_pinentry
) && !keyfile
) {
787 rc
= pwmd_command(pwm
, NULL
, "ISCACHED %s", filename
);
789 if (rc
&& rc
!= GPG_ERR_NOT_FOUND
&&
790 rc
!= GPG_ERR_ENOENT
)
797 rc
= pwmd_getpin(pwm
, filename
, &p1
, PWMD_PINENTRY_SAVE
);
802 rc
= pwmd_getpin(pwm
, filename
, &password
,
803 PWMD_PINENTRY_SAVE_CONFIRM
);
811 rc
= get_password(&p1
, PWMD_PINENTRY_SAVE
, 0);
816 rc
= get_password(&password
, PWMD_PINENTRY_SAVE_CONFIRM
, 0);
826 if ((p1
|| password
) && ((!p1
&& password
) || (!password
&& p1
) ||
827 strcmp(p1
, password
))) {
837 rc
= pwmd_setopt(pwm
, PWMD_OPTION_PASSPHRASE
, password
);
847 rc
= pwmd_command(pwm
, NULL
, "CLEARCACHE %s", filename
);
853 rc
= pwmd_setopt(pwm
, PWMD_OPTION_PASSPHRASE
, NULL
);
862 struct inquire_s inq
;
864 memset(&inq
, 0, sizeof(inq
));
865 inq
.fd
= open(keyfile
, O_RDONLY
);
868 rc
= gpg_error_from_syserror();
872 inq
.line
= pwmd_calloc(1, ASSUAN_LINELENGTH
);
880 rc
= pwmd_save_inquire(pwm
, inquire_cb
, &inq
);
892 rc
= pwmd_save2(pwm
);
895 rc
= pwmd_save_async(pwm
);
898 rc
= pwmd_save_async2(pwm
);
902 if (!rc
&& method
>= 2)
903 rc
= process_cmd(pwm
, NULL
, 0, 0);
906 #if defined(WITH_PINENTRY) && defined(WITH_TCP)
908 rc
= pwmd_save2(pwm
);
917 return rc
? rc
: quit
? 0 : GPG_ERR_CANCELED
;
922 int main(int argc
, char *argv
[])
928 char *socketpath
= NULL
;
929 char command
[ASSUAN_LINELENGTH
], *p
;
930 int ret
= EXIT_SUCCESS
;
932 char *pinentry_path
= NULL
;
933 char *display
= NULL
, *tty
= NULL
, *ttytype
= NULL
, *lcctype
= NULL
,
935 int outfd
= STDOUT_FILENO
;
936 FILE *outfp
= stdout
;
937 int inquirefd
= STDIN_FILENO
;
938 FILE *inquirefp
= stdin
;
940 char *clientname
= "pwmc";
941 char *inquire
= NULL
;
942 char *inquire_line
= NULL
;
947 int port
= DEFAULT_PORT
;
948 char *username
= NULL
;
950 char *known_hosts
= NULL
;
952 int prot
= PWMD_IP_ANY
;
953 int use_ssh_agent
= 1;
959 int lock_on_open
= 1;
963 char *url_string
= NULL
;
964 /* The order is important. */
970 OPT_HOST
, OPT_PORT
, OPT_IDENTITY
, OPT_KNOWN_HOSTS
, OPT_USER
,
971 OPT_GET_HOSTKEY
, OPT_IPV4
, OPT_IPV6
, OPT_USE_SSH_AGENT
,
973 OPT_URL
, OPT_LOCAL
, OPT_FORCE_SAVE
, OPT_TTYNAME
, OPT_TTYTYPE
,
974 OPT_DISPLAY
, OPT_LC_CTYPE
, OPT_LC_MESSAGES
, OPT_TIMEOUT
, OPT_TRIES
,
975 OPT_PINENTRY
, OPT_PASSPHRASE
, OPT_KEYFILE
, OPT_BASE64
, OPT_SOCKET
,
976 OPT_NOLOCK
, OPT_SAVE
, OPT_ITERATIONS
, OPT_OUTPUT_FD
, OPT_INQUIRE
,
977 OPT_INQUIRE_FD
, OPT_INQUIRE_LINE
, OPT_NO_STATUS
, OPT_NAME
,
978 OPT_VERSION
, OPT_HELP
, OPT_CIPHER
, OPT_NO_PINENTRY
,
979 #ifdef HAVE_LIBREADLINE
983 const struct option long_opts
[] = {
985 { "debug", 1, 0, 0 },
988 { "host", 1, 0, 'h' },
989 { "port", 1, 0, 'p' },
990 { "identity", 1, 0, 'i' },
991 { "known-hosts", 1, 0, 'k' },
992 { "user", 1, 0, 'u' },
993 { "get-hostkey", 0, 0, 'g' },
994 { "ipv4", 0, 0, '4' },
995 { "ipv6", 0, 0, '6' },
996 { "no-ssh-agent", 0, 0, 0 },
999 { "local-pinentry", 0, 0 },
1000 { "force-save", 0, 0 },
1001 { "ttyname", 1, 0, 'y' },
1002 { "ttytype", 1, 0, 't' },
1003 { "display", 1, 0, 'd' },
1004 { "lc-ctype", 1, 0, 0 },
1005 { "lc-messages", 1, 0, 0 },
1006 { "timeout", 1, 0, 0 },
1007 { "tries", 1, 0, 0 },
1008 { "pinentry", 1, 0, 0 },
1009 { "passphrase", 1, 0, 'P' },
1010 { "key-file", 1, 0, 0 },
1011 { "base64", 0, 0, 0 },
1012 { "socket", 1, 0, 0 },
1013 { "no-lock", 0, 0, 0 },
1014 { "save", 0, 0, 'S' },
1015 { "iterations", 1, 0, 'I' },
1016 { "output-fd", 1, 0, 0 },
1017 { "inquire", 1, 0, 0 },
1018 { "inquire-fd", 1, 0, 0 },
1019 { "inquire-line", 1, 0, 'L' },
1020 { "no-status", 0, 0, 0 },
1021 { "name", 1, 0, 'n' },
1022 { "version", 0, 0, 0 },
1023 { "help", 0, 0, 0 },
1024 { "cipher", 1, 0, 0 },
1025 { "no-pinentry", 0, 0, 0 },
1026 #ifdef HAVE_LIBREADLINE
1027 { "interactive", 0, 0 },
1032 const char *optstring
= "L:46h:p:i:k:u:gy:t:d:P:I:Sn:";
1034 const char *optstring
= "L:y:t:d:P:I:Sn:";
1039 setlocale(LC_ALL
, "");
1040 bindtextdomain("libpwmd", LOCALEDIR
);
1043 #ifdef HAVE_LIBREADLINE
1044 if (!strcmp(basename(argv
[0]), "pwmsh"))
1050 while ((opt
= getopt_long(argc
, argv
, optstring
, long_opts
, &opt_index
)) != -1) {
1052 /* Handle long options without a short option part. */
1054 switch (opt_index
) {
1057 method
= atoi(optarg
);
1064 case OPT_USE_SSH_AGENT
:
1078 url_string
= optarg
;
1083 case OPT_FORCE_SAVE
:
1084 save
= force_save
= 1;
1087 lcctype
= pwmd_strdup(optarg
);
1089 case OPT_LC_MESSAGES
:
1090 lcmessages
= pwmd_strdup(optarg
);
1093 timeout
= atoi(optarg
);
1096 tries
= atoi(optarg
);
1097 local_tries
= tries
;
1100 socketpath
= pwmd_strdup(optarg
);
1105 case OPT_INQUIRE_FD
:
1106 inquirefd
= atoi(optarg
);
1107 inquirefp
= fdopen(inquirefd
, "r");
1110 pwmd_free(password
);
1111 err(EXIT_FAILURE
, "%i", inquirefd
);
1115 outfd
= atoi(optarg
);
1116 outfp
= fdopen(outfd
, "w");
1119 pwmd_free(password
);
1120 err(EXIT_FAILURE
, "%i", outfd
);
1127 pwmd_free(password
);
1128 printf("%s (pwmc)\n%s\n\n"
1129 "Compile-time features:\n"
1135 #ifdef WITH_PINENTRY
1150 #ifdef HAVE_LIBREADLINE
1156 , PACKAGE_STRING
, PACKAGE_BUGREPORT
);
1159 pinentry_path
= optarg
;
1162 usage(argv
[0], EXIT_SUCCESS
);
1166 case OPT_NO_PINENTRY
:
1169 #ifdef HAVE_LIBREADLINE
1170 case OPT_INTERACTIVE
:
1175 usage(argv
[0], EXIT_FAILURE
);
1187 host
= pwmd_strdup(optarg
);
1190 port
= atoi(optarg
);
1193 ident
= pwmd_strdup(optarg
);
1196 username
= pwmd_strdup(optarg
);
1199 known_hosts
= pwmd_strdup(optarg
);
1206 inquire_line
= optarg
;
1221 iter
= strtol(optarg
, NULL
, 10);
1225 password
= pwmd_strdup(optarg
);
1226 memset(optarg
, 0, strlen(optarg
));
1229 clientname
= optarg
;
1232 pwmd_free(password
);
1233 usage(argv
[0], EXIT_FAILURE
);
1237 #ifdef HAVE_LIBREADLINE
1238 if (interactive
&& !isatty(STDIN_FILENO
)) {
1239 pwmd_free(password
);
1240 usage(argv
[0], EXIT_FAILURE
);
1248 if (host
&& !get
&& !ident
) {
1249 pwmd_free(password
);
1250 usage(argv
[0], EXIT_FAILURE
);
1254 pwmd_free(password
);
1255 usage(argv
[0], EXIT_FAILURE
);
1262 filename
= argv
[optind
];
1264 pwm
= pwmd_new(clientname
);
1270 if (host
|| is_remote_url(url_string
)) {
1271 #ifndef WITH_PINENTRY
1278 if (prot
!= PWMD_IP_ANY
) {
1279 error
= pwmd_setopt(pwm
, PWMD_OPTION_IP_VERSION
, prot
);
1285 error
= pwmd_setopt(pwm
, PWMD_OPTION_KNOWNHOST_CB
, knownhost_cb
);
1290 error
= pwmd_setopt(pwm
, PWMD_OPTION_KNOWNHOST_DATA
, clientname
);
1295 if (!getenv("SSH_AGENT_PID") || ident
)
1298 error
= pwmd_setopt(pwm
, PWMD_OPTION_SSH_AGENT
, use_ssh_agent
);
1303 fprintf(stderr
, N_("Connecting ...\n"));
1310 error
= pwmd_get_hostkey_async(pwm
, host
, port
);
1313 errx(EXIT_FAILURE
, "%s: %s", host
, pwmd_strerror(error
));
1315 error
= process_cmd(pwm
, &hostkey
, 0, 0);
1320 printf("%s", hostkey
);
1322 pwmd_free(password
);
1328 error
= pwmd_connect_url_async(pwm
, url_string
);
1330 error
= pwmd_ssh_connect_async(pwm
, host
, port
, ident
, username
,
1336 error
= process_cmd(pwm
, NULL
, 0, 0);
1346 error
= pwmd_get_hostkey(pwm
, host
, port
, &hostkey
);
1351 printf("%s", hostkey
);
1353 pwmd_free(password
);
1359 error
= pwmd_connect_url(pwm
, url_string
);
1361 error
= pwmd_ssh_connect(pwm
, host
, port
, ident
, username
, known_hosts
);
1372 error
= pwmd_connect_url(pwm
, url_string
);
1374 error
= pwmd_connect(pwm
, socketpath
);
1382 fprintf(stderr
, N_("Connected.\n"));
1384 error
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TITLE
, NULL
);
1385 error
= pwmd_socket_type(pwm
, &s
);
1391 if (s
== PWMD_SOCKET_SSH
&& force_save
&& !local_pin
) {
1392 error
= GPG_ERR_WRONG_KEY_USAGE
;
1398 error
= pwmd_command(pwm
, &result
, "VERSION");
1406 pwmd_free(password
);
1408 usage(argv
[0], EXIT_FAILURE
);
1412 if (filename
&& lock_on_open
) {
1413 error
= pwmd_setopt(pwm
, PWMD_OPTION_LOCK_ON_OPEN
, 1);
1420 error
= pwmd_setopt(pwm
, PWMD_OPTION_BASE64
, 1);
1427 error
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, timeout
);
1434 error
= pwmd_setopt(pwm
, PWMD_OPTION_NO_PINENTRY
, 1);
1440 if ((no_pinentry
|| local_pin
) && filename
&& !keyfile
&& !password
) {
1441 error
= pwmd_command(pwm
, NULL
, "ISCACHED %s", filename
);
1443 if (error
== GPG_ERR_NOT_FOUND
) {
1445 if (try++ == local_tries
)
1449 pwmd_free(password
);
1456 error
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, 0);
1458 error
= pwmd_getpin(pwm
, filename
, &password
,
1459 try > 1 ? PWMD_PINENTRY_OPEN_FAILED
: PWMD_PINENTRY_OPEN
);
1465 password
= pwmd_strdup("");
1468 error
= get_password(&password
,try > 1 ? PWMD_PINENTRY_OPEN_FAILED
: PWMD_PINENTRY_OPEN
, 0);
1474 error
= pwmd_setopt(pwm
, PWMD_OPTION_PASSPHRASE
, password
);
1482 else if (error
&& error
!= GPG_ERR_ENOENT
)
1486 error
= pwmd_setopt(pwm
, PWMD_OPTION_PASSPHRASE
, password
);
1492 if (pinentry_path
) {
1493 error
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_PATH
, pinentry_path
);
1500 error
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_DISPLAY
, display
);
1507 error
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TTY
, tty
);
1514 error
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TERM
, ttytype
);
1521 error
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_LC_CTYPE
, lcctype
);
1528 error
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_LC_MESSAGES
,
1536 error
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TRIES
, tries
);
1544 error
= pwmd_setopt(pwm
, PWMD_OPTION_STATUS_CB
, status_msg_cb
);
1552 fprintf(stderr
, N_("Opening data file \"%s\" ...\n"), filename
);
1555 if (keyfile
&& (!local_pin
|| host
|| is_remote_url(url_string
))) {
1556 struct inquire_s inq
;
1558 memset(&inq
, 0, sizeof(inq
));
1559 inq
.fd
= open(keyfile
, O_RDONLY
);
1562 error
= gpg_error_from_syserror();
1566 inq
.line
= pwmd_calloc(1, ASSUAN_LINELENGTH
);
1569 error
= GPG_ERR_ENOMEM
;
1574 error
= pwmd_open_inquire(pwm
, filename
, inquire_cb
, &inq
);
1576 pwmd_free(inq
.line
);
1588 error
= pwmd_open(pwm
, filename
);
1591 error
= pwmd_open2(pwm
, filename
);
1594 error
= pwmd_open_async(pwm
, filename
);
1598 error
= pwmd_open_async2(pwm
, filename
);
1602 if (error
&& (local_pin
|| no_pinentry
) &&
1603 error
== GPG_ERR_INV_PASSPHRASE
)
1604 goto local_password
;
1610 error
= process_cmd(pwm
, &result
, 0, 0);
1612 #ifdef WITH_PINENTRY
1614 error
= pwmd_open2(pwm
, filename
);
1617 error
= pwmd_open(pwm
, filename
);
1619 if (error
&& (local_pin
|| no_pinentry
) &&
1620 error
== GPG_ERR_INV_PASSPHRASE
)
1621 goto local_password
;
1631 #ifdef HAVE_LIBREADLINE
1636 error
= do_interactive();
1642 int fd
= fileno(inquirefp
);
1645 error
= gpg_error_from_syserror();
1649 error
= send_inquire(fd
, inquire
, inquire_line
);
1654 fcntl(STDIN_FILENO
, F_SETFL
, O_NONBLOCK
);
1658 error
= process_cmd(pwm
, NULL
, 1, 0);
1663 n
= read(STDIN_FILENO
, command
, sizeof(command
));
1666 if (errno
== EAGAIN
)
1669 error
= gpg_error_from_errno(errno
);
1683 if (strcasecmp(p
, "BYE") == 0)
1686 error
= pwmd_command(pwm
, &result
, command
);
1692 fwrite(result
, 1, strlen(result
), outfp
);
1699 pwmd_free(password
);
1707 memset(command
, 0, sizeof(command
));
1717 fprintf(stderr
, N_("Connection closed.\n"));
1720 pwmd_free(socketpath
);