2 /* vim:tw=78:ts=8:sw=4:set ft=c: */
4 Copyright (C) 2007-2009 Ben Kibbey <bjk@luxsci.net>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110-1301 USA
29 #include <sys/select.h>
42 #define N_(msgid) gettext(msgid)
46 #define DEFAULT_PORT 22
49 static void show_error(gpg_error_t error
)
51 fprintf(stderr
, "ERR %i %s\n", gpg_err_code(error
), pwmd_strerror(error
));
54 static void usage(const char *pn
)
57 "Read a PWMD protocol command from standard input.\n\n"
58 "Usage: pwmc [-hvX] [-s <socket>] "
62 "[-PTNDCM <string>] [-p <passphrase>]\n"
63 " [-S [-i <iter>]] [-c <name>] [-t <n>] [-d <fd>] [-I <fd>]\n"
65 " [-H <hostname> [-R <port>] -Y <identity> -K <known_hosts>\n"
66 " [-U <username>] [-G]] [filename]\n"
71 " -E pinentry method (0=pwmd, 1=pwmd async, 2=libpwmd nb)\n"
73 " -y number of pinentry tries before failing (3)\n"
75 " -H connect to hostname\n"
76 " -R alterate port (%i)\n"
77 " -U SSH username (default is the invoking user)\n"
78 " -Y SSH identity file\n"
79 " -K known host's file (for server validation)\n"
80 " -G retrieve the remote SSH host key and exit\n"
82 " -t pinentry timeout\n"
83 " -X disable showing of status messages from the server\n"
84 " -c set the client name\n"
85 " -s socket path (~/.pwmd/socket)\n"
87 " -P path to the pinentry binary (server default)\n"
89 " -N pinentry terminal type\n"
90 " -D pinentry display\n"
91 " -C pinentry LC_CTYPE\n"
92 " -M pinentry LC_MESSAGES\n"
93 " -d redirect command output to the specified file descriptor\n"
94 " -I read inquire data from the specified file descriptor\n"
95 " -S send the SAVE command before exiting\n"
96 " -i encrypt with the specified number of iterations\n"
99 " -h this help text\n"), DEFAULT_PORT
);
101 " -h this help text\n"));
111 static gpg_error_t
do_inquire(void *data
, const char *keyword
, gpg_error_t rc
,
112 char **result
, size_t *result_len
)
115 static char buf
[ASSUAN_LINELENGTH
];
118 struct inquire_s
*inq
= (struct inquire_s
*)data
;
121 memset(buf
, 0, sizeof(buf
));
129 snprintf(buf
, sizeof(buf
), "%s", inq
->data
);
130 pwmd_free(inq
->data
);
136 while ((c
= fgetc(inq
->fp
)) != EOF
) {
137 if (len
== sizeof(buf
)) {
147 memset(buf
, 0, sizeof(buf
));
156 static int status_msg_cb(void *data
, const char *line
)
158 fprintf(stderr
, "%s\n", line
);
162 int main(int argc
, char *argv
[])
165 char *password
= NULL
;
166 char *filename
= NULL
;
167 char *socketpath
= NULL
;
168 char command
[ASSUAN_LINELENGTH
], *p
;
169 int ret
= EXIT_SUCCESS
;
173 char *pinentry_path
= NULL
;
174 char *display
= NULL
, *tty
= NULL
, *ttytype
= NULL
, *lcctype
= NULL
,
176 int outfd
= STDOUT_FILENO
;
177 FILE *outfp
= stdout
;
178 int inquirefd
= STDIN_FILENO
;
179 FILE *inquirefp
= stdin
;
181 char *clientname
= NULL
;
182 char *inquire
= NULL
;
188 int port
= DEFAULT_PORT
;
189 char *username
= NULL
;
191 char *known_hosts
= NULL
;
201 setlocale(LC_ALL
, "");
202 bindtextdomain("libpwmd", LOCALEDIR
);
207 while ((opt
= getopt(argc
, argv
, "C:M:GK:U:Y:H:R:y:t:E:c:I:XT:N:D:hvP:p:s:Si:d:")) != EOF
) {
209 while ((opt
= getopt(argc
, argv
, "C:M:y:t:E:c:I:XT:N:D:hvP:p:s:Si:d:")) != EOF
) {
213 while ((opt
= getopt(argc
, argv
, "y:C:M:GK:U:Y:H:R:t:c:I:XT:N:D:hvP:p:s:Si:d:")) != EOF
) {
215 while ((opt
= getopt(argc
, argv
, "y:C:M:t:c:I:XT:N:D:hvP:p:s:Si:d:")) != EOF
) {
221 method
= atoi(optarg
);
228 tries
= atoi(optarg
);
232 host
= pwmd_strdup(optarg
);
238 ident
= pwmd_strdup(optarg
);
241 username
= pwmd_strdup(optarg
);
244 known_hosts
= pwmd_strdup(optarg
);
251 lcctype
= pwmd_strdup(optarg
);
254 lcmessages
= pwmd_strdup(optarg
);
257 timeout
= atoi(optarg
);
260 clientname
= pwmd_strdup(optarg
);
275 inquirefd
= atoi(optarg
);
276 inquirefp
= fdopen(inquirefd
, "r");
280 err(EXIT_FAILURE
, "%i", inquirefd
);
284 outfd
= atoi(optarg
);
285 outfp
= fdopen(outfd
, "w");
289 err(EXIT_FAILURE
, "%i", outfd
);
296 iter
= strtol(optarg
, NULL
, 10);
300 socketpath
= pwmd_strdup(optarg
);
303 password
= pwmd_strdup(optarg
);
304 memset(optarg
, 0, strlen(optarg
));
307 pinentry_path
= pwmd_strdup(optarg
);
311 printf("%s (pwmc)\n%s\n", PACKAGE_STRING
, PACKAGE_BUGREPORT
);
320 if (host
&& !get
&& (!known_hosts
|| !ident
)) {
330 filename
= argv
[optind
];
332 pwm
= pwmd_new("pwmc");
341 error
= pwmd_get_hostkey_async(pwm
, host
, port
);
344 errx(EXIT_FAILURE
, "%s: %s", host
, pwmd_strerror(error
));
347 s
= pwmd_process(pwm
, &error
, &hostkey
);
350 } while (s
== ASYNC_PROCESS
);
355 printf("%s\n", hostkey
);
362 error
= pwmd_tcp_connect_async(pwm
, host
, port
, ident
, username
, known_hosts
);
368 s
= pwmd_process(pwm
, &error
, &result
);
371 } while (s
== ASYNC_PROCESS
);
381 error
= pwmd_get_hostkey(host
, port
, &hostkey
);
386 printf("%s\n", hostkey
);
392 error
= pwmd_tcp_connect(pwm
, host
, port
, ident
, username
, known_hosts
);
402 error
= pwmd_connect(pwm
, socketpath
);
411 error
= pwmd_command(pwm
, &result
, "VERSION");
413 if (error
&& error
!= GPG_ERR_ASS_UNKNOWN_CMD
)
418 if (error
== GPG_ERR_ASS_UNKNOWN_CMD
) {
426 /* pwmd version 2 or later. */
436 error
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TIMEOUT
, timeout
);
443 error
= pwmd_setopt(pwm
, PWMD_OPTION_PASSWORD
, password
);
450 error
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_PATH
, pinentry_path
);
457 error
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_DISPLAY
, display
);
464 error
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TTY
, tty
);
471 error
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TERM
, ttytype
);
478 error
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_LC_CTYPE
, lcctype
);
485 error
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_LC_MESSAGES
,
494 error
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY
, 1);
502 error
= pwmd_setopt(pwm
, PWMD_OPTION_PINENTRY_TRIES
, tries
);
510 error
= pwmd_setopt(pwm
, PWMD_OPTION_STATUS_FUNC
, status_msg_cb
);
518 /* This method doesn't support PWMD_OPTION_PINENTRY_TRIES. */
521 error
= pwmd_open_async(pwm
, filename
);
523 error
= pwmd_open_async2(pwm
, filename
);
527 s
= pwmd_process(pwm
, &error
, &result
);
530 } while (s
== ASYNC_PROCESS
);
534 error
= pwmd_open(pwm
, filename
);
536 error
= pwmd_open(pwm
, filename
);
544 error
= pwmd_command(pwm
, &result
, "LOCK");
553 struct timeval tv
= {0, 100000};
558 FD_SET(STDIN_FILENO
, &rfds
);
559 n
= select(STDIN_FILENO
+1, &rfds
, NULL
, NULL
, &tv
);
562 s
= pwmd_process(pwm
, &error
, &result
);
567 fprintf(stderr
, ".");
572 error
= gpg_error_from_errno(errno
);
576 fprintf(stderr
, "\n");
577 n
= read(STDIN_FILENO
, command
, sizeof(command
));
580 error
= gpg_error_from_errno(errno
);
584 if (n
&& command
[strlen(command
)-1] == '\n')
585 command
[strlen(command
)-1] = 0;
593 p
= fgets(command
, sizeof(command
), stdin
);
595 p
= fgets(command
, sizeof(command
), stdin
);
602 * This is a known INQUIRE command. We use pwmd_inquire() to send the
603 * data from the do_inquire() callback function.
605 if (strncasecmp(p
, "STORE ", 6) == 0) {
607 inquire
= (char *)"STORE";
609 else if (strncasecmp(p
, "IMPORT ", 7) == 0) {
611 inquire
= (char *)"IMPORT";
615 struct inquire_s
*inq
= (struct inquire_s
*)pwmd_malloc(sizeof(struct inquire_s
));
618 error
= gpg_error_from_errno(ENOMEM
);
622 inq
->data
= pwmd_strdup(p
);
624 error
= pwmd_inquire(pwm
, inquire
, do_inquire
, inq
);
629 if (strcasecmp(p
, "BYE") == 0)
632 error
= pwmd_command(pwm
, &result
, command
);
633 memset(command
, 0, sizeof(command
));
639 fwrite(result
, 1, strlen(result
), outfp
);
644 memset(command
, 0, sizeof(command
));
647 if (!error
&& save
) {
649 error
= pwmd_command(pwm
, &result
, "OPTION ITERATIONS=%i", iter
);
658 error
= pwmd_save_async(pwm
);
660 error
= pwmd_save_async2(pwm
);
664 s
= pwmd_process(pwm
, &error
, &result
);
667 } while (s
== ASYNC_PROCESS
);
671 error
= pwmd_save(pwm
);
673 error
= pwmd_save(pwm
);
677 if (!error
&& filename
)
678 error
= pwmd_command(pwm
, &result
, "UNLOCK");
688 pwmd_free(socketpath
);