Make sure the STORE command has following data.
[libpwmd.git] / pwmc.c
blob67b9e5505c56d2f7431802d045cacc0dba56302d
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2007 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 <signal.h>
26 #include <termios.h>
27 #include <libpwmd.h>
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
33 #ifdef HAVE_LOCALE_H
34 #include <locale.h>
35 #endif
37 #include "gettext.h"
38 #define N_(msgid) gettext(msgid)
40 #ifndef MEM_DEBUG
41 #include "mem.h"
42 #else
43 #define xfree free
44 #define xrealloc realloc
45 #define xmalloc malloc
46 #define xstrdup strdup
47 #define xcalloc calloc
48 #endif
50 int timeout, elapsed;
51 pwm_t *pwm;
53 static void show_error(gpg_error_t error)
55 fprintf(stderr, "ERR %i %s\n", gpg_err_code(error), pwmd_strerror(error));
58 void catchsig(int sig)
60 gpg_error_t error;
62 switch (sig) {
63 case SIGALRM:
64 if (pwm && timeout > 0 && elapsed++ >= timeout) {
65 error = pwmd_terminate_pinentry(pwm);
67 if (error)
68 show_error(error);
70 break;
73 alarm(1);
74 break;
75 default:
76 break;
80 static void usage(const char *pn)
82 fprintf(stderr, N_(
83 "Reads PWMD protocol commands from standard input.\n\n"
84 "Usage: pwmc [-hvX] [-s <socket>] [[-a [-P -T -N -D] [-t <seconds>]] |\n"
85 " [-p <password>]] [-S] [-d <n>] [-I <n>] [filename]\n"
86 " -X disable showing of status messages from the server\n"
87 " -s socket path\n"
88 " -p password\n"
89 " -a use pinentry(1) for password retrieval\n"
90 " -P path to the pinentry binary (%s)\n"
91 " -T pinentry tty\n"
92 " -N pinentry terminal type\n"
93 " -D pinentry display\n"
94 " -t pinentry timeout\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 after all others\n"
98 " -v version\n"
99 " -h this help text\n"), PINENTRY_PATH);
100 exit(EXIT_FAILURE);
103 int set_pinentry_option(pwmd_option_t option, void *value)
105 gpg_error_t error;
107 error = pwmd_setopt(pwm, option, value);
109 if (error) {
110 show_error(error);
111 pwmd_close(pwm);
112 return 1;
115 return 0;
118 struct inquire_s {
119 FILE *fp;
120 char *data;
123 static int do_inquire(void *data, const char *keyword, gpg_error_t rc,
124 char **result, size_t *result_len)
126 int c;
127 static char buf[1000]; /* Assuan protocol line length limit. */
128 char *p;
129 size_t len = 0;
130 struct inquire_s *inq = data;
132 if (rc) {
133 memset(buf, 0, sizeof(buf));
134 return rc;
137 if (!inq)
138 return EPWMD_COMMAND_SYNTAX;
140 buf[0] = 0;
141 p = buf;
143 if (inq->data) {
144 snprintf(buf, sizeof(buf), "%s", inq->data);
145 xfree(inq->data);
146 inq->data = NULL;
147 len = strlen(buf);
148 goto done;
151 while ((c = fgetc(inq->fp)) != EOF) {
152 if (len >= sizeof(buf)) {
153 ungetc(c, stdin);
154 break;
157 *p++ = c;
158 len++;
161 if (!buf[0]) {
162 memset(buf, 0, sizeof(buf));
163 return GPG_ERR_EOF;
166 done:
167 *result = buf;
168 *result_len = len;
169 return 0;
172 static int status_msg_cb(void *data, const char *line)
174 fprintf(stderr, "%s\n", line);
175 return 0;
178 int main(int argc, char *argv[])
180 int opt;
181 int use_pinentry = 0;
182 char *password = NULL;
183 char *filename = NULL;
184 char *socketpath = NULL;
185 char command[1000], *p;
186 int ret = EXIT_SUCCESS;
187 gpg_error_t error;
188 char *result = NULL;
189 int save = 0;
190 char *pinentry_path = NULL;
191 char *display = NULL, *tty = NULL, *ttytype = NULL;
192 struct termios term;
193 int outfd = STDOUT_FILENO;
194 FILE *outfp = stdout;
195 int inquirefd = STDIN_FILENO;
196 FILE *inquirefp = stdin;
197 int show_status = 1;
199 setlocale(LC_ALL, "");
200 bindtextdomain("libpwmd", LOCALEDIR);
201 timeout = -1;
203 while ((opt = getopt(argc, argv, "I:XT:N:D:hvaP:t:p:s:Sd:")) != EOF) {
204 switch (opt) {
205 case 'X':
206 show_status = 0;
207 break;
208 case 'T':
209 tty = optarg;
210 break;
211 case 'N':
212 ttytype = optarg;
213 break;
214 case 'D':
215 display = optarg;
216 break;
217 case 'I':
218 inquirefd = atoi(optarg);
219 inquirefp = fdopen(inquirefd, "r");
221 if (!inquirefp) {
222 xfree(password);
223 err(EXIT_FAILURE, "%i", inquirefd);
225 break;
226 case 'd':
227 outfd = atoi(optarg);
228 outfp = fdopen(outfd, "w");
230 if (!outfp) {
231 xfree(password);
232 err(EXIT_FAILURE, "%i", outfd);
234 break;
235 case 'S':
236 save = 1;
237 break;
238 case 's':
239 socketpath = xstrdup(optarg);
240 break;
241 case 'p':
242 password = xstrdup(optarg);
243 break;
244 case 'a':
245 use_pinentry = 1;
246 break;
247 case 'P':
248 pinentry_path = xstrdup(optarg);
249 break;
250 case 't':
251 timeout = atoi(optarg);
252 break;
253 case 'v':
254 xfree(password);
255 printf("%s (pwmc)\n%s\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
256 exit(EXIT_SUCCESS);
257 case 'h':
258 default:
259 xfree(password);
260 usage(argv[0]);
264 if (use_pinentry && password) {
265 xfree(password);
266 usage(argv[0]);
269 filename = argv[optind];
270 pwmd_init();
272 if ((pwm = pwmd_connect(socketpath, &error)) == NULL) {
273 xfree(password);
274 errx(EXIT_FAILURE, "pwmd_connect(): %s", pwmd_strerror(error));
277 if (password) {
278 if (set_pinentry_option(PWMD_OPTION_PASSWORD, password)) {
279 xfree(password);
280 exit(EXIT_FAILURE);
283 xfree(password);
285 else if (use_pinentry) {
286 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY, 1);
288 if (error) {
289 show_error(error);
290 pwmd_close(pwm);
291 exit(EXIT_FAILURE);
294 if (set_pinentry_option(PWMD_OPTION_PINENTRY_PATH, pinentry_path))
295 exit(EXIT_FAILURE);
297 if (set_pinentry_option(PWMD_OPTION_PINENTRY_TITLE,
298 N_("Password Manager Daemon")))
299 exit(EXIT_FAILURE);
301 snprintf(command, sizeof(command), N_("A password is required for the "
302 "file \"%s\". Please\nenter the password below."), filename);
304 if (set_pinentry_option(PWMD_OPTION_PINENTRY_DESC, command))
305 exit(EXIT_FAILURE);
307 if (display) {
308 if (set_pinentry_option(PWMD_OPTION_PINENTRY_DISPLAY, display))
309 exit(EXIT_FAILURE);
312 if (tty) {
313 if (set_pinentry_option(PWMD_OPTION_PINENTRY_TTY, tty))
314 exit(EXIT_FAILURE);
317 if (ttytype) {
318 if (set_pinentry_option(PWMD_OPTION_PINENTRY_TERM, ttytype))
319 exit(EXIT_FAILURE);
323 if (set_pinentry_option(PWMD_OPTION_INQUIRE_FUNC, do_inquire)) {
324 show_error(error);
325 pwmd_close(pwm);
326 exit(EXIT_FAILURE);
329 if (show_status) {
330 if (set_pinentry_option(PWMD_OPTION_STATUS_FUNC, status_msg_cb)) {
331 show_error(error);
332 pwmd_close(pwm);
333 exit(EXIT_FAILURE);
337 if (filename) {
338 if (use_pinentry && timeout != -1) {
339 tcgetattr(STDOUT_FILENO, &term);
340 signal(SIGALRM, catchsig);
341 alarm(1);
344 error = pwmd_open(pwm, filename);
346 if (error) {
347 if (error == GPG_ERR_TIMEOUT) {
348 tcsetattr(STDOUT_FILENO, 0, &term);
349 printf("\r\n");
352 show_error(error);
353 pwmd_close(pwm);
354 exit(EXIT_FAILURE);
358 signal(SIGALRM, SIG_IGN);
359 elapsed = 0;
361 p = fgets(command, sizeof(command), stdin);
363 if (!p)
364 goto done;
366 if (strncasecmp(p, "STORE ", 6) == 0) {
367 struct inquire_s *inq = malloc(sizeof(struct inquire_s));
369 inq->data = xstrdup(p+6);
370 inq->fp = inquirefp;
372 if (set_pinentry_option(PWMD_OPTION_INQUIRE_DATA, inq)) {
373 xfree(inq->data);
374 free(inq);
375 pwmd_close(pwm);
376 exit(EXIT_FAILURE);
379 error = pwmd_command(pwm, &result, "STORE");
380 free(inq);
382 if (error) {
383 show_error(error);
384 ret = EXIT_FAILURE;
387 memset(command, 0, sizeof(command));
388 goto done;
391 if (p[strlen(p) - 1] == '\n')
392 p[strlen(p) - 1] = 0;
394 if (strcasecmp(p, "BYE") == 0)
395 goto done;
397 error = pwmd_command(pwm, &result, command);
398 memset(command, 0, sizeof(command));
400 if (error) {
401 show_error(error);
402 ret = EXIT_FAILURE;
403 goto fail;
406 if (result) {
407 if (isatty(outfd) && result[strlen(result) - 1] == '\n')
408 result[strlen(result) - 1] = 0;
410 fwrite(result, 1, strlen(result), outfp);
411 pwmd_free_result(result);
413 if (isatty(outfd))
414 fputc('\n', outfp);
417 done:
418 memset(command, 0, sizeof(command));
420 if (save) {
421 save_again:
422 error = pwmd_save(pwm);
424 if (error) {
425 if (use_pinentry && (error == EPWMD_BADKEY || error == EPWMD_KEY))
426 goto save_again;
428 show_error(error);
429 ret = EXIT_FAILURE;
430 goto fail;
434 fail:
435 pwmd_close(pwm);
437 if (socketpath)
438 xfree(socketpath);
440 exit(ret);