Added pwmd_command_ap(). This makes pwmd_command() a wrapper around this
[libpwmd.git] / pwmc.c
blob1e4e0f3d6213db5ee9878419f6c9f5997cbc7a6c
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 pwm_t *pwm;
55 static void show_error(gpg_error_t error)
57 fprintf(stderr, "ERR %i %s\n", gpg_err_code(error), pwmd_strerror(error));
60 static void usage(const char *pn)
62 fprintf(stderr, N_(
63 "Reads PWMD protocol commands from standard input.\n\n"
64 "Usage: pwmc [-hvX] [-s <socket>] "
65 #ifdef DEBUG
66 "[-E <n>] [-y <n>]"
67 #endif
68 "[-PTND <string>] [-p <passphrase>]\n"
69 " [-S [-i <iter>]] [-c <name>] [-t <n>] [-d <fd>] [-I <fd>]\n"
70 " [filename]\n"
71 #ifdef DEBUG
72 " -E pinentry method (0=pwmd, 1=pwmd async, 2=libpwmd nb)\n"
73 " -y number of pinentry tries before failing (3)\n"
74 #endif
75 " -t pinentry timeout\n"
76 " -X disable showing of status messages from the server\n"
77 " -c set the client name\n"
78 " -s socket path (~/.pwmd/socket)\n"
79 " -p passphrase\n"
80 " -P path to the pinentry binary (server default)\n"
81 " -T pinentry tty\n"
82 " -N pinentry terminal type\n"
83 " -D pinentry display\n"
84 " -d redirect command output to the specified file descriptor\n"
85 " -I read inquire data from the specified file descriptor\n"
86 " -S send the SAVE command before exiting\n"
87 " -i encrypt with the specified number of iterations (-1 = 0 iterations)\n"
88 " -v version\n"
89 " -h this help text\n"));
90 exit(EXIT_FAILURE);
93 struct inquire_s {
94 FILE *fp;
95 char *data;
98 static gpg_error_t do_inquire(void *data, const char *keyword, gpg_error_t rc,
99 char **result, size_t *result_len)
101 int c;
102 static char buf[ASSUAN_LINELENGTH];
103 char *p;
104 size_t len = 0;
105 struct inquire_s *inq = (struct inquire_s *)data;
107 if (rc) {
108 memset(buf, 0, sizeof(buf));
109 return rc;
112 buf[0] = 0;
113 p = buf;
115 if (inq->data) {
116 snprintf(buf, sizeof(buf), "%s", inq->data);
117 xfree(inq->data);
118 inq->data = NULL;
119 len = strlen(buf);
120 p = buf + len;
123 while ((c = fgetc(inq->fp)) != EOF) {
124 if (len == sizeof(buf)) {
125 ungetc(c, inq->fp);
126 break;
129 *p++ = c;
130 len++;
133 if (!buf[0]) {
134 memset(buf, 0, sizeof(buf));
135 return GPG_ERR_EOF;
138 *result = buf;
139 *result_len = len;
140 return 0;
143 static int status_msg_cb(void *data, const char *line)
145 fprintf(stderr, "%s\n", line);
146 return 0;
149 #ifdef DEBUG
150 static gpg_error_t do_nb_command(int fd, int which)
152 int n;
153 gpg_error_t error = 0;
155 fcntl(fd, F_SETFL, O_NONBLOCK);
157 do {
158 fd_set fds;
159 struct timeval tv = {0, 50000};
161 FD_ZERO(&fds);
162 FD_SET(fd, &fds);
163 n = select(fd+1, &fds, NULL, NULL, &tv);
165 if (n > 0) {
166 if (FD_ISSET(fd, &fds)) {
167 pwmd_nb_status_t status;
169 n = read(fd, &status, sizeof(status));
171 if (n == -1) {
172 error = gpg_error_from_errno(errno);
173 goto done;
176 if (!which)
177 error = pwmd_open_nb_finalize(pwm, &status);
178 else
179 error = pwmd_save_nb_finalize(pwm, &status);
181 if (error)
182 goto done;
185 else
186 fputc('.', stderr);
187 } while (n == 0);
189 done:
190 return error;
192 #endif
194 int main(int argc, char *argv[])
196 int opt;
197 char *password = NULL;
198 char *filename = NULL;
199 char *socketpath = NULL;
200 char command[ASSUAN_LINELENGTH], *p;
201 int ret = EXIT_SUCCESS;
202 gpg_error_t error;
203 char *result = NULL;
204 int save = 0;
205 char *pinentry_path = NULL;
206 char *display = NULL, *tty = NULL, *ttytype = NULL;
207 int outfd = STDOUT_FILENO;
208 FILE *outfp = stdout;
209 int inquirefd = STDIN_FILENO;
210 FILE *inquirefp = stdin;
211 int show_status = 1;
212 char *clientname = NULL;
213 char *inquire = NULL;
214 int iter = -2;
215 int timeout = 0;
216 #ifdef DEBUG
217 int tries = 0;
218 int method = 0;
219 pwmd_async_t s;
220 #endif
222 setlocale(LC_ALL, "");
223 bindtextdomain("libpwmd", LOCALEDIR);
225 #ifdef DEBUG
226 while ((opt = getopt(argc, argv, "y:t:E:c:I:XT:N:D:hvP:p:s:Si:d:")) != EOF) {
227 #else
228 while ((opt = getopt(argc, argv, "t:c:I:XT:N:D:hvP:p:s:Si:d:")) != EOF) {
229 #endif
230 switch (opt) {
231 #ifdef DEBUG
232 case 'E':
233 method = atoi(optarg);
234 break;
235 case 'y':
236 tries = atoi(optarg);
237 break;
238 #endif
239 case 't':
240 timeout = atoi(optarg);
241 break;
242 case 'c':
243 clientname = xstrdup(optarg);
244 break;
245 case 'X':
246 show_status = 0;
247 break;
248 case 'T':
249 tty = optarg;
250 break;
251 case 'N':
252 ttytype = optarg;
253 break;
254 case 'D':
255 display = optarg;
256 break;
257 case 'I':
258 inquirefd = atoi(optarg);
259 inquirefp = fdopen(inquirefd, "r");
261 if (!inquirefp) {
262 xfree(password);
263 err(EXIT_FAILURE, "%i", inquirefd);
265 break;
266 case 'd':
267 outfd = atoi(optarg);
268 outfp = fdopen(outfd, "w");
270 if (!outfp) {
271 xfree(password);
272 err(EXIT_FAILURE, "%i", outfd);
274 break;
275 case 'S':
276 save = 1;
277 break;
278 case 'i':
279 iter = atoi(optarg);
281 if (iter < -1) {
282 xfree(password);
283 usage(argv[0]);
285 break;
286 case 's':
287 socketpath = xstrdup(optarg);
288 break;
289 case 'p':
290 password = xstrdup(optarg);
291 memset(optarg, 0, strlen(optarg));
292 break;
293 case 'P':
294 pinentry_path = xstrdup(optarg);
295 break;
296 case 'v':
297 xfree(password);
298 printf("%s (pwmc)\n%s\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
299 exit(EXIT_SUCCESS);
300 case 'h':
301 default:
302 xfree(password);
303 usage(argv[0]);
307 filename = argv[optind];
308 pwmd_init();
310 if ((pwm = pwmd_connect(socketpath, &error)) == NULL) {
311 xfree(password);
312 errx(EXIT_FAILURE, "pwmd_connect(): %s", pwmd_strerror(error));
315 error = pwmd_command(pwm, &result, "OPTION CLIENT NAME=%s", clientname ? clientname : "pwmc");
316 xfree(clientname);
318 if (error) {
319 xfree(password);
320 errx(EXIT_FAILURE, "pwmd_command(): %s", pwmd_strerror(error));
323 if (timeout > 0) {
324 error = pwmd_command(pwm, &result, "OPTION TIMEOUT=%i", timeout);
326 if (error) {
327 xfree(password);
328 errx(EXIT_FAILURE, "pwmd_command(): %s", pwmd_strerror(error));
332 if (password) {
333 error = pwmd_setopt(pwm, PWMD_OPTION_PASSWORD, password);
335 if (error) {
336 xfree(password);
337 goto done;
340 xfree(password);
342 else {
343 if (pinentry_path) {
344 error = pwmd_command(pwm, &result, "OPTION PATH=%s", pinentry_path);
346 if (error)
347 goto done;
350 if (display) {
351 error = pwmd_command(pwm, &result, "OPTION DISPLAY=%s", display);
353 if (error)
354 goto done;
357 if (tty) {
358 error = pwmd_command(pwm, &result, "OPTION TTYNAME=%s", tty);
360 if (error)
361 goto done;
364 if (ttytype) {
365 error = pwmd_command(pwm, &result, "OPTION TTYTYPE=%s", ttytype);
367 if (error)
368 goto done;
370 #ifdef DEBUG
371 if (method >= 2) {
372 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY, 1);
374 if (error)
375 goto done;
378 if (tries > 0) {
379 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
381 if (error)
382 goto done;
384 #endif
387 if (show_status) {
388 error = pwmd_setopt(pwm, PWMD_OPTION_STATUS_FUNC, status_msg_cb);
390 if (error)
391 goto done;
394 if (filename) {
395 #ifdef DEBUG
396 /* This method doesn't support PWMD_OPTION_PINENTRY_TRIES. */
397 if (method == 1) {
398 error = pwmd_open_async(pwm, filename);
400 if (!error) {
401 do {
402 s = pwmd_process(pwm, &error);
403 fputc('.', stderr);
404 usleep(50000);
405 } while (s == ASYNC_PROCESS);
407 pwmd_finalize(pwm);
410 else if (method == 2) {
411 int fd = pwmd_open_nb(pwm, &error, filename, timeout);
413 if (fd == -1)
414 goto done;
415 else if (fd >= 0)
416 error = do_nb_command(fd, 0);
418 else
419 error = pwmd_open(pwm, filename);
420 #else
421 error = pwmd_open(pwm, filename);
422 #endif
424 if (error)
425 goto done;
428 if (filename) {
429 error = pwmd_command(pwm, &result, "LOCK");
431 if (error)
432 goto done;
435 p = fgets(command, sizeof(command), stdin);
437 if (!p)
438 goto done;
441 * This is a known INQUIRE command. We use pwmd_inquire() to send the
442 * data from the do_inquire() callback function.
444 if (strncasecmp(p, "STORE ", 6) == 0) {
445 p += 6;
446 inquire = (char *)"STORE";
448 else if (strncasecmp(p, "IMPORT ", 7) == 0) {
449 p += 7;
450 inquire = (char *)"IMPORT";
453 if (inquire) {
454 struct inquire_s *inq = (struct inquire_s *)malloc(sizeof(struct inquire_s));
456 if (!inq) {
457 error = gpg_error_from_errno(ENOMEM);
458 goto done;
461 inq->data = xstrdup(p);
462 inq->fp = inquirefp;
463 error = pwmd_inquire(pwm, inquire, do_inquire, inq);
464 free(inq);
465 goto done;
468 if (strcasecmp(p, "BYE") == 0)
469 goto done;
471 error = pwmd_command(pwm, &result, command);
472 memset(command, 0, sizeof(command));
474 if (error)
475 goto done;
477 if (result) {
478 fwrite(result, 1, strlen(result), outfp);
479 pwmd_free_result(result);
482 done:
483 memset(command, 0, sizeof(command));
485 if (!error && save) {
486 if (iter != -2) {
487 error = pwmd_command(pwm, &result, "OPTION ITERATIONS=%i", iter);
489 if (error)
490 goto done;
493 #ifdef DEBUG
494 if (method == 1) {
495 error = pwmd_save_async(pwm);
497 if (!error) {
498 do {
499 s = pwmd_process(pwm, &error);
500 fputc('.', stderr);
501 usleep(50000);
502 } while (s == ASYNC_PROCESS);
504 pwmd_finalize(pwm);
507 else if (method == 3) {
508 int fd = pwmd_save_nb(pwm, &error);
510 if (fd == -1)
511 goto done;
512 else if (fd >= 0)
513 error = do_nb_command(fd, 1);
515 else
516 error = pwmd_save(pwm);
517 #else
518 error = pwmd_save(pwm);
519 #endif
522 if (!error && filename)
523 error = pwmd_command(pwm, &result, "UNLOCK");
525 if (error) {
526 show_error(error);
527 ret = EXIT_FAILURE;
530 pwmd_close(pwm);
532 if (socketpath)
533 xfree(socketpath);
535 exit(ret);