Added assuan_socket_connect_fd() and assuan_set_finish_handler().
[libpwmd.git] / pwmc.c
blob125246982d1f3714103a71fbb3490df2a4c0f612
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2007-2008 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
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <err.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <libpwmd.h>
26 #include <assuan.h>
27 #ifdef DEBUG
28 #include <sys/select.h>
29 #include <fcntl.h>
30 #endif
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
36 #ifdef HAVE_LOCALE_H
37 #include <locale.h>
38 #endif
40 #include "gettext.h"
41 #define N_(msgid) gettext(msgid)
43 #ifndef MEM_DEBUG
44 #include "mem.h"
45 #else
46 #define xfree free
47 #define xrealloc realloc
48 #define xmalloc malloc
49 #define xstrdup strdup
50 #define xcalloc calloc
51 #endif
53 #define DEFAULT_PORT 6466
54 pwm_t *pwm;
56 static void show_error(gpg_error_t error)
58 fprintf(stderr, "ERR %i %s\n", gpg_err_code(error), pwmd_strerror(error));
61 static void usage(const char *pn)
63 fprintf(stderr, N_(
64 "Reads PWMD protocol commands from standard input.\n\n"
65 "Usage: pwmc [-hvX] [-s <socket>] "
66 #ifdef DEBUG
67 "[-E <n>] [-y <n>]"
68 #endif
69 "[-PTND <string>] [-p <passphrase>]\n"
70 " [-S [-i <iter>]] [-c <name>] [-t <n>] [-d <fd>] [-I <fd>]\n"
71 #ifdef WITH_TCP
72 " [-H <hostname> [-R <port>] [-V] [-C <cipher>]] [filename]\n"
73 #else
74 " [filename]\n"
75 #endif
76 #ifdef DEBUG
77 " -E pinentry method (0=pwmd, 1=pwmd async, 2=libpwmd nb)\n"
78 " -y number of pinentry tries before failing (3)\n"
79 #endif
80 #ifdef WITH_TCP
81 " -H connect to hostname\n"
82 " -R alterate port (%i)\n"
83 " -V verify peer hostname\n"
84 " -C cipher suite to use (in priority format)\n"
85 #endif
86 " -t pinentry timeout\n"
87 " -X disable showing of status messages from the server\n"
88 " -c set the client name\n"
89 " -s socket path (~/.pwmd/socket)\n"
90 " -p passphrase\n"
91 " -P path to the pinentry binary (server default)\n"
92 " -T pinentry tty\n"
93 " -N pinentry terminal type\n"
94 " -D pinentry display\n"
95 " -d redirect command output to the specified file descriptor\n"
96 " -I read inquire data from the specified file descriptor\n"
97 " -S send the SAVE command before exiting\n"
98 " -i encrypt with the specified number of iterations (-1 = 0 iterations)\n"
99 " -v version\n"
100 " -h this help text\n"), DEFAULT_PORT);
101 exit(EXIT_FAILURE);
104 struct inquire_s {
105 FILE *fp;
106 char *data;
109 static gpg_error_t do_inquire(void *data, const char *keyword, gpg_error_t rc,
110 char **result, size_t *result_len)
112 int c;
113 static char buf[ASSUAN_LINELENGTH];
114 char *p;
115 size_t len = 0;
116 struct inquire_s *inq = (struct inquire_s *)data;
118 if (rc) {
119 memset(buf, 0, sizeof(buf));
120 return rc;
123 buf[0] = 0;
124 p = buf;
126 if (inq->data) {
127 snprintf(buf, sizeof(buf), "%s", inq->data);
128 xfree(inq->data);
129 inq->data = NULL;
130 len = strlen(buf);
131 p = buf + len;
134 while ((c = fgetc(inq->fp)) != EOF) {
135 if (len == sizeof(buf)) {
136 ungetc(c, inq->fp);
137 break;
140 *p++ = c;
141 len++;
144 if (!buf[0]) {
145 memset(buf, 0, sizeof(buf));
146 return GPG_ERR_EOF;
149 *result = buf;
150 *result_len = len;
151 return 0;
154 static int status_msg_cb(void *data, const char *line)
156 fprintf(stderr, "%s\n", line);
157 return 0;
160 #ifdef DEBUG
161 static gpg_error_t do_nb_command(int fd, int which)
163 int n;
164 gpg_error_t error = 0;
166 fcntl(fd, F_SETFL, O_NONBLOCK);
168 do {
169 fd_set fds;
170 struct timeval tv = {0, 50000};
172 FD_ZERO(&fds);
173 FD_SET(fd, &fds);
174 n = select(fd+1, &fds, NULL, NULL, &tv);
176 if (n > 0) {
177 if (FD_ISSET(fd, &fds)) {
178 pwmd_nb_status_t status;
180 n = read(fd, &status, sizeof(status));
182 if (n == -1) {
183 error = gpg_error_from_errno(errno);
184 goto done;
187 if (!which)
188 error = pwmd_open_nb_finalize(pwm, &status);
189 else
190 error = pwmd_save_nb_finalize(pwm, &status);
192 if (error)
193 goto done;
196 else
197 fputc('.', stderr);
198 } while (n == 0);
200 done:
201 return error;
203 #endif
205 int main(int argc, char *argv[])
207 int opt;
208 char *password = NULL;
209 char *filename = NULL;
210 char *socketpath = NULL;
211 char command[ASSUAN_LINELENGTH], *p;
212 int ret = EXIT_SUCCESS;
213 gpg_error_t error;
214 char *result = NULL;
215 int save = 0;
216 char *pinentry_path = NULL;
217 char *display = NULL, *tty = NULL, *ttytype = NULL;
218 int outfd = STDOUT_FILENO;
219 FILE *outfp = stdout;
220 int inquirefd = STDIN_FILENO;
221 FILE *inquirefp = stdin;
222 int show_status = 1;
223 char *clientname = NULL;
224 char *inquire = NULL;
225 int iter = -2;
226 int timeout = 0;
227 #ifdef WITH_TCP
228 char *host = NULL;
229 int port = DEFAULT_PORT;
230 int verify = 0;
231 char *cipher = NULL;
232 #endif
233 #ifdef DEBUG
234 int tries = 0;
235 int method = 0;
236 pwmd_async_t s;
237 #endif
239 setlocale(LC_ALL, "");
240 bindtextdomain("libpwmd", LOCALEDIR);
242 #ifdef DEBUG
243 #ifdef WITH_TCP
244 while ((opt = getopt(argc, argv, "C:VH:R:y:t:E:c:I:XT:N:D:hvP:p:s:Si:d:")) != EOF) {
245 #else
246 while ((opt = getopt(argc, argv, "y:t:E:c:I:XT:N:D:hvP:p:s:Si:d:")) != EOF) {
247 #endif
248 #else
249 #ifdef WITH_TCP
250 while ((opt = getopt(argc, argv, "C:VH:R:t:c:I:XT:N:D:hvP:p:s:Si:d:")) != EOF) {
251 #else
252 while ((opt = getopt(argc, argv, "t:c:I:XT:N:D:hvP:p:s:Si:d:")) != EOF) {
253 #endif
254 #endif
255 switch (opt) {
256 #ifdef DEBUG
257 case 'E':
258 method = atoi(optarg);
260 if (method > 2)
261 method = 2;
262 break;
263 case 'y':
264 tries = atoi(optarg);
265 break;
266 #endif
267 #ifdef WITH_TCP
268 case 'H':
269 host = xstrdup(optarg);
270 break;
271 case 'R':
272 port = atoi(optarg);
273 break;
274 case 'V':
275 verify = 1;
276 break;
277 case 'C':
278 cipher = optarg;
279 break;
280 #endif
281 case 't':
282 timeout = atoi(optarg);
283 break;
284 case 'c':
285 clientname = xstrdup(optarg);
286 break;
287 case 'X':
288 show_status = 0;
289 break;
290 case 'T':
291 tty = optarg;
292 break;
293 case 'N':
294 ttytype = optarg;
295 break;
296 case 'D':
297 display = optarg;
298 break;
299 case 'I':
300 inquirefd = atoi(optarg);
301 inquirefp = fdopen(inquirefd, "r");
303 if (!inquirefp) {
304 xfree(password);
305 err(EXIT_FAILURE, "%i", inquirefd);
307 break;
308 case 'd':
309 outfd = atoi(optarg);
310 outfp = fdopen(outfd, "w");
312 if (!outfp) {
313 xfree(password);
314 err(EXIT_FAILURE, "%i", outfd);
316 break;
317 case 'S':
318 save = 1;
319 break;
320 case 'i':
321 iter = atoi(optarg);
323 if (iter < -1) {
324 xfree(password);
325 usage(argv[0]);
327 break;
328 case 's':
329 socketpath = xstrdup(optarg);
330 break;
331 case 'p':
332 password = xstrdup(optarg);
333 memset(optarg, 0, strlen(optarg));
334 break;
335 case 'P':
336 pinentry_path = xstrdup(optarg);
337 break;
338 case 'v':
339 xfree(password);
340 printf("%s (pwmc)\n%s\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
341 exit(EXIT_SUCCESS);
342 case 'h':
343 default:
344 xfree(password);
345 usage(argv[0]);
349 filename = argv[optind];
350 pwmd_init();
352 #ifdef WITH_TCP
353 if (host) {
354 #ifdef DEBUG
355 if (method == 1) {
356 if ((pwm = pwmd_tcp_connect_async(host, port, &error, NULL, NULL,
357 NULL, verify, cipher)) == NULL) {
358 xfree(password);
359 errx(EXIT_FAILURE, "%s: %s", host, pwmd_strerror(error));
362 do {
363 s = pwmd_process(pwm, &error);
364 fputc('.', stderr);
365 usleep(50000);
366 } while (s == ASYNC_PROCESS);
368 if (error) {
369 pwmd_close(pwm);
370 xfree(password);
371 errx(EXIT_FAILURE, "%s: %s", host, pwmd_strerror(error));
374 pwmd_finalize(pwm);
376 else {
377 #endif
378 if ((pwm = pwmd_tcp_connect(host, port, &error, NULL, NULL, NULL,
379 verify, cipher))
380 == NULL) {
381 xfree(password);
382 errx(EXIT_FAILURE, "%s: %s", host, pwmd_strerror(error));
384 #ifdef DEBUG
386 #endif
388 else {
389 #endif
390 if ((pwm = pwmd_connect(socketpath, &error)) == NULL) {
391 xfree(password);
392 errx(EXIT_FAILURE, "pwmd_connect(): %s", pwmd_strerror(error));
394 #ifdef WITH_TCP
396 #endif
398 error = pwmd_command(pwm, &result, "OPTION CLIENT NAME=%s", clientname ? clientname : "pwmc");
399 xfree(clientname);
401 if (error) {
402 xfree(password);
403 errx(EXIT_FAILURE, "pwmd_command(): %s", pwmd_strerror(error));
406 if (timeout > 0) {
407 error = pwmd_command(pwm, &result, "OPTION TIMEOUT=%i", timeout);
409 if (error) {
410 xfree(password);
411 errx(EXIT_FAILURE, "pwmd_command(): %s", pwmd_strerror(error));
415 if (password) {
416 error = pwmd_setopt(pwm, PWMD_OPTION_PASSWORD, password);
418 if (error) {
419 xfree(password);
420 goto done;
423 xfree(password);
425 else {
426 if (pinentry_path) {
427 error = pwmd_command(pwm, &result, "OPTION PATH=%s", pinentry_path);
429 if (error)
430 goto done;
433 if (display) {
434 error = pwmd_command(pwm, &result, "OPTION DISPLAY=%s", display);
436 if (error)
437 goto done;
440 if (tty) {
441 error = pwmd_command(pwm, &result, "OPTION TTYNAME=%s", tty);
443 if (error)
444 goto done;
447 if (ttytype) {
448 error = pwmd_command(pwm, &result, "OPTION TTYTYPE=%s", ttytype);
450 if (error)
451 goto done;
453 #ifdef DEBUG
454 if (method >= 2) {
455 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY, 1);
457 if (error)
458 goto done;
461 if (tries > 0) {
462 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
464 if (error)
465 goto done;
467 #endif
470 if (show_status) {
471 error = pwmd_setopt(pwm, PWMD_OPTION_STATUS_FUNC, status_msg_cb);
473 if (error)
474 goto done;
477 if (filename) {
478 #ifdef DEBUG
479 /* This method doesn't support PWMD_OPTION_PINENTRY_TRIES. */
480 if (method == 1) {
481 error = pwmd_open_async(pwm, filename);
483 if (!error) {
484 do {
485 s = pwmd_process(pwm, &error);
486 fputc('.', stderr);
487 usleep(50000);
488 } while (s == ASYNC_PROCESS);
490 pwmd_finalize(pwm);
493 else if (method == 2) {
494 int fd = pwmd_open_nb(pwm, &error, filename, timeout);
496 if (fd == -1)
497 goto done;
498 else if (fd >= 0)
499 error = do_nb_command(fd, 0);
501 else
502 error = pwmd_open(pwm, filename);
503 #else
504 error = pwmd_open(pwm, filename);
505 #endif
507 if (error)
508 goto done;
511 if (filename) {
512 error = pwmd_command(pwm, &result, "LOCK");
514 if (error)
515 goto done;
518 p = fgets(command, sizeof(command), stdin);
520 if (!p)
521 goto done;
524 * This is a known INQUIRE command. We use pwmd_inquire() to send the
525 * data from the do_inquire() callback function.
527 if (strncasecmp(p, "STORE ", 6) == 0) {
528 p += 6;
529 inquire = (char *)"STORE";
531 else if (strncasecmp(p, "IMPORT ", 7) == 0) {
532 p += 7;
533 inquire = (char *)"IMPORT";
536 if (inquire) {
537 struct inquire_s *inq = (struct inquire_s *)malloc(sizeof(struct inquire_s));
539 if (!inq) {
540 error = gpg_error_from_errno(ENOMEM);
541 goto done;
544 inq->data = xstrdup(p);
545 inq->fp = inquirefp;
546 error = pwmd_inquire(pwm, inquire, do_inquire, inq);
547 free(inq);
548 goto done;
551 if (strcasecmp(p, "BYE") == 0)
552 goto done;
554 error = pwmd_command(pwm, &result, command);
555 memset(command, 0, sizeof(command));
557 if (error)
558 goto done;
560 if (result) {
561 fwrite(result, 1, strlen(result), outfp);
562 pwmd_free_result(result);
565 done:
566 memset(command, 0, sizeof(command));
568 if (!error && save) {
569 if (iter != -2) {
570 error = pwmd_command(pwm, &result, "OPTION ITERATIONS=%i", iter);
572 if (error)
573 goto done;
576 #ifdef DEBUG
577 if (method == 1) {
578 error = pwmd_save_async(pwm);
580 if (!error) {
581 do {
582 s = pwmd_process(pwm, &error);
583 fputc('.', stderr);
584 usleep(50000);
585 } while (s == ASYNC_PROCESS);
587 pwmd_finalize(pwm);
590 else if (method == 3) {
591 int fd = pwmd_save_nb(pwm, &error);
593 if (fd == -1)
594 goto done;
595 else if (fd >= 0)
596 error = do_nb_command(fd, 1);
598 else
599 error = pwmd_save(pwm);
600 #else
601 error = pwmd_save(pwm);
602 #endif
605 if (!error && filename)
606 error = pwmd_command(pwm, &result, "UNLOCK");
608 if (error) {
609 show_error(error);
610 ret = EXIT_FAILURE;
613 pwmd_close(pwm);
615 if (socketpath)
616 xfree(socketpath);
618 exit(ret);