Renamed pwmd_tcp_connect() and pwmd_tcp_connect_async() to
[libpwmd.git] / src / pwmc.c
blob5153a04317811279cf649f0166f6cf5e8998f524
1 #define DEBUG 1
2 /* vim:tw=78:ts=8:sw=4:set ft=c: */
3 /*
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
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <err.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <libpwmd.h>
27 #include <assuan.h>
28 #ifdef DEBUG
29 #include <sys/select.h>
30 #include <fcntl.h>
31 #endif
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif
37 #ifdef HAVE_LOCALE_H
38 #include <locale.h>
39 #endif
41 #include "gettext.h"
42 #define N_(msgid) gettext(msgid)
44 #include "mem.h"
46 #define DEFAULT_PORT 22
47 pwm_t *pwm;
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)
56 fprintf(stderr, N_(
57 "Read a PWMD protocol command from standard input.\n\n"
58 "Usage: pwmc [-hvX] [-s <socket>] "
59 #ifdef DEBUG
60 "[-E <n>] [-y <n>]"
61 #endif
62 "[-PTNDCM <string>] [-p <passphrase>]\n"
63 " [-S [-i <iter>]] [-c <name>] [-t <n>] [-d <fd>] [-I <fd>]\n"
64 #ifdef WITH_TCP
65 " [-H <hostname> [-R <port>] -Y <identity> -K <known_hosts>\n"
66 " [-U <username>] [-G]] [filename]\n"
67 #else
68 " [filename]\n"
69 #endif
70 #ifdef DEBUG
71 " -E pinentry method (0=pwmd, 1=pwmd async, 2=libpwmd nb)\n"
72 #endif
73 " -y number of pinentry tries before failing (3)\n"
74 #ifdef WITH_TCP
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"
81 #endif
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"
86 " -p passphrase\n"
87 " -P path to the pinentry binary (server default)\n"
88 " -T pinentry tty\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"
97 " -v version\n"
98 #ifdef WITH_TCP
99 " -h this help text\n"), DEFAULT_PORT);
100 #else
101 " -h this help text\n"));
102 #endif
103 exit(EXIT_FAILURE);
106 struct inquire_s {
107 FILE *fp;
108 char *data;
111 static gpg_error_t do_inquire(void *data, const char *keyword, gpg_error_t rc,
112 char **result, size_t *result_len)
114 int c;
115 static char buf[ASSUAN_LINELENGTH];
116 char *p;
117 size_t len = 0;
118 struct inquire_s *inq = (struct inquire_s *)data;
120 if (rc) {
121 memset(buf, 0, sizeof(buf));
122 return rc;
125 buf[0] = 0;
126 p = buf;
128 if (inq->data) {
129 snprintf(buf, sizeof(buf), "%s", inq->data);
130 pwmd_free(inq->data);
131 inq->data = NULL;
132 len = strlen(buf);
133 p = buf + len;
136 while ((c = fgetc(inq->fp)) != EOF) {
137 if (len == sizeof(buf)) {
138 ungetc(c, inq->fp);
139 break;
142 *p++ = c;
143 len++;
146 if (!buf[0]) {
147 memset(buf, 0, sizeof(buf));
148 return GPG_ERR_EOF;
151 *result = buf;
152 *result_len = len;
153 return 0;
156 static int status_msg_cb(void *data, const char *line)
158 fprintf(stderr, "%s\n", line);
159 return 0;
162 int main(int argc, char *argv[])
164 int opt;
165 char *password = NULL;
166 char *filename = NULL;
167 char *socketpath = NULL;
168 char command[ASSUAN_LINELENGTH], *p;
169 int ret = EXIT_SUCCESS;
170 gpg_error_t error;
171 char *result = NULL;
172 int save = 0;
173 char *pinentry_path = NULL;
174 char *display = NULL, *tty = NULL, *ttytype = NULL, *lcctype = NULL,
175 *lcmessages = NULL;
176 int outfd = STDOUT_FILENO;
177 FILE *outfp = stdout;
178 int inquirefd = STDIN_FILENO;
179 FILE *inquirefp = stdin;
180 int show_status = 1;
181 char *clientname = NULL;
182 char *inquire = NULL;
183 long iter = -2;
184 int have_iter = 0;
185 int timeout = 0;
186 #ifdef WITH_TCP
187 char *host = NULL;
188 int port = DEFAULT_PORT;
189 char *username = NULL;
190 char *ident = NULL;
191 char *known_hosts = NULL;
192 int get = 0;
193 #endif
194 int tries = 0;
195 #ifdef DEBUG
196 int method = 0;
197 pwmd_async_t s;
198 #endif
200 #ifdef ENABLE_NLS
201 setlocale(LC_ALL, "");
202 bindtextdomain("libpwmd", LOCALEDIR);
203 #endif
205 #ifdef DEBUG
206 #ifdef WITH_TCP
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) {
208 #else
209 while ((opt = getopt(argc, argv, "C:M:y:t:E:c:I:XT:N:D:hvP:p:s:Si:d:")) != EOF) {
210 #endif
211 #else
212 #ifdef WITH_TCP
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) {
214 #else
215 while ((opt = getopt(argc, argv, "y:C:M:t:c:I:XT:N:D:hvP:p:s:Si:d:")) != EOF) {
216 #endif
217 #endif
218 switch (opt) {
219 #ifdef DEBUG
220 case 'E':
221 method = atoi(optarg);
223 if (method > 2)
224 method = 2;
225 break;
226 #endif
227 case 'y':
228 tries = atoi(optarg);
229 break;
230 #ifdef WITH_TCP
231 case 'H':
232 host = pwmd_strdup(optarg);
233 break;
234 case 'R':
235 port = atoi(optarg);
236 break;
237 case 'Y':
238 ident = pwmd_strdup(optarg);
239 break;
240 case 'U':
241 username = pwmd_strdup(optarg);
242 break;
243 case 'K':
244 known_hosts = pwmd_strdup(optarg);
245 break;
246 case 'G':
247 get = 1;
248 break;
249 #endif
250 case 'C':
251 lcctype = pwmd_strdup(optarg);
252 break;
253 case 'M':
254 lcmessages = pwmd_strdup(optarg);
255 break;
256 case 't':
257 timeout = atoi(optarg);
258 break;
259 case 'c':
260 clientname = pwmd_strdup(optarg);
261 break;
262 case 'X':
263 show_status = 0;
264 break;
265 case 'T':
266 tty = optarg;
267 break;
268 case 'N':
269 ttytype = optarg;
270 break;
271 case 'D':
272 display = optarg;
273 break;
274 case 'I':
275 inquirefd = atoi(optarg);
276 inquirefp = fdopen(inquirefd, "r");
278 if (!inquirefp) {
279 pwmd_free(password);
280 err(EXIT_FAILURE, "%i", inquirefd);
282 break;
283 case 'd':
284 outfd = atoi(optarg);
285 outfp = fdopen(outfd, "w");
287 if (!outfp) {
288 pwmd_free(password);
289 err(EXIT_FAILURE, "%i", outfd);
291 break;
292 case 'S':
293 save = 1;
294 break;
295 case 'i':
296 iter = strtol(optarg, NULL, 10);
297 have_iter = 1;
298 break;
299 case 's':
300 socketpath = pwmd_strdup(optarg);
301 break;
302 case 'p':
303 password = pwmd_strdup(optarg);
304 memset(optarg, 0, strlen(optarg));
305 break;
306 case 'P':
307 pinentry_path = pwmd_strdup(optarg);
308 break;
309 case 'v':
310 pwmd_free(password);
311 printf("%s (pwmc)\n%s\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
312 exit(EXIT_SUCCESS);
313 case 'h':
314 default:
315 pwmd_free(password);
316 usage(argv[0]);
320 if (host && !get && (!known_hosts || !ident)) {
321 pwmd_free(password);
322 usage(argv[0]);
325 if (get && !host) {
326 pwmd_free(password);
327 usage(argv[0]);
330 filename = argv[optind];
331 pwmd_init();
332 pwm = pwmd_new("pwmc");
334 #ifdef WITH_TCP
335 if (host) {
336 #ifdef DEBUG
337 if (method) {
338 if (get) {
339 char *hostkey;
341 error = pwmd_get_hostkey_async(pwm, host, port);
343 if (error)
344 errx(EXIT_FAILURE, "%s: %s", host, pwmd_strerror(error));
346 do {
347 s = pwmd_process(pwm, &error, &hostkey);
348 fputc('.', stderr);
349 usleep(50000);
350 } while (s == ASYNC_PROCESS);
352 if (error)
353 goto done;
355 printf("%s\n", hostkey);
356 pwmd_free(hostkey);
357 pwmd_free(password);
358 pwmd_close(pwm);
359 exit(EXIT_SUCCESS);
362 error = pwmd_ssh_connect_async(pwm, host, port, ident, username, known_hosts);
364 if (error)
365 goto done;
367 do {
368 s = pwmd_process(pwm, &error, &result);
369 fputc('.', stderr);
370 usleep(50000);
371 } while (s == ASYNC_PROCESS);
373 if (error)
374 goto done;
376 else {
377 #endif
378 if (get) {
379 char *hostkey;
381 error = pwmd_get_hostkey(host, port, &hostkey);
383 if (error)
384 goto done;
386 printf("%s\n", hostkey);
387 pwmd_free(hostkey);
388 pwmd_free(password);
389 exit(EXIT_SUCCESS);
392 error = pwmd_ssh_connect(pwm, host, port, ident, username, known_hosts);
394 if (error)
395 goto done;
396 #ifdef DEBUG
398 #endif
400 else {
401 #endif
402 error = pwmd_connect(pwm, socketpath);
404 if (error)
405 goto done;
406 #ifdef WITH_TCP
408 #endif
410 if (have_iter) {
411 error = pwmd_command(pwm, &result, "VERSION");
413 if (error && error != GPG_ERR_ASS_UNKNOWN_CMD)
414 goto done;
416 pwmd_free(result);
418 if (error == GPG_ERR_ASS_UNKNOWN_CMD) {
419 if (iter < -1) {
420 pwmd_free(password);
421 pwmd_close(pwm);
422 usage(argv[0]);
425 else {
426 /* pwmd version 2 or later. */
427 if (iter < 0) {
428 pwmd_free(password);
429 pwmd_close(pwm);
430 usage(argv[0]);
435 if (timeout > 0) {
436 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT, timeout);
438 if (error)
439 goto done;
442 if (password) {
443 error = pwmd_setopt(pwm, PWMD_OPTION_PASSWORD, password);
445 if (error)
446 goto done;
448 else {
449 if (pinentry_path) {
450 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
452 if (error)
453 goto done;
456 if (display) {
457 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
459 if (error)
460 goto done;
463 if (tty) {
464 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TTY, tty);
466 if (error)
467 goto done;
470 if (ttytype) {
471 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
473 if (error)
474 goto done;
477 if (lcctype) {
478 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_LC_CTYPE, lcctype);
480 if (error)
481 goto done;
484 if (lcmessages) {
485 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_LC_MESSAGES,
486 lcmessages);
488 if (error)
489 goto done;
492 #ifdef DEBUG
493 if (method >= 2) {
494 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY, 1);
496 if (error)
497 goto done;
499 #endif
501 if (tries > 0) {
502 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
504 if (error)
505 goto done;
509 if (show_status) {
510 error = pwmd_setopt(pwm, PWMD_OPTION_STATUS_FUNC, status_msg_cb);
512 if (error)
513 goto done;
516 if (filename) {
517 #ifdef DEBUG
518 /* This method doesn't support PWMD_OPTION_PINENTRY_TRIES. */
519 if (method) {
520 if (method == 1)
521 error = pwmd_open_async(pwm, filename);
522 else
523 error = pwmd_open_async2(pwm, filename);
525 if (!error) {
526 do {
527 s = pwmd_process(pwm, &error, &result);
528 fputc('.', stderr);
529 usleep(50000);
530 } while (s == ASYNC_PROCESS);
533 else
534 error = pwmd_open(pwm, filename);
535 #else
536 error = pwmd_open(pwm, filename);
537 #endif
539 if (error)
540 goto done;
543 if (filename) {
544 error = pwmd_command(pwm, &result, "LOCK");
546 if (error)
547 goto done;
550 #ifdef DEBUG
551 if (method) {
552 for (;;) {
553 struct timeval tv = {0, 100000};
554 fd_set rfds;
555 int n;
557 FD_ZERO(&rfds);
558 FD_SET(STDIN_FILENO, &rfds);
559 n = select(STDIN_FILENO+1, &rfds, NULL, NULL, &tv);
561 if (n == 0) {
562 s = pwmd_process(pwm, &error, &result);
564 if (error)
565 goto done;
567 fprintf(stderr, ".");
568 continue;
571 if (n == -1) {
572 error = gpg_error_from_errno(errno);
573 goto done;
576 fprintf(stderr, "\n");
577 n = read(STDIN_FILENO, command, sizeof(command));
579 if (n == -1) {
580 error = gpg_error_from_errno(errno);
581 goto done;
584 if (n && command[strlen(command)-1] == '\n')
585 command[strlen(command)-1] = 0;
587 command[n] = 0;
588 p = command;
589 break;
592 else
593 p = fgets(command, sizeof(command), stdin);
594 #else
595 p = fgets(command, sizeof(command), stdin);
596 #endif
598 if (!p || !*p)
599 goto done;
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) {
606 p += 6;
607 inquire = (char *)"STORE";
609 else if (strncasecmp(p, "IMPORT ", 7) == 0) {
610 p += 7;
611 inquire = (char *)"IMPORT";
614 if (inquire) {
615 struct inquire_s *inq = (struct inquire_s *)pwmd_malloc(sizeof(struct inquire_s));
617 if (!inq) {
618 error = gpg_error_from_errno(ENOMEM);
619 goto done;
622 inq->data = pwmd_strdup(p);
623 inq->fp = inquirefp;
624 error = pwmd_inquire(pwm, inquire, do_inquire, inq);
625 pwmd_free(inq);
626 goto done;
629 if (strcasecmp(p, "BYE") == 0)
630 goto done;
632 error = pwmd_command(pwm, &result, command);
633 memset(command, 0, sizeof(command));
635 if (error)
636 goto done;
638 if (result) {
639 fwrite(result, 1, strlen(result), outfp);
640 pwmd_free(result);
643 done:
644 memset(command, 0, sizeof(command));
645 pwmd_free(password);
647 if (!error && save) {
648 if (iter != -2) {
649 error = pwmd_command(pwm, &result, "OPTION ITERATIONS=%i", iter);
651 if (error)
652 goto done;
655 #ifdef DEBUG
656 if (method) {
657 if (method == 1)
658 error = pwmd_save_async(pwm);
659 else
660 error = pwmd_save_async2(pwm);
662 if (!error) {
663 do {
664 s = pwmd_process(pwm, &error, &result);
665 fputc('.', stderr);
666 usleep(50000);
667 } while (s == ASYNC_PROCESS);
670 else
671 error = pwmd_save(pwm);
672 #else
673 error = pwmd_save(pwm);
674 #endif
677 if (!error && filename)
678 error = pwmd_command(pwm, &result, "UNLOCK");
680 if (error) {
681 show_error(error);
682 ret = EXIT_FAILURE;
685 pwmd_close(pwm);
687 if (socketpath)
688 pwmd_free(socketpath);
690 exit(ret);