Compile time fix for -DMEM_DEBUG.
[libpwmd.git] / pwmc.c
blobcf19e4f4256f17611329105cac936c554e27e8d3
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2007-2009 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 #include "mem.h"
45 pwm_t *pwm;
47 static void show_error(gpg_error_t error)
49 fprintf(stderr, "ERR %i %s\n", gpg_err_code(error), pwmd_strerror(error));
52 static void usage(const char *pn)
54 fprintf(stderr, N_(
55 "Reads PWMD protocol commands from standard input.\n\n"
56 "Usage: pwmc [-hvX] [-s <socket>] "
57 #ifdef DEBUG
58 "[-E <n>] [-y <n>]"
59 #endif
60 "[-PTND <string>] [-p <passphrase>]\n"
61 " [-S [-i <iter>]] [-c <name>] [-t <n>] [-d <fd>] [-I <fd>]\n"
62 " [filename]\n"
63 #ifdef DEBUG
64 " -E pinentry method (0=pwmd, 1=pwmd async, 2=libpwmd nb)\n"
65 " -y number of pinentry tries before failing (3)\n"
66 #endif
67 " -t pinentry timeout\n"
68 " -X disable showing of status messages from the server\n"
69 " -c set the client name\n"
70 " -s socket path (~/.pwmd/socket)\n"
71 " -p passphrase\n"
72 " -P path to the pinentry binary (server default)\n"
73 " -T pinentry tty\n"
74 " -N pinentry terminal type\n"
75 " -D pinentry display\n"
76 " -d redirect command output to the specified file descriptor\n"
77 " -I read inquire data from the specified file descriptor\n"
78 " -S send the SAVE command before exiting\n"
79 " -i encrypt with the specified number of iterations (-1 = 0 iterations)\n"
80 " -v version\n"
81 " -h this help text\n"));
82 exit(EXIT_FAILURE);
85 struct inquire_s {
86 FILE *fp;
87 char *data;
90 static gpg_error_t do_inquire(void *data, const char *keyword, gpg_error_t rc,
91 char **result, size_t *result_len)
93 int c;
94 static char buf[ASSUAN_LINELENGTH];
95 char *p;
96 size_t len = 0;
97 struct inquire_s *inq = (struct inquire_s *)data;
99 if (rc) {
100 memset(buf, 0, sizeof(buf));
101 return rc;
104 buf[0] = 0;
105 p = buf;
107 if (inq->data) {
108 snprintf(buf, sizeof(buf), "%s", inq->data);
109 xfree(inq->data);
110 inq->data = NULL;
111 len = strlen(buf);
112 p = buf + len;
115 while ((c = fgetc(inq->fp)) != EOF) {
116 if (len == sizeof(buf)) {
117 ungetc(c, inq->fp);
118 break;
121 *p++ = c;
122 len++;
125 if (!buf[0]) {
126 memset(buf, 0, sizeof(buf));
127 return GPG_ERR_EOF;
130 *result = buf;
131 *result_len = len;
132 return 0;
135 static int status_msg_cb(void *data, const char *line)
137 fprintf(stderr, "%s\n", line);
138 return 0;
141 #ifdef DEBUG
142 static gpg_error_t do_nb_command(int fd, int which)
144 int n;
145 gpg_error_t error = 0;
147 fcntl(fd, F_SETFL, O_NONBLOCK);
149 do {
150 fd_set fds;
151 struct timeval tv = {0, 50000};
153 FD_ZERO(&fds);
154 FD_SET(fd, &fds);
155 n = select(fd+1, &fds, NULL, NULL, &tv);
157 if (n > 0) {
158 if (FD_ISSET(fd, &fds)) {
159 pwmd_nb_status_t status;
161 n = read(fd, &status, sizeof(status));
163 if (n == -1) {
164 error = gpg_error_from_errno(errno);
165 goto done;
168 if (!which)
169 error = pwmd_open_nb_finalize(pwm, &status);
170 else
171 error = pwmd_save_nb_finalize(pwm, &status);
173 if (error)
174 goto done;
177 else
178 fputc('.', stderr);
179 } while (n == 0);
181 done:
182 return error;
184 #endif
186 int main(int argc, char *argv[])
188 int opt;
189 char *password = NULL;
190 char *filename = NULL;
191 char *socketpath = NULL;
192 char command[ASSUAN_LINELENGTH], *p;
193 int ret = EXIT_SUCCESS;
194 gpg_error_t error;
195 char *result = NULL;
196 int save = 0;
197 char *pinentry_path = NULL;
198 char *display = NULL, *tty = NULL, *ttytype = NULL;
199 int outfd = STDOUT_FILENO;
200 FILE *outfp = stdout;
201 int inquirefd = STDIN_FILENO;
202 FILE *inquirefp = stdin;
203 int show_status = 1;
204 char *clientname = NULL;
205 char *inquire = NULL;
206 int iter = -2;
207 int timeout = 0;
208 #ifdef DEBUG
209 int tries = 0;
210 int method = 0;
211 pwmd_async_t s;
212 #endif
214 setlocale(LC_ALL, "");
215 bindtextdomain("libpwmd", LOCALEDIR);
217 #ifdef DEBUG
218 while ((opt = getopt(argc, argv, "y:t:E:c:I:XT:N:D:hvP:p:s:Si:d:")) != EOF) {
219 #else
220 while ((opt = getopt(argc, argv, "t:c:I:XT:N:D:hvP:p:s:Si:d:")) != EOF) {
221 #endif
222 switch (opt) {
223 #ifdef DEBUG
224 case 'E':
225 method = atoi(optarg);
226 break;
227 case 'y':
228 tries = atoi(optarg);
229 break;
230 #endif
231 case 't':
232 timeout = atoi(optarg);
233 break;
234 case 'c':
235 clientname = xstrdup(optarg);
236 break;
237 case 'X':
238 show_status = 0;
239 break;
240 case 'T':
241 tty = optarg;
242 break;
243 case 'N':
244 ttytype = optarg;
245 break;
246 case 'D':
247 display = optarg;
248 break;
249 case 'I':
250 inquirefd = atoi(optarg);
251 inquirefp = fdopen(inquirefd, "r");
253 if (!inquirefp) {
254 xfree(password);
255 err(EXIT_FAILURE, "%i", inquirefd);
257 break;
258 case 'd':
259 outfd = atoi(optarg);
260 outfp = fdopen(outfd, "w");
262 if (!outfp) {
263 xfree(password);
264 err(EXIT_FAILURE, "%i", outfd);
266 break;
267 case 'S':
268 save = 1;
269 break;
270 case 'i':
271 iter = atoi(optarg);
273 if (iter < -1) {
274 xfree(password);
275 usage(argv[0]);
277 break;
278 case 's':
279 socketpath = xstrdup(optarg);
280 break;
281 case 'p':
282 password = xstrdup(optarg);
283 memset(optarg, 0, strlen(optarg));
284 break;
285 case 'P':
286 pinentry_path = xstrdup(optarg);
287 break;
288 case 'v':
289 xfree(password);
290 printf("%s (pwmc)\n%s\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
291 exit(EXIT_SUCCESS);
292 case 'h':
293 default:
294 xfree(password);
295 usage(argv[0]);
299 filename = argv[optind];
300 pwmd_init();
302 if ((pwm = pwmd_connect(socketpath, &error)) == NULL) {
303 xfree(password);
304 errx(EXIT_FAILURE, "pwmd_connect(): %s", pwmd_strerror(error));
307 error = pwmd_command(pwm, &result, "OPTION CLIENT NAME=%s", clientname ? clientname : "pwmc");
308 xfree(clientname);
310 if (error) {
311 xfree(password);
312 errx(EXIT_FAILURE, "pwmd_command(): %s", pwmd_strerror(error));
315 if (timeout > 0) {
316 error = pwmd_command(pwm, &result, "OPTION TIMEOUT=%i", timeout);
318 if (error) {
319 xfree(password);
320 errx(EXIT_FAILURE, "pwmd_command(): %s", pwmd_strerror(error));
324 if (password) {
325 error = pwmd_setopt(pwm, PWMD_OPTION_PASSWORD, password);
327 if (error) {
328 xfree(password);
329 goto done;
332 xfree(password);
334 else {
335 if (pinentry_path) {
336 error = pwmd_command(pwm, &result, "OPTION PATH=%s", pinentry_path);
338 if (error)
339 goto done;
342 if (display) {
343 error = pwmd_command(pwm, &result, "OPTION DISPLAY=%s", display);
345 if (error)
346 goto done;
349 if (tty) {
350 error = pwmd_command(pwm, &result, "OPTION TTYNAME=%s", tty);
352 if (error)
353 goto done;
356 if (ttytype) {
357 error = pwmd_command(pwm, &result, "OPTION TTYTYPE=%s", ttytype);
359 if (error)
360 goto done;
362 #ifdef DEBUG
363 if (method >= 2) {
364 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY, 1);
366 if (error)
367 goto done;
370 if (tries > 0) {
371 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TRIES, tries);
373 if (error)
374 goto done;
376 #endif
379 if (show_status) {
380 error = pwmd_setopt(pwm, PWMD_OPTION_STATUS_FUNC, status_msg_cb);
382 if (error)
383 goto done;
386 if (filename) {
387 #ifdef DEBUG
388 /* This method doesn't support PWMD_OPTION_PINENTRY_TRIES. */
389 if (method == 1) {
390 error = pwmd_open_async(pwm, filename);
392 if (!error) {
393 do {
394 s = pwmd_process(pwm, &error);
395 fputc('.', stderr);
396 usleep(50000);
397 } while (s == ASYNC_PROCESS);
399 pwmd_finalize(pwm);
402 else if (method == 2) {
403 int fd = pwmd_open_nb(pwm, &error, filename, timeout);
405 if (fd == -1)
406 goto done;
407 else if (fd >= 0)
408 error = do_nb_command(fd, 0);
410 else
411 error = pwmd_open(pwm, filename);
412 #else
413 error = pwmd_open(pwm, filename);
414 #endif
416 if (error)
417 goto done;
420 if (filename) {
421 error = pwmd_command(pwm, &result, "LOCK");
423 if (error)
424 goto done;
427 p = fgets(command, sizeof(command), stdin);
429 if (!p)
430 goto done;
433 * This is a known INQUIRE command. We use pwmd_inquire() to send the
434 * data from the do_inquire() callback function.
436 if (strncasecmp(p, "STORE ", 6) == 0) {
437 p += 6;
438 inquire = (char *)"STORE";
440 else if (strncasecmp(p, "IMPORT ", 7) == 0) {
441 p += 7;
442 inquire = (char *)"IMPORT";
445 if (inquire) {
446 struct inquire_s *inq = (struct inquire_s *)malloc(sizeof(struct inquire_s));
448 if (!inq) {
449 error = gpg_error_from_errno(ENOMEM);
450 goto done;
453 inq->data = xstrdup(p);
454 inq->fp = inquirefp;
455 error = pwmd_inquire(pwm, inquire, do_inquire, inq);
456 free(inq);
457 goto done;
460 if (strcasecmp(p, "BYE") == 0)
461 goto done;
463 error = pwmd_command(pwm, &result, command);
464 memset(command, 0, sizeof(command));
466 if (error)
467 goto done;
469 if (result) {
470 fwrite(result, 1, strlen(result), outfp);
471 pwmd_free_result(result);
474 done:
475 memset(command, 0, sizeof(command));
477 if (!error && save) {
478 if (iter != -2) {
479 error = pwmd_command(pwm, &result, "OPTION ITERATIONS=%i", iter);
481 if (error)
482 goto done;
485 #ifdef DEBUG
486 if (method == 1) {
487 error = pwmd_save_async(pwm);
489 if (!error) {
490 do {
491 s = pwmd_process(pwm, &error);
492 fputc('.', stderr);
493 usleep(50000);
494 } while (s == ASYNC_PROCESS);
496 pwmd_finalize(pwm);
499 else if (method == 3) {
500 int fd = pwmd_save_nb(pwm, &error);
502 if (fd == -1)
503 goto done;
504 else if (fd >= 0)
505 error = do_nb_command(fd, 1);
507 else
508 error = pwmd_save(pwm);
509 #else
510 error = pwmd_save(pwm);
511 #endif
514 if (!error && filename)
515 error = pwmd_command(pwm, &result, "UNLOCK");
517 if (error) {
518 show_error(error);
519 ret = EXIT_FAILURE;
522 pwmd_close(pwm);
524 if (socketpath)
525 xfree(socketpath);
527 exit(ret);