In pwmc, LOCK the opened data file.
[libpwmd.git] / pwmc.c
blob3d93d4cae53c0c9ba3502ad4440957196151956d
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 02111-1307 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 #ifdef DEBUG
65 "Usage: pwmc [-hvX] [-s <socket>] [-E <n> -P -T -N -D | -p <password>] [-S [-i <iter>]]\n"
66 #else
67 "Usage: pwmc [-hvX] [-s <socket>] [-P -T -N -D | -p <password>]\n"
68 #endif
69 " [-S [-i <iter>]] [-c <name>] [-d <fd>] [-I <fd>] [filename]\n"
70 #ifdef DEBUG
71 " -E pinentry method (0=pwmd, 1=pwmd async, 2=libpwmd, 3=libpwmd nb)\n"
72 " -M pinentry timeout (method 3 only)\n"
73 #endif
74 " -X disable showing of status messages from the server\n"
75 " -c set the client name\n"
76 " -s socket path (~/.pwmd/socket)\n"
77 " -p password\n"
78 " -P path to the pinentry binary (server default)\n"
79 " -T pinentry tty\n"
80 " -N pinentry terminal type\n"
81 " -D pinentry display\n"
82 " -d redirect command output to the specified file descriptor\n"
83 " -I read inquire data from the specified file descriptor\n"
84 " -S send the SAVE command before exiting\n"
85 " -i encrypt with the specified number of iterations (-1 = 0 iterations)\n"
86 " -v version\n"
87 " -h this help text\n"));
88 exit(EXIT_FAILURE);
91 struct inquire_s {
92 FILE *fp;
93 char *data;
96 static gpg_error_t do_inquire(void *data, const char *keyword, gpg_error_t rc,
97 char **result, size_t *result_len)
99 int c;
100 static char buf[ASSUAN_LINELENGTH];
101 char *p;
102 size_t len = 0;
103 struct inquire_s *inq = (struct inquire_s *)data;
105 if (rc) {
106 memset(buf, 0, sizeof(buf));
107 return rc;
110 buf[0] = 0;
111 p = buf;
113 if (inq->data) {
114 snprintf(buf, sizeof(buf), "%s", inq->data);
115 xfree(inq->data);
116 inq->data = NULL;
117 len = strlen(buf);
118 p = buf + len;
121 while ((c = fgetc(inq->fp)) != EOF) {
122 if (len == sizeof(buf)) {
123 ungetc(c, inq->fp);
124 break;
127 *p++ = c;
128 len++;
131 if (!buf[0]) {
132 memset(buf, 0, sizeof(buf));
133 return GPG_ERR_EOF;
136 *result = buf;
137 *result_len = len;
138 return 0;
141 static int status_msg_cb(void *data, const char *line)
143 fprintf(stderr, "%s\n", line);
144 return 0;
147 #ifdef DEBUG
148 static gpg_error_t do_nb_command(int fd, int which)
150 int n;
151 gpg_error_t error = 0;
153 fcntl(fd, F_SETFL, O_NONBLOCK);
155 do {
156 fd_set fds;
157 struct timeval tv = {0, 50000};
159 FD_ZERO(&fds);
160 FD_SET(fd, &fds);
161 n = select(fd+1, &fds, NULL, NULL, &tv);
163 if (n > 0) {
164 if (FD_ISSET(fd, &fds)) {
165 pwmd_nb_status_t status;
167 n = read(fd, &status, sizeof(status));
169 if (n == -1) {
170 error = gpg_error_from_errno(errno);
171 goto done;
174 if (!which)
175 error = pwmd_open_nb_finalize(pwm, &status);
176 else
177 error = pwmd_save_nb_finalize(pwm, &status);
179 if (error)
180 goto done;
183 else
184 fprintf(stderr, "Waiting ...\n");
185 } while (n == 0);
187 done:
188 return error;
190 #endif
192 int main(int argc, char *argv[])
194 int opt;
195 char *password = NULL;
196 char *filename = NULL;
197 char *socketpath = NULL;
198 char command[ASSUAN_LINELENGTH], *p;
199 int ret = EXIT_SUCCESS;
200 gpg_error_t error;
201 char *result = NULL;
202 int save = 0;
203 char *pinentry_path = NULL;
204 char *display = NULL, *tty = NULL, *ttytype = NULL;
205 int outfd = STDOUT_FILENO;
206 FILE *outfp = stdout;
207 int inquirefd = STDIN_FILENO;
208 FILE *inquirefp = stdin;
209 int show_status = 1;
210 char *clientname = NULL;
211 char *inquire = NULL;
212 int iter = -2;
213 #ifdef DEBUG
214 int method = 0;
215 pwmd_async_t s;
216 int timeout = 0;
217 #endif
219 setlocale(LC_ALL, "");
220 bindtextdomain("libpwmd", LOCALEDIR);
222 #ifdef DEBUG
223 while ((opt = getopt(argc, argv, "E:M:c:I:XT:N:D:hvP:p:s:Si:d:")) != EOF) {
224 #else
225 while ((opt = getopt(argc, argv, "c:I:XT:N:D:hvP:p:s:Si:d:")) != EOF) {
226 #endif
227 switch (opt) {
228 #ifdef DEBUG
229 case 'E':
230 method = atoi(optarg);
231 break;
232 case 'M':
233 timeout = atoi(optarg);
234 break;
235 #endif
236 case 'c':
237 clientname = xstrdup(optarg);
238 break;
239 case 'X':
240 show_status = 0;
241 break;
242 case 'T':
243 tty = optarg;
244 break;
245 case 'N':
246 ttytype = optarg;
247 break;
248 case 'D':
249 display = optarg;
250 break;
251 case 'I':
252 inquirefd = atoi(optarg);
253 inquirefp = fdopen(inquirefd, "r");
255 if (!inquirefp) {
256 xfree(password);
257 err(EXIT_FAILURE, "%i", inquirefd);
259 break;
260 case 'd':
261 outfd = atoi(optarg);
262 outfp = fdopen(outfd, "w");
264 if (!outfp) {
265 xfree(password);
266 err(EXIT_FAILURE, "%i", outfd);
268 break;
269 case 'S':
270 save = 1;
271 break;
272 case 'i':
273 iter = atoi(optarg);
275 if (iter < -1) {
276 xfree(password);
277 usage(argv[0]);
279 break;
280 case 's':
281 socketpath = xstrdup(optarg);
282 break;
283 case 'p':
284 password = xstrdup(optarg);
285 memset(optarg, 0, strlen(optarg));
286 break;
287 case 'P':
288 pinentry_path = xstrdup(optarg);
289 break;
290 case 'v':
291 xfree(password);
292 printf("%s (pwmc)\n%s\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
293 exit(EXIT_SUCCESS);
294 case 'h':
295 default:
296 xfree(password);
297 usage(argv[0]);
301 filename = argv[optind];
302 pwmd_init();
304 if ((pwm = pwmd_connect(socketpath, &error)) == NULL) {
305 xfree(password);
306 errx(EXIT_FAILURE, "pwmd_connect(): %s", pwmd_strerror(error));
309 error = pwmd_command(pwm, &result, "OPTION CLIENT NAME=%s", clientname ? clientname : "pwmc");
310 xfree(clientname);
312 if (error) {
313 xfree(password);
314 errx(EXIT_FAILURE, "pwmd_connect(): %s", pwmd_strerror(error));
317 if (password) {
318 error = pwmd_setopt(pwm, PWMD_OPTION_PASSWORD, password);
320 if (error) {
321 xfree(password);
322 goto done;
325 xfree(password);
327 else {
328 if (pinentry_path) {
329 error = pwmd_command(pwm, &result, "OPTION PATH=%s", pinentry_path);
331 if (error)
332 goto done;
335 if (display) {
336 error = pwmd_command(pwm, &result, "OPTION DISPLAY=%s", display);
338 if (error)
339 goto done;
342 if (tty) {
343 error = pwmd_command(pwm, &result, "OPTION TTYNAME=%s", tty);
345 if (error)
346 goto done;
349 if (ttytype) {
350 error = pwmd_command(pwm, &result, "OPTION TTYTYPE=%s", ttytype);
352 if (error)
353 goto done;
355 #ifdef DEBUG
356 if (method >= 2) {
357 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY, 1);
359 if (error)
360 goto done;
362 #endif
365 if (show_status) {
366 error = pwmd_setopt(pwm, PWMD_OPTION_STATUS_FUNC, status_msg_cb);
368 if (error)
369 goto done;
372 if (filename) {
373 #ifdef DEBUG
374 if (method == 1) {
375 error = pwmd_open_async(pwm, filename);
377 if (!error) {
378 do {
379 s = pwmd_process(pwm, &error);
380 fprintf(stderr, "Waiting ...\n");
381 usleep(50000);
382 } while (s == ASYNC_PROCESS);
384 pwmd_finalize(pwm);
387 else if (method == 3) {
388 int fd = pwmd_open_nb(pwm, &error, filename, timeout);
390 if (fd == -1)
391 goto done;
392 else if (fd >= 0)
393 error = do_nb_command(fd, 0);
395 else
396 error = pwmd_open(pwm, filename);
397 #else
398 error = pwmd_open(pwm, filename);
399 #endif
401 if (error)
402 goto done;
405 error = pwmd_command(pwm, &result, "LOCK");
407 if (error)
408 goto done;
410 p = fgets(command, sizeof(command), stdin);
412 if (!p)
413 goto done;
416 * This is a known INQUIRE command. We use pwmd_inquire() to send the
417 * data from the do_inquire() callback function.
419 if (strncasecmp(p, "STORE ", 6) == 0) {
420 p += 6;
421 inquire = (char *)"STORE";
423 else if (strncasecmp(p, "IMPORT ", 7) == 0) {
424 p += 7;
425 inquire = (char *)"IMPORT";
428 if (inquire) {
429 struct inquire_s *inq = (struct inquire_s *)malloc(sizeof(struct inquire_s));
431 if (!inq) {
432 error = gpg_error_from_errno(ENOMEM);
433 goto done;
436 inq->data = xstrdup(p);
437 inq->fp = inquirefp;
438 error = pwmd_inquire(pwm, inquire, do_inquire, inq);
439 free(inq);
440 goto done;
443 if (strcasecmp(p, "BYE") == 0)
444 goto done;
446 error = pwmd_command(pwm, &result, command);
447 memset(command, 0, sizeof(command));
449 if (error)
450 goto done;
452 if (result) {
453 fwrite(result, 1, strlen(result), outfp);
454 pwmd_free_result(result);
457 done:
458 memset(command, 0, sizeof(command));
460 if (!error && save) {
461 if (iter != -2) {
462 error = pwmd_command(pwm, &result, "OPTION ITERATIONS=%i", iter);
464 if (error)
465 goto done;
468 #ifdef DEBUG
469 if (method == 1) {
470 error = pwmd_save_async(pwm);
472 if (!error) {
473 do {
474 s = pwmd_process(pwm, &error);
475 fprintf(stderr, "Waiting ...\n");
476 usleep(50000);
477 } while (s == ASYNC_PROCESS);
479 pwmd_finalize(pwm);
482 else if (method == 3) {
483 int fd = pwmd_save_nb(pwm, &error);
485 if (fd == -1)
486 goto done;
487 else if (fd >= 0)
488 error = do_nb_command(fd, 1);
490 else
491 error = pwmd_save(pwm);
492 #else
493 error = pwmd_save(pwm);
494 #endif
497 if (!error)
498 error = pwmd_command(pwm, &result, "UNLOCK");
500 if (error) {
501 show_error(error);
502 ret = EXIT_FAILURE;
505 pwmd_close(pwm);
507 if (socketpath)
508 xfree(socketpath);
510 exit(ret);