1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
3 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012
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>
47 #ifdef HAVE_GETOPT_LONG
52 #include "getopt_long.h"
55 #ifdef HAVE_LIBREADLINE
56 #include <readline/readline.h>
57 #include <readline/history.h>
59 static int interactive_error
;
60 static int interactive
;
68 #define N_(msgid) gettext(msgid)
72 #define DEFAULT_PORT 22
73 #define DEFAULT_PIN_TRIES 3
74 #define FINISH(rc) (gpg_err_source(rc) == GPG_ERR_SOURCE_UNKNOWN) \
77 static int no_pinentry
;
79 static char *filename
;
81 static int force_save
;
82 static int no_passphrase
;
85 static char *sign_keygrip
;
86 static char *keyparams
;
87 static char *password
;
89 static char *new_keyfile
;
90 static unsigned long s2k_count
;
91 static uint64_t iterations
;
92 static int iterations_arg
;
101 size_t size
; // from stat(2).
105 static gpg_error_t
finalize();
106 static gpg_error_t
set_inquire(int fd
, const char *line
,
107 struct inquire_s
**result
);
108 static gpg_error_t
parse_dotcommand(const char *line
, char **result
,
109 size_t *len
, struct inquire_s
*inq
);
110 static gpg_error_t
open_command(const char *line
);
112 static gpg_error_t
get_password(char **result
, pwmd_pinentry_t w
, int echo
);
115 static void show_error(gpg_error_t error
)
117 fprintf(stderr
, "ERR %i %s\n", error
, gpg_strerror(error
));
120 static void usage(const char *pn
, int status
)
122 fprintf(status
== EXIT_FAILURE
? stderr
: stdout
, N_(
123 "Read a PWMD protocol command from standard input.\n\n"
124 "Usage: pwmc [options] [file]\n"
126 " a url string to connect to (see below)\n"
129 " disable SSH agent use (enabled when SSH_AUTH_SOCK is set)\n"
130 " --identity, -i <filename>\n"
131 " the ssh identity file to use for authentication\n"
132 " --knownhosts, -k <filename>\n"
133 " the ssh knownhosts file to use (~/.ssh/knownhosts)\n"
134 " --ssh-timeout <seconds>\n"
135 " timeout before a remote command fails (0=disabled, default)\n"
136 " --ssh-keepalive <seconds>\n"
137 " interval to send a keepalive to the remote server (0=disabled, default)\n"
140 " --ca-cert <filename>\n"
141 " certificate authority (CA) used to sign the server cert\n"
142 " --client-cert <filename>\n"
143 " client certificate to use for authentication\n"
144 " --client-key <filename>\n"
145 " key file used to protect the client certificate\n"
146 " --tls-priority <string>\n"
147 " compression, cipher and hash algorithm string (SECURE256)\n"
149 " verify the hostname against the server certificate\n"
152 " do not lock the data file upon opening it\n"
153 " --lock-timeout <N>\n"
154 " time in tenths of a second to wait for a locked data file\n"
156 " disable showing of status messages from the server\n"
157 " --name, -n <string>\n"
158 " set the client name\n"
160 " do not require a passphrase when saving a new file\n"
161 " --keygrip <string>\n"
162 " the hex string of the keygrip to save to\n"
163 " --sign-keygrip <string>\n"
164 " the hex string of the keygrip to sign with\n"
165 " --key-file <filename>\n"
166 " obtain the passphrase from the specified filename\n"
167 " --new-key-file <filename>\n"
168 " obtain the passphrase to save with from the specified filename\n"
170 " the number of times to hash the passphrase for a new file\n"
171 " --cipher-iterations <N>\n"
172 " the number of times to encrypt the XML data (N+1)\n"
173 " --timeout <seconds>\n"
174 " pinentry timeout\n"
176 " number of pinentry tries before failing (3)\n"
178 " disable pinentry both remotely and locally\n"
179 " --pinentry <path>\n"
180 " the full path to the pinentry binary (server default)\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"
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 " --local-pinentry\n"
192 " force using a local pinentry\n"
193 #ifdef HAVE_LIBREADLINE
195 " use a shell like interface to pwmd (allows more than one command)\n"
197 " --output-fd <FD>\n"
198 " redirect command output to the specified file descriptor\n"
199 " --inquire <COMMAND>\n"
200 " the specified command (with any options) uses a server inquire while\n"
201 " command data is read via the inquire file descriptor (stdin)\n"
202 " --inquire-fd <FD>\n"
203 " read inquire data from the specified file descriptor (stdin)\n"
204 " --inquire-file <filename>\n"
205 " read inquire data from the specified filename\n"
206 " --inquire-line, -L <STRING>\n"
207 " the initial line to send (i.e., element path) before the inquire data\n"
208 " --cipher <string>\n"
209 " the cipher to use when saving (see pwmd(1))\n"
211 " send the SAVE command before exiting\n"
212 " --key-params <string>\n"
213 " the key parameters to use when saving a new file (pwmd default)\n"
215 " like --save but always ask for a passphrase\n"
218 fprintf(status
== EXIT_FAILURE
? stderr
: stdout
, N_(
220 "An optional url may be in the form of:\n"
221 " --url /path/to/socket\n"
222 " --url file://[path/to/socket]\n"
225 " --url ssh[46]://[username@]hostname[:port]\n"
226 " --no-ssh-agent -i identity_file --url ssh[46]://[username@]hostname[:port]\n"
230 " --url tls[46]://hostname[:port]\n"
236 static gpg_error_t
inquire_cb(void *user
, const char *keyword
, gpg_error_t rc
,
237 char **data
, size_t *size
)
239 struct inquire_s
*inq
= user
;
241 int is_newpassword
= 0;
249 if (!strcmp(keyword
, "PASSPHRASE"))
251 else if (!strcmp(keyword
, "NEW_PASSPHRASE"))
253 #ifdef HAVE_LIBREADLINE
254 else if (!strcmp(keyword
, "KEYPARAM") && !interactive
) {
256 else if (!strcmp(keyword
, "KEYPARAM")) {
258 if (!keyparams
|| !*keyparams
)
259 return gpg_error(GPG_ERR_INV_PARAMETER
);
262 *size
= strlen(keyparams
);
263 return gpg_error(GPG_ERR_EOF
);
266 if ((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
)) {
267 int fd
= open(is_password
? keyfile
: new_keyfile
, O_RDONLY
);
270 fprintf(stderr
, "%s: %s\n", is_newpassword
? new_keyfile
: keyfile
,
272 return gpg_error_from_syserror();
275 rc
= set_inquire(fd
, NULL
, &inq
);
281 fprintf(stderr
, N_("Using keyfile '%s' as %s.\n"),
282 is_newpassword
? new_keyfile
: keyfile
, keyword
);
284 if (!new_keyfile
|| is_newpassword
) {
287 pwmd_socket_type(pwm
, &t
);
288 pwmd_setopt(pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
289 if (!no_pinentry
&& t
== PWMD_SOCKET_LOCAL
)
290 pwmd_setopt(pwm
, PWMD_OPTION_NO_PINENTRY
, 0);
293 else if (is_password
&& !keyfile
) {
296 rc
= pwmd_password(pwm
, keyword
, &tmp
, &inq
->len
);
297 if (rc
&& gpg_err_code(rc
) != GPG_ERR_EOF
)
300 pwmd_free(inq
->line
);
304 return gpg_error(GPG_ERR_EOF
);
306 #ifdef HAVE_LIBREADLINE
307 else if (!inq
->header
&& interactive
) {
309 "Press CTRL-D to send the current line. Press twice to end. %s:\n"), keyword
);
314 /* The first part of the command data. */
319 return inq
->fd
== -1 ? gpg_error(GPG_ERR_EOF
) : 0;
322 *size
= read(inq
->fd
, inq
->line
, ASSUAN_LINELENGTH
);
325 return gpg_error(gpg_error_from_syserror());
330 if (((is_newpassword
&& new_keyfile
) || (is_password
&& keyfile
))
331 && *size
== inq
->size
)
332 return gpg_error(GPG_ERR_EOF
);
334 return *size
? 0 : gpg_error(GPG_ERR_EOF
);
337 static int status_msg_cb(void *data
, const char *line
)
339 char *p
= strchr(line
, ' ');
341 if (!strcmp(line
, "KEEPALIVE"))
344 if (*line
!= '#' && p
&& strchr(p
, ' ') && *++p
) {
345 char *p1
= strchr(p
, ' ');
346 int a
= strtol(p
, NULL
, 10);
348 if (isdigit(*p
) && p1
) {
349 int b
= strtol(p1
, NULL
, 10);
351 int t
= a
&& b
? a
*100/b
: 0;
353 strncpy(l
, line
, strlen(line
)-strlen(p
)-1);
354 fprintf(stderr
, "\r%s %i/%i %i%%%s", l
, a
, b
, t
, a
== b
? "\n" : "");
360 fprintf(stderr
, "%s\n", line
);
366 static gpg_error_t
process_cmd()
368 return pwmd_process(pwm
);
372 static gpg_error_t
get_password(char **result
, pwmd_pinentry_t w
, int echo
)
374 char buf
[LINE_MAX
] = {0}, *p
;
375 struct termios told
, tnew
;
380 if (!isatty(STDIN_FILENO
)) {
381 fprintf(stderr
, N_("Input is not from a terminal! Failing.\n"));
382 return GPG_ERR_ENOTTY
;
386 if (tcgetattr(STDIN_FILENO
, &told
) == -1)
387 return gpg_error_from_syserror();
389 memcpy(&tnew
, &told
, sizeof(struct termios
));
390 tnew
.c_lflag
&= ~(ECHO
);
391 tnew
.c_lflag
|= ICANON
|ECHONL
;
393 if (tcsetattr(STDIN_FILENO
, TCSANOW
, &tnew
) == -1) {
396 tcsetattr(STDIN_FILENO
, TCSANOW
, &told
);
397 return gpg_error_from_errno(n
);
402 case PWMD_PINENTRY_OPEN
:
403 fprintf(stderr
, N_("Password for %s: "), filename
);
405 case PWMD_PINENTRY_OPEN_FAILED
:
406 fprintf(stderr
, N_("Invalid password. Password for %s: "), filename
);
408 case PWMD_PINENTRY_SAVE
:
409 fprintf(stderr
, N_("New password for %s: "), filename
);
411 case PWMD_PINENTRY_SAVE_CONFIRM
:
412 fprintf(stderr
, N_("Confirm password: "));
418 if ((p
= fgets(buf
, sizeof(buf
), stdin
)) == NULL
) {
419 tcsetattr(STDIN_FILENO
, TCSANOW
, &told
);
424 tcsetattr(STDIN_FILENO
, TCSANOW
, &told
);
428 return GPG_ERR_CANCELED
;
431 p
[strlen(p
) - 1] = 0;
434 key
= pwmd_strdup_printf("%s", p
);
435 memset(&buf
, 0, sizeof(buf
));
438 return GPG_ERR_ENOMEM
;
445 static gpg_error_t
knownhost_cb(void *data
, const char *host
, const char *key
,
449 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
);
451 if (no_pinentry
&& !isatty(STDIN_FILENO
)) {
452 fprintf(stderr
, N_("Input is not from a terminal! Failing.\n"));
454 return GPG_ERR_ENOTTY
;
456 else if (no_pinentry
) {
457 for (char *p
= buf
, len
= 0; *p
; p
++, len
++) {
464 while (!isspace(*(--p
)));
471 fprintf(stderr
, "%s\n\n", buf
);
477 fprintf(stderr
, N_("Trust this connection [y/N]: "));
479 rc
= get_password(&result
, PWMD_PINENTRY_CONFIRM
, 1);
484 if (!result
|| !*result
|| *result
== 'n' || *result
== 'N') {
485 if (result
&& *result
)
488 return GPG_ERR_NOT_CONFIRMED
;
491 if ((*result
== 'y' || *result
== 'Y') && *(result
+1) == 0) {
498 rc
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_DESC
, buf
);
504 return pwmd_getpin(pwm
, NULL
, NULL
, NULL
, PWMD_PINENTRY_CONFIRM
);
508 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
509 static pwmd_socket_t
is_remote_url(const char *str
)
512 return PWMD_SOCKET_LOCAL
;
515 if (strstr(str
, "ssh://") || strstr(str
, "ssh4://")
516 || strstr(str
, "ssh6://"))
517 return PWMD_SOCKET_SSH
;
521 if (strstr(str
, "tls://") || strstr(str
, "tls4://")
522 || strstr(str
, "tls6://"))
523 return PWMD_SOCKET_TLS
;
526 return PWMD_SOCKET_LOCAL
;
530 static char *escape(const char *str
)
533 char *buf
= pwmd_malloc(ASSUAN_LINELENGTH
+1), *b
= buf
;
536 for (p
= str
; *p
; p
++, len
++) {
537 if (len
== ASSUAN_LINELENGTH
)
578 static void free_inquire(struct inquire_s
*inq
)
583 pwmd_free(inq
->line
);
585 if (inq
->fd
!= -1 && inq
->fd
!= STDIN_FILENO
)
591 /* When *result is not NULL it is updated to the new values and not
593 static gpg_error_t
set_inquire(int fd
, const char *line
,
594 struct inquire_s
**result
)
596 struct inquire_s inq
= {0};
597 struct stat st
= {0};
601 if (fstat(fd
, &st
) == -1)
602 return gpg_error_from_syserror();
604 inq
.size
= st
.st_size
;
608 inq
.line
= pwmd_calloc(1, ASSUAN_LINELENGTH
);
610 return GPG_ERR_ENOMEM
;
613 char *s
= escape(line
);
615 if (strlen(s
) >= ASSUAN_LINELENGTH
) {
617 return GPG_ERR_LINE_TOO_LONG
;
620 strncpy(inq
.line
, s
, ASSUAN_LINELENGTH
-1);
625 rc
= pwmd_setopt(pwm
, PWMD_OPTION_INQUIRE_TOTAL
,
626 st
.st_size
? st
.st_size
+strlen(inq
.line
) : 0);
633 *result
= pwmd_malloc(sizeof(struct inquire_s
));
635 if ((*result
)->fd
!= -1 && (*result
)->fd
!= STDIN_FILENO
)
636 close((*result
)->fd
);
638 pwmd_free((*result
)->line
);
639 (*result
)->line
= NULL
;
644 memcpy(*result
, &inq
, sizeof(struct inquire_s
));
645 memset(&inq
, 0, sizeof(struct inquire_s
));
649 #ifdef HAVE_LIBREADLINE
650 static int interactive_hook(void)
652 interactive_error
= process_cmd();
654 if (interactive_error
)
655 rl_event_hook
= NULL
;
660 static void print_help()
663 "------------------------------------------------------------------------------\n"
664 "Elements are TAB delimited. Press CTRL-V then TAB to insert from the prompt.\n"
666 "Type HELP for protocol commands. Type .help for pwmc commands. Press CTRL-D\n"
668 "------------------------------------------------------------------------------\n"
673 static char *parse_arg(const char *src
, char *dst
, size_t len
)
679 for (; s
&& *s
&& *s
!= ' ' && n
< len
; s
++, n
++)
687 static gpg_error_t
read_command(const char *line
, char **result
, size_t *len
)
689 const char *p
= line
;
691 gpg_error_t rc
= GPG_ERR_SYNTAX
;
692 char filebuf
[ASSUAN_LINELENGTH
];
693 char *filename
= NULL
;
694 struct inquire_s
*inq
= NULL
;
696 if (p
&& *p
&& *++p
) {
697 filename
= parse_arg(p
, filebuf
, sizeof(filebuf
));
698 if (filename
&& *filename
) {
699 p
+= strlen(filename
)+1;
701 while (*p
&& isspace(*p
))
710 fprintf(stderr
, N_("Usage: .read <filename> <command> [args]\n"));
714 fd
= open(filename
, O_RDONLY
);
716 return gpg_error_from_syserror();
718 rc
= set_inquire(fd
, NULL
, &inq
);
725 rc
= pwmd_command(pwm
, result
, len
, inquire_cb
, inq
, p
);
730 static gpg_error_t
redir_command(const char *line
)
732 const char *p
= line
;
734 gpg_error_t rc
= GPG_ERR_SYNTAX
;
735 char filebuf
[ASSUAN_LINELENGTH
];
736 char *filename
= NULL
;
737 struct inquire_s
*inq
= NULL
;
741 if (p
&& *p
&& *++p
) {
742 filename
= parse_arg(p
, filebuf
, sizeof(filebuf
));
743 if (filename
&& *filename
) {
744 p
+= strlen(filename
)+1;
746 while (*p
&& isspace(*p
))
755 fprintf(stderr
, N_("Usage: .redir <filename> <command> [args]\n"));
759 fd
= open(filename
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0600);
761 return gpg_error_from_syserror();
763 #ifdef HAVE_LIBREADLINE
764 rc
= set_inquire(interactive
? STDIN_FILENO
: inquirefd
, NULL
, &inq
);
766 rc
= set_inquire(inquirefd
, NULL
, &inq
);
773 rc
= parse_dotcommand(p
, &result
, &len
, inq
);
774 if (!rc
&& result
&& len
--) { // null byte which is always appended
775 if (write(fd
, result
, len
) != len
)
776 rc
= GPG_ERR_TOO_SHORT
;
785 static gpg_error_t
help_command(const char *line
)
787 fprintf(stderr
, N_("Type HELP for protocol commands. Available pwmc commands:\n\n"
788 " .redir <filename> <command>\n"
789 " redirect the output of a command to the specified file\n"
791 " .open <filename>\n"
792 " open the specified filename losing any changes to the current one\n"
794 " .read <filename> <command> [args]\n"
795 " obtain data from the specified filename for an inquire command\n"
797 " .set help | <name> [<value>]\n"
798 " set option <name> to <value>\n"
801 " this help text\n"));
805 static gpg_error_t
open_command(const char *line
)
807 struct inquire_s
*inq
= NULL
;
808 const char *filename
= line
;
811 while (filename
&& isspace(*filename
))
814 if (!filename
|| !*filename
) {
815 fprintf(stderr
, N_("Usage: .open <filename>\n"));
816 return GPG_ERR_SYNTAX
;
819 fprintf(stderr
, N_("Opening data file \"%s\" ...\n"), filename
);
820 #ifdef HAVE_LIBREADLINE
821 rc
= set_inquire(interactive
? STDIN_FILENO
: -1, NULL
, &inq
);
823 rc
= set_inquire(-1, NULL
, &inq
);
829 pwmd_setopt(pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
831 #ifdef HAVE_LIBREADLINE
832 // For safety. This file may be a different one. Make the user set it
835 pwmd_free(new_keyfile
);
840 rc
= pwmd_open(pwm
, filename
, inquire_cb
, inq
);
845 static gpg_error_t
set_command(const char *line
)
848 char name
[256] = {0};
849 char value
[512] = {0};
852 const char *p
= line
;
854 while (p
&& *p
&& isspace(*p
))
857 namep
= parse_arg(p
, name
, sizeof(name
));
858 if (!namep
|| !*namep
) {
859 fprintf(stderr
, N_("Usage: .set help | <name> [<value>]\n"));
860 return GPG_ERR_SYNTAX
;
864 while (p
&& *p
&& isspace(*p
))
867 valuep
= parse_arg(p
, value
, sizeof(value
));
869 if (!strcmp(name
, "keyfile") || !strcmp(name
, "new-keyfile")) {
870 int is_newkeyfile
= 1;
872 if (!strcmp(name
, "keyfile"))
876 pwmd_free(new_keyfile
);
886 new_keyfile
= pwmd_strdup(value
);
888 keyfile
= pwmd_strdup(value
);
890 rc
= pwmd_command(pwm
, NULL
, NULL
, NULL
, NULL
, "AGENT option pinentry-mode=loopback");
892 rc
= pwmd_setopt(pwm
, PWMD_OPTION_NO_PINENTRY
, 1);
893 rc
= pwmd_setopt(pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
896 else if (!local_pin
&& !no_pinentry
) {
899 pwmd_socket_type(pwm
, &t
);
900 if (t
== PWMD_SOCKET_LOCAL
) {
901 rc
= pwmd_setopt(pwm
, PWMD_OPTION_NO_PINENTRY
, 0);
902 rc
= pwmd_setopt(pwm
, PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
906 else if (!strcmp(name
, "help")) {
908 "Set a libpwmd or pwmc option. The option name and optional value is space\n"
909 "delimited. When no value is specified the option is unset.\n\n"
910 "keyfile [<filename>]\n"
911 " set or unset the keyfile to be used when a passphrase is required\n"
913 "new-keyfile [<filename>]\n"
914 " set or unset the keyfile to be used when a new passphrase is required\n"
918 rc
= GPG_ERR_UNKNOWN_OPTION
;
923 static gpg_error_t
parse_dotcommand(const char *line
, char **result
,
924 size_t *len
, struct inquire_s
*inq
)
926 const char *p
= line
;
929 if (!strncmp(p
, ".read", 5))
930 rc
= read_command(p
+5, result
, len
);
931 else if (!strncmp(p
, ".redir", 6))
932 rc
= redir_command(p
+6);
933 else if (!strncmp(p
, ".help", 5))
934 rc
= help_command(p
+5);
935 else if (!strncmp(p
, ".open", 5))
936 rc
= open_command(p
+5);
937 else if (!strncmp(p
, ".set", 4))
938 rc
= set_command(p
+4);
940 rc
= pwmd_command(pwm
, result
, len
, inquire_cb
, inq
, line
);
945 #ifdef HAVE_LIBREADLINE
946 static gpg_error_t
do_interactive()
949 struct inquire_s
*inq
= NULL
;
956 rc
= set_inquire(STDIN_FILENO
, NULL
, &inq
);
960 fprintf(stderr
, N_("WARNING: interactive mode doesn't use secure memory!\n"));
962 rl_event_hook
= &interactive_hook
;
963 rl_set_keyboard_input_timeout(100000);
970 line
= readline("pwm> ");
971 if (interactive_error
) {
972 rc
= interactive_error
;
981 if (gpg_err_code(rc
) != GPG_ERR_CANCELED
&&
982 gpg_err_code(rc
) != GPG_ERR_EOF
)
983 fprintf(stderr
, "ERR %i: %s\n", rc
, gpg_strerror(rc
));
992 #ifdef HAVE_LIBREADLINE
996 rc
= parse_dotcommand(line
, &result
, &len
, inq
);
999 fprintf(stderr
, "ERR %i: %s\n", rc
, gpg_strerror(rc
));
1000 else if (result
&& len
)
1001 printf("%s%s", result
, result
[len
-1] != '\n' ? "\n" : "");
1011 static char *itoa(long long int n
)
1013 static char buf
[64];
1015 snprintf(buf
, sizeof(buf
), "%llu", n
);
1019 static gpg_error_t
finalize()
1022 #ifdef HAVE_LIBREADLINE
1025 if (!force_save
&& interactive
) {
1029 fprintf(stderr
, "\n");
1032 fprintf(stderr
, N_("(c)ancel/(f)orget password/(s)ave/(Q)uit/(S)ave and quit/(h)elp?: "));
1033 p
= fgets(buf
, sizeof(buf
), stdin
);
1045 return GPG_ERR_CANCELED
;
1049 rc
= pwmd_command(pwm
, NULL
, NULL
, NULL
, NULL
,
1050 "CLEARCACHE %s", filename
);
1065 } while (!finished
);
1069 if (save
&& !filename
) {
1070 fprintf(stderr
, N_("No filename was specified on the command line. Aborting.\n"));
1071 return GPG_ERR_CANCELED
;
1074 if (save
&& filename
) {
1075 char *args
= pwmd_strdup_printf("%s%s %s%s %s %s%s %s%s --s2k-count=%lu",
1076 keygrip
? "--keygrip=" : "", keygrip
? keygrip
: "",
1077 sign_keygrip
? "--sign-keygrip=" : "", sign_keygrip
? sign_keygrip
: "",
1078 no_passphrase
? "--no-passphrase" : "",
1079 cipher
? "--cipher=" : "", cipher
? cipher
: "",
1080 iterations_arg
? "--cipher-iterations=" : "", iterations_arg
? itoa(iterations
) : "",
1083 fprintf(stderr
, "\n");
1084 fprintf(stderr
, N_("Saving changes ...\n"));
1085 rc
= pwmd_save(pwm
, args
, inquire_cb
, NULL
);
1089 no_passphrase
= 0; // reset to avoid usage error on the next SAVE
1092 #ifdef HAVE_LIBREADLINE
1094 return rc
? rc
: quit
? 0 : GPG_ERR_CANCELED
;
1100 int main(int argc
, char *argv
[])
1105 char command
[ASSUAN_LINELENGTH
], *p
= NULL
;
1106 char *result
= NULL
;
1108 char *pinentry_path
= NULL
;
1109 char *display
= NULL
, *tty
= NULL
, *ttytype
= NULL
, *lcctype
= NULL
,
1111 int outfd
= STDOUT_FILENO
;
1112 FILE *outfp
= stdout
;
1113 FILE *inquirefp
= stdin
;
1114 int show_status
= 1;
1115 char *clientname
= "pwmc";
1116 char *inquire
= NULL
;
1117 char *inquire_line
= NULL
;
1120 int use_ssh_agent
= 1;
1121 long ssh_timeout
= 0;
1122 int ssh_keepalive
= 0;
1123 char *knownhosts
= NULL
;
1124 char *identity
= NULL
;
1127 char *cacert
= NULL
;
1128 char *clientcert
= NULL
;
1129 char *clientkey
= NULL
;
1133 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1134 pwmd_socket_t socktype
;
1136 int lock_on_open
= 1;
1137 long lock_timeout
= 0;
1139 /* The order is important. */
1142 OPT_USE_SSH_AGENT
, OPT_IDENTITY
, OPT_KNOWNHOSTS
, OPT_SSH_TIMEOUT
,
1146 OPT_CACERT
, OPT_CLIENTCERT
, OPT_CLIENTKEY
, OPT_PRIORITY
, OPT_VERIFY
,
1148 OPT_URL
, OPT_LOCAL
, OPT_FORCE_SAVE
, OPT_TTYNAME
, OPT_TTYTYPE
,
1149 OPT_DISPLAY
, OPT_LC_CTYPE
, OPT_LC_MESSAGES
, OPT_TIMEOUT
, OPT_TRIES
,
1150 OPT_PINENTRY
, OPT_KEYFILE
, OPT_NEW_KEYFILE
, OPT_NOLOCK
,
1151 OPT_LOCK_TIMEOUT
, OPT_SAVE
, OPT_OUTPUT_FD
, OPT_INQUIRE
,
1152 OPT_INQUIRE_FD
, OPT_INQUIRE_FILE
, OPT_INQUIRE_LINE
, OPT_NO_STATUS
,
1153 OPT_NAME
, OPT_VERSION
, OPT_HELP
, OPT_KEYGRIP
, OPT_SIGN_KEYGRIP
,
1154 OPT_NOPASSPHRASE
, OPT_CIPHER
, OPT_KEYPARAMS
, OPT_NO_PINENTRY
,
1155 OPT_S2K_COUNT
, OPT_ITERATIONS
,
1156 #ifdef HAVE_LIBREADLINE
1160 const struct option long_opts
[] = {
1162 { "no-ssh-agent", 0, 0, 0 },
1163 { "identity", 1, 0, 'i' },
1164 { "knownhosts", 1, 0, 'k' },
1165 { "ssh-timeout", 1, 0, 0 },
1166 { "ssh-keepalive", 1, 0, 0 },
1169 { "ca-cert", 1, 0, 0 },
1170 { "client-cert", 1, 0, 0 },
1171 { "client-key", 1, 0, 0 },
1172 { "tls-priority", 1, 0, 0 },
1173 { "tls-verify", 0, 0, 0 },
1176 { "local-pinentry", 0, 0 },
1177 { "force-save", 0, 0 },
1178 { "ttyname", 1, 0, 'y' },
1179 { "ttytype", 1, 0, 't' },
1180 { "display", 1, 0, 'd' },
1181 { "lc-ctype", 1, 0, 0 },
1182 { "lc-messages", 1, 0, 0 },
1183 { "timeout", 1, 0, 0 },
1184 { "tries", 1, 0, 0 },
1185 { "pinentry", 1, 0, 0 },
1186 { "key-file", 1, 0, 0 },
1187 { "new-key-file", 1, 0, 0 },
1188 { "no-lock", 0, 0, 0 },
1189 { "lock-timeout", 1, 0, 0 },
1190 { "save", 0, 0, 'S' },
1191 { "output-fd", 1, 0, 0 },
1192 { "inquire", 1, 0, 0 },
1193 { "inquire-fd", 1, 0, 0 },
1194 { "inquire-file", 1, 0, 0 },
1195 { "inquire-line", 1, 0, 'L' },
1196 { "no-status", 0, 0, 0 },
1197 { "name", 1, 0, 'n' },
1198 { "version", 0, 0, 0 },
1199 { "help", 0, 0, 0 },
1200 { "keygrip", 1, 0, 0 },
1201 { "sign-keygrip", 1, 0, 0 },
1202 { "no-passphrase", 0, 0, 0 },
1203 { "cipher", 1, 0, 0 },
1204 { "key-params", 1, 0, 0 },
1205 { "no-pinentry", 0, 0, 0 },
1206 { "s2k-count", 1, 0, 0 },
1207 { "cipher-iterations", 1, 0, 0 },
1208 #ifdef HAVE_LIBREADLINE
1209 { "interactive", 0, 0 },
1214 const char *optstring
= "L:y:t:d:P:I:Sn:i:k:";
1216 const char *optstring
= "L:y:t:d:P:I:Sn:";
1221 setlocale(LC_ALL
, "");
1222 bindtextdomain("libpwmd", LOCALEDIR
);
1225 #ifdef HAVE_LIBREADLINE
1226 if (!strcmp(basename(argv
[0]), "pwmsh"))
1230 tries
= DEFAULT_PIN_TRIES
;
1231 inquirefd
= STDIN_FILENO
;
1233 while ((opt
= getopt_long(argc
, argv
, optstring
, long_opts
, &opt_index
)) != -1) {
1235 /* Handle long options without a short option part. */
1237 switch (opt_index
) {
1239 case OPT_USE_SSH_AGENT
:
1242 case OPT_SSH_TIMEOUT
:
1243 ssh_timeout
= strtol(optarg
, &p
, 10);
1245 case OPT_SSH_KEEPALIVE
:
1246 ssh_keepalive
= strtol(optarg
, &p
, 10);
1253 case OPT_CLIENTCERT
:
1254 clientcert
= optarg
;
1270 keyfile
= pwmd_strdup(optarg
);
1272 case OPT_NEW_KEYFILE
:
1273 new_keyfile
= pwmd_strdup(optarg
);
1278 case OPT_LOCK_TIMEOUT
:
1279 lock_timeout
= strtol(optarg
, &p
, 10);
1287 case OPT_FORCE_SAVE
:
1288 save
= force_save
= 1;
1291 lcctype
= pwmd_strdup(optarg
);
1293 case OPT_LC_MESSAGES
:
1294 lcmessages
= pwmd_strdup(optarg
);
1297 timeout
= strtol(optarg
, &p
, 10);
1300 tries
= strtol(optarg
, &p
, 10);
1305 case OPT_INQUIRE_FD
:
1306 inquirefd
= strtol(optarg
, &p
, 10);
1308 inquirefp
= fdopen(inquirefd
, "r");
1310 pwmd_free(password
);
1311 err(EXIT_FAILURE
, "%i", inquirefd
);
1315 case OPT_INQUIRE_FILE
:
1316 inquirefd
= open(optarg
, O_RDONLY
);
1317 if (!inquirefd
== -1) {
1318 pwmd_free(password
);
1319 err(EXIT_FAILURE
, "%s", optarg
);
1321 inquirefp
= fdopen(inquirefd
, "r");
1324 outfd
= strtol(optarg
, &p
, 10);
1326 outfp
= fdopen(outfd
, "w");
1328 pwmd_free(password
);
1329 err(EXIT_FAILURE
, "%i", outfd
);
1337 pwmd_free(password
);
1338 printf("%s (pwmc)\n\n"
1339 "Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012\n"
1341 "Released under the terms of the GPL v2. Use at your own risk.\n\n"
1342 "Compile-time features:\n"
1353 #ifdef WITH_PINENTRY
1368 #ifdef HAVE_LIBREADLINE
1374 , PACKAGE_STRING
, PACKAGE_BUGREPORT
);
1377 pinentry_path
= optarg
;
1380 usage(argv
[0], EXIT_SUCCESS
);
1384 case OPT_SIGN_KEYGRIP
:
1385 sign_keygrip
= optarg
;
1388 s2k_count
= strtoul(optarg
, &p
, 10);
1390 case OPT_ITERATIONS
:
1391 iterations
= strtoull(optarg
, &p
, 10);
1394 case OPT_NOPASSPHRASE
:
1400 case OPT_NO_PINENTRY
:
1403 #ifdef HAVE_LIBREADLINE
1404 case OPT_INTERACTIVE
:
1409 usage(argv
[0], EXIT_FAILURE
);
1413 fprintf(stderr
, N_("%s: invalid argument for option '--%s'\n"),
1414 argv
[0], long_opts
[opt_index
].name
);
1415 usage(argv
[0], EXIT_FAILURE
);
1424 knownhosts
= optarg
;
1428 inquire_line
= optarg
;
1443 clientname
= optarg
;
1446 pwmd_free(password
);
1447 usage(argv
[0], EXIT_FAILURE
);
1451 #ifdef HAVE_LIBREADLINE
1452 if (interactive
&& !isatty(STDIN_FILENO
)) {
1453 pwmd_free(password
);
1454 usage(argv
[0], EXIT_FAILURE
);
1456 else if (isatty(STDIN_FILENO
) && !inquire
&& !inquire_line
)
1460 filename
= argv
[optind
];
1462 gnutls_global_set_mem_functions(pwmd_malloc
, pwmd_malloc
, NULL
,
1463 pwmd_realloc
, pwmd_free
);
1466 rc
= pwmd_new(clientname
, &pwm
);
1470 pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TRIES
, tries
);
1471 fprintf(stderr
, N_("Connecting ...\n"));
1473 #if defined(WITH_SSH) || defined(WITH_GNUTLS)
1474 socktype
= is_remote_url(url
);
1475 if (socktype
!= PWMD_SOCKET_LOCAL
) {
1477 if (socktype
== PWMD_SOCKET_SSH
) {
1479 rc
= pwmd_setopt(pwm
, PWMD_OPTION_KNOWNHOST_CB
, knownhost_cb
);
1483 rc
= pwmd_setopt(pwm
, PWMD_OPTION_KNOWNHOST_DATA
, clientname
);
1487 if (!getenv("SSH_AUTH_SOCK") || identity
)
1490 rc
= pwmd_setopt(pwm
, PWMD_OPTION_SSH_AGENT
, use_ssh_agent
);
1494 rc
= pwmd_setopt(pwm
, PWMD_OPTION_SSH_TIMEOUT
, ssh_timeout
);
1498 rc
= pwmd_setopt(pwm
, PWMD_OPTION_SSH_KEEPALIVE
, ssh_keepalive
);
1502 rc
= pwmd_connect(pwm
, url
, identity
, knownhosts
);
1507 rc
= pwmd_setopt(pwm
, PWMD_OPTION_TLS_VERIFY
, tls_verify
);
1511 rc
= pwmd_connect(pwm
, url
, clientcert
, clientkey
, cacert
, prio
);
1516 rc
= pwmd_connect(pwm
, url
);
1518 rc
= pwmd_connect(pwm
, url
);
1523 fprintf(stderr
, N_("Connected.\n"));
1526 rc
= pwmd_command(pwm
, NULL
, NULL
, NULL
, NULL
,
1527 "OPTION LOCK-TIMEOUT=%li", lock_timeout
);
1533 rc
= pwmd_setopt(pwm
, PWMD_OPTION_LOCK_ON_OPEN
, 1);
1538 rc
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_DESC
, NULL
);
1543 rc
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, timeout
);
1548 rc
= pwmd_setopt(pwm
, PWMD_OPTION_NO_PINENTRY
, no_pinentry
);
1552 rc
= pwmd_setopt(pwm
, PWMD_OPTION_LOCAL_PINENTRY
,
1553 (local_pin
|| keyfile
|| new_keyfile
));
1557 if (pinentry_path
) {
1558 rc
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_PATH
, pinentry_path
);
1564 rc
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_DISPLAY
, display
);
1570 rc
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TTY
, tty
);
1576 rc
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TERM
, ttytype
);
1582 rc
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_LC_CTYPE
, lcctype
);
1588 rc
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_LC_MESSAGES
,
1595 rc
= pwmd_setopt(pwm
, PWMD_OPTION_STATUS_CB
, status_msg_cb
);
1601 rc
= open_command(filename
);
1606 #ifdef HAVE_LIBREADLINE
1611 rc
= do_interactive();
1617 struct inquire_s
*inq
= NULL
;
1619 rc
= set_inquire(inquirefd
, inquire_line
, &inq
);
1621 rc
= pwmd_command(pwm
, &result
, &len
, inquire_cb
, inq
, inquire
);
1627 fcntl(STDIN_FILENO
, F_SETFL
, O_NONBLOCK
);
1636 n
= read(STDIN_FILENO
, command
, sizeof(command
));
1638 if (errno
== EAGAIN
) {
1643 rc
= gpg_error_from_errno(errno
);
1654 if (!p
|| !*p
|| !strcasecmp(p
, "BYE"))
1658 struct inquire_s
*inq
= NULL
;
1659 rc
= set_inquire(inquirefd
, inquire_line
, &inq
);
1661 rc
= parse_dotcommand(command
, &result
, &len
, inq
);
1670 fwrite(result
, 1, result
[len
-1] == 0 ? len
-1 : len
, outfp
);
1675 pwmd_free(password
);
1680 #ifdef HAVE_LIBREADLINE
1683 memset(command
, 0, sizeof(command
));
1686 pwmd_free(new_keyfile
);
1693 fprintf(stderr
, N_("Connection closed.\n"));
1695 exit(rc
? EXIT_FAILURE
: EXIT_SUCCESS
);