Make pwmd_open_nb(), pwmd_save_nb(), pwmd_open_nb_finalize(),
[libpwmd.git] / pwmc.c
blob24f238e42d6b4a5b4ac296f820286c09940071e8
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] \n"
66 #else
67 "Usage: pwmc [-hvX] [-s <socket>] [-P -T -N -D | -p <password>] [-S] \n"
68 #endif
69 " [-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 " -v version\n"
86 " -h this help text\n"));
87 exit(EXIT_FAILURE);
90 struct inquire_s {
91 FILE *fp;
92 char *data;
95 static gpg_error_t do_inquire(void *data, const char *keyword, gpg_error_t rc,
96 char **result, size_t *result_len)
98 int c;
99 static char buf[ASSUAN_LINELENGTH];
100 char *p;
101 size_t len = 0;
102 struct inquire_s *inq = (struct inquire_s *)data;
104 if (rc) {
105 memset(buf, 0, sizeof(buf));
106 return rc;
109 buf[0] = 0;
110 p = buf;
112 if (inq->data) {
113 snprintf(buf, sizeof(buf), "%s", inq->data);
114 xfree(inq->data);
115 inq->data = NULL;
116 len = strlen(buf);
117 p = buf + len;
120 while ((c = fgetc(inq->fp)) != EOF) {
121 if (len == sizeof(buf)) {
122 ungetc(c, inq->fp);
123 break;
126 *p++ = c;
127 len++;
130 if (!buf[0]) {
131 memset(buf, 0, sizeof(buf));
132 return GPG_ERR_EOF;
135 *result = buf;
136 *result_len = len;
137 return 0;
140 static int status_msg_cb(void *data, const char *line)
142 fprintf(stderr, "%s\n", line);
143 return 0;
146 #ifdef DEBUG
147 static gpg_error_t do_nb_command(int fd, int which)
149 int n;
150 gpg_error_t error = 0;
152 fcntl(fd, F_SETFL, O_NONBLOCK);
154 do {
155 fd_set fds;
156 struct timeval tv = {0, 50000};
158 FD_ZERO(&fds);
159 FD_SET(fd, &fds);
160 n = select(fd+1, &fds, NULL, NULL, &tv);
162 if (n > 0) {
163 if (FD_ISSET(fd, &fds)) {
164 pwmd_nb_status_t status;
166 n = read(fd, &status, sizeof(status));
168 if (n == -1) {
169 error = gpg_error_from_errno(errno);
170 goto done;
173 if (!which)
174 error = pwmd_open_nb_finalize(pwm, &status);
175 else
176 error = pwmd_save_nb_finalize(pwm, &status);
178 if (error)
179 goto done;
182 else
183 fprintf(stderr, "Waiting ...\n");
184 } while (n == 0);
186 done:
187 return error;
189 #endif
191 int main(int argc, char *argv[])
193 int opt;
194 char *password = NULL;
195 char *filename = NULL;
196 char *socketpath = NULL;
197 char command[ASSUAN_LINELENGTH], *p;
198 int ret = EXIT_SUCCESS;
199 gpg_error_t error;
200 char *result = NULL;
201 int save = 0;
202 char *pinentry_path = NULL;
203 char *display = NULL, *tty = NULL, *ttytype = NULL;
204 int outfd = STDOUT_FILENO;
205 FILE *outfp = stdout;
206 int inquirefd = STDIN_FILENO;
207 FILE *inquirefp = stdin;
208 int show_status = 1;
209 char *clientname = NULL;
210 char *inquire = NULL;
211 #ifdef DEBUG
212 int method = 0;
213 pwmd_async_t s;
214 int timeout = 0;
215 #endif
217 setlocale(LC_ALL, "");
218 bindtextdomain("libpwmd", LOCALEDIR);
220 #ifdef DEBUG
221 while ((opt = getopt(argc, argv, "E:M:c:I:XT:N:D:hvP:p:s:Sd:")) != EOF) {
222 #else
223 while ((opt = getopt(argc, argv, "c:I:XT:N:D:hvP:p:s:Sd:")) != EOF) {
224 #endif
225 switch (opt) {
226 #ifdef DEBUG
227 case 'E':
228 method = atoi(optarg);
229 break;
230 case 'M':
231 timeout = atoi(optarg);
232 break;
233 #endif
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 's':
271 socketpath = xstrdup(optarg);
272 break;
273 case 'p':
274 password = xstrdup(optarg);
275 memset(optarg, 0, strlen(optarg));
276 break;
277 case 'P':
278 pinentry_path = xstrdup(optarg);
279 break;
280 case 'v':
281 xfree(password);
282 printf("%s (pwmc)\n%s\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
283 exit(EXIT_SUCCESS);
284 case 'h':
285 default:
286 xfree(password);
287 usage(argv[0]);
291 filename = argv[optind];
292 pwmd_init();
294 if ((pwm = pwmd_connect(socketpath, &error)) == NULL) {
295 xfree(password);
296 errx(EXIT_FAILURE, "pwmd_connect(): %s", pwmd_strerror(error));
299 error = pwmd_command(pwm, &result, "OPTION CLIENT NAME=%s", clientname ? clientname : "pwmc");
300 xfree(clientname);
302 if (error) {
303 xfree(password);
304 errx(EXIT_FAILURE, "pwmd_connect(): %s", pwmd_strerror(error));
307 if (password) {
308 error = pwmd_setopt(pwm, PWMD_OPTION_PASSWORD, password);
310 if (error) {
311 xfree(password);
312 goto done;
315 xfree(password);
317 else {
318 if (pinentry_path) {
319 error = pwmd_command(pwm, &result, "OPTION PATH=%s", pinentry_path);
321 if (error)
322 goto done;
325 if (display) {
326 error = pwmd_command(pwm, &result, "OPTION DISPLAY=%s", display);
328 if (error)
329 goto done;
332 if (tty) {
333 error = pwmd_command(pwm, &result, "OPTION TTYNAME=%s", tty);
335 if (error)
336 goto done;
339 if (ttytype) {
340 error = pwmd_command(pwm, &result, "OPTION TTYTYPE=%s", ttytype);
342 if (error)
343 goto done;
345 #ifdef DEBUG
346 if (method >= 2) {
347 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY, 1);
349 if (error)
350 goto done;
352 #endif
355 if (show_status) {
356 error = pwmd_setopt(pwm, PWMD_OPTION_STATUS_FUNC, status_msg_cb);
358 if (error)
359 goto done;
362 if (filename) {
363 #ifdef DEBUG
364 if (method == 1) {
365 error = pwmd_open_async(pwm, filename);
367 if (!error) {
368 do {
369 s = pwmd_process(pwm, &error);
370 fprintf(stderr, "Waiting ...\n");
371 usleep(50000);
372 } while (s == ASYNC_PROCESS);
374 pwmd_finalize(pwm);
377 else if (method == 3) {
378 int fd = pwmd_open_nb(pwm, &error, filename, timeout);
380 if (fd == -1)
381 goto done;
382 else if (fd >= 0)
383 error = do_nb_command(fd, 0);
385 else
386 error = pwmd_open(pwm, filename);
387 #else
388 error = pwmd_open(pwm, filename);
389 #endif
391 if (error)
392 goto done;
395 p = fgets(command, sizeof(command), stdin);
397 if (!p)
398 goto done;
401 * This is a known INQUIRE command. We use pwmd_inquire() to send the
402 * data from the do_inquire() callback function.
404 if (strncasecmp(p, "STORE ", 6) == 0) {
405 p += 6;
406 inquire = "STORE";
408 else if (strncasecmp(p, "IMPORT ", 7) == 0) {
409 p += 7;
410 inquire = "IMPORT";
413 if (inquire) {
414 struct inquire_s *inq = (struct inquire_s *)malloc(sizeof(struct inquire_s));
416 if (!inq) {
417 error = gpg_error_from_errno(ENOMEM);
418 goto done;
421 inq->data = xstrdup(p);
422 inq->fp = inquirefp;
423 error = pwmd_inquire(pwm, inquire, do_inquire, inq);
424 free(inq);
425 goto done;
428 if (strcasecmp(p, "BYE") == 0)
429 goto done;
431 error = pwmd_command(pwm, &result, command);
432 memset(command, 0, sizeof(command));
434 if (error)
435 goto done;
437 if (result) {
438 fwrite(result, 1, strlen(result), outfp);
439 pwmd_free_result(result);
442 done:
443 memset(command, 0, sizeof(command));
445 if (!error && save) {
446 #ifdef DEBUG
447 if (method == 1) {
448 error = pwmd_save_async(pwm);
450 if (!error) {
451 do {
452 s = pwmd_process(pwm, &error);
453 fprintf(stderr, "Waiting ...\n");
454 usleep(50000);
455 } while (s == ASYNC_PROCESS);
457 pwmd_finalize(pwm);
460 else if (method == 3) {
461 int fd = pwmd_save_nb(pwm, &error);
463 if (fd == -1)
464 goto done;
465 else if (fd >= 0)
466 error = do_nb_command(fd, 1);
468 else
469 error = pwmd_save(pwm);
470 #else
471 error = pwmd_save(pwm);
472 #endif
475 if (error) {
476 show_error(error);
477 ret = EXIT_FAILURE;
480 pwmd_close(pwm);
482 if (socketpath)
483 xfree(socketpath);
485 exit(ret);