Look for ~/.pwmd/pinentry.conf rather than ~/.pwmd/env. 'env' isn't
[libpwmd.git] / pwmc.c
blob09ac1a94141fe1b6516c9460696e48fde39f294c
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 <termios.h>
26 #include <libpwmd.h>
27 #include <assuan.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 static void usage(const char *pn)
60 fprintf(stderr, N_(
61 "Reads PWMD protocol commands from standard input.\n\n"
62 "Usage: pwmc [-hvX] [-s <socket>] [-P -T -N -D -t <seconds> |\n"
63 " -p <password>] [-S] [-d <fd>] [-I <fd>] [filename]\n"
64 " -X disable showing of status messages from the server\n"
65 " -s socket path (~/.pwmd/socket)\n"
66 " -p password\n"
67 " -P path to the pinentry binary (%s)\n"
68 " -T pinentry tty\n"
69 " -N pinentry terminal type\n"
70 " -D pinentry display\n"
71 " -t pinentry timeout\n"
72 " -d redirect command output to the specified file descriptor\n"
73 " -I read inquire data from the specified file descriptor\n"
74 " -S send the SAVE command before exiting\n"
75 " -v version\n"
76 " -h this help text\n"), PINENTRY_PATH);
77 exit(EXIT_FAILURE);
80 struct inquire_s {
81 FILE *fp;
82 char *data;
85 static gpg_error_t do_inquire(void *data, const char *keyword, gpg_error_t rc,
86 char **result, size_t *result_len)
88 int c;
89 static char buf[ASSUAN_LINELENGTH];
90 char *p;
91 size_t len = 0;
92 struct inquire_s *inq = (struct inquire_s *)data;
94 if (rc) {
95 memset(buf, 0, sizeof(buf));
96 return rc;
99 buf[0] = 0;
100 p = buf;
102 if (inq->data) {
103 snprintf(buf, sizeof(buf), "%s", inq->data);
104 xfree(inq->data);
105 inq->data = NULL;
106 len = strlen(buf);
107 p = buf + len;
110 while ((c = fgetc(inq->fp)) != EOF) {
111 if (len == sizeof(buf)) {
112 ungetc(c, inq->fp);
113 break;
116 *p++ = c;
117 len++;
120 if (!buf[0]) {
121 memset(buf, 0, sizeof(buf));
122 return GPG_ERR_EOF;
125 *result = buf;
126 *result_len = len;
127 return 0;
130 static int status_msg_cb(void *data, const char *line)
132 fprintf(stderr, "%s\n", line);
133 return 0;
136 int main(int argc, char *argv[])
138 int opt;
139 char *password = NULL;
140 char *filename = NULL;
141 char *socketpath = NULL;
142 char command[ASSUAN_LINELENGTH], *p;
143 int ret = EXIT_SUCCESS;
144 gpg_error_t error;
145 char *result = NULL;
146 int save = 0;
147 char *pinentry_path = NULL;
148 char *display = NULL, *tty = NULL, *ttytype = NULL;
149 struct termios term;
150 int outfd = STDOUT_FILENO;
151 FILE *outfp = stdout;
152 int inquirefd = STDIN_FILENO;
153 FILE *inquirefp = stdin;
154 int show_status = 1;
156 setlocale(LC_ALL, "");
157 bindtextdomain("libpwmd", LOCALEDIR);
158 timeout = -1;
160 while ((opt = getopt(argc, argv, "I:XT:N:D:hvP:t:p:s:Sd:")) != EOF) {
161 switch (opt) {
162 case 'X':
163 show_status = 0;
164 break;
165 case 'T':
166 tty = optarg;
167 break;
168 case 'N':
169 ttytype = optarg;
170 break;
171 case 'D':
172 display = optarg;
173 break;
174 case 'I':
175 inquirefd = atoi(optarg);
176 inquirefp = fdopen(inquirefd, "r");
178 if (!inquirefp) {
179 xfree(password);
180 err(EXIT_FAILURE, "%i", inquirefd);
182 break;
183 case 'd':
184 outfd = atoi(optarg);
185 outfp = fdopen(outfd, "w");
187 if (!outfp) {
188 xfree(password);
189 err(EXIT_FAILURE, "%i", outfd);
191 break;
192 case 'S':
193 save = 1;
194 break;
195 case 's':
196 socketpath = xstrdup(optarg);
197 break;
198 case 'p':
199 password = xstrdup(optarg);
200 memset(optarg, 0, strlen(optarg));
201 break;
202 case 'P':
203 pinentry_path = xstrdup(optarg);
204 break;
205 case 't':
206 timeout = atoi(optarg);
207 break;
208 case 'v':
209 xfree(password);
210 printf("%s (pwmc)\n%s\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
211 exit(EXIT_SUCCESS);
212 case 'h':
213 default:
214 xfree(password);
215 usage(argv[0]);
219 filename = argv[optind];
220 pwmd_init();
222 if ((pwm = pwmd_connect(socketpath, &error)) == NULL) {
223 xfree(password);
224 errx(EXIT_FAILURE, "pwmd_connect(): %s", pwmd_strerror(error));
227 error = pwmd_command(pwm, &result, "OPTION CLIENT NAME=pwmc");
229 if (error) {
230 xfree(password);
231 errx(EXIT_FAILURE, "pwmd_connect(): %s", pwmd_strerror(error));
234 if (password) {
235 error = pwmd_setopt(pwm, PWMD_OPTION_PASSWORD, password);
237 if (error) {
238 xfree(password);
239 goto done;
242 xfree(password);
244 else {
245 tcgetattr(STDOUT_FILENO, &term);
247 if (pinentry_path) {
248 error = pwmd_command(pwm, &result, "OPTION PATH=%s", pinentry_path);
250 if (error)
251 goto done;
254 snprintf(command, sizeof(command), N_("A password is required for the "
255 "file \"%s\". Please\nenter the password below."), filename);
257 error = pwmd_command(pwm, &result, "OPTION DESC=%s", command);
259 if (error)
260 goto done;
262 if (display) {
263 error = pwmd_command(pwm, &result, "OPTION DISPLAY=%s", display);
265 if (error)
266 goto done;
269 if (tty) {
270 error = pwmd_command(pwm, &result, "OPTION TTYNAME=%s", tty);
272 if (error)
273 goto done;
276 if (ttytype) {
277 error = pwmd_command(pwm, &result, "OPTION TTYTYPE=%s", ttytype);
279 if (error)
280 goto done;
284 if (show_status) {
285 error = pwmd_setopt(pwm, PWMD_OPTION_STATUS_FUNC, status_msg_cb);
287 if (error)
288 goto done;
291 if (filename) {
292 if (timeout != -1) {
293 error = pwmd_command(pwm, &result, "OPTION TIMEOUT=%i", timeout);
295 if (error)
296 goto done;
299 error = pwmd_open(pwm, filename);
301 if (error) {
302 if (!password && error == GPG_ERR_TIMEOUT)
303 tcsetattr(STDOUT_FILENO, TCSANOW, &term);
305 goto done;
309 elapsed = 0;
310 p = fgets(command, sizeof(command), stdin);
312 if (!p)
313 goto done;
316 * This is a known INQUIRE command. We use pwmd_inquire() to send the
317 * data from the do_inquire() callback function.
319 if (strncasecmp(p, "STORE ", 6) == 0) {
320 struct inquire_s *inq = (struct inquire_s *)malloc(sizeof(struct inquire_s));
322 if (!inq) {
323 error = gpg_error_from_errno(ENOMEM);
324 goto done;
327 inq->data = xstrdup(p+6);
328 inq->fp = inquirefp;
329 error = pwmd_inquire(pwm, "STORE", do_inquire, inq);
330 free(inq);
331 goto done;
334 if (strcasecmp(p, "BYE") == 0)
335 goto done;
337 error = pwmd_command(pwm, &result, command);
338 memset(command, 0, sizeof(command));
340 if (error)
341 goto done;
343 if (result) {
344 fwrite(result, 1, strlen(result), outfp);
345 pwmd_free_result(result);
348 done:
349 memset(command, 0, sizeof(command));
351 if (!error && save) {
352 save_again:
353 error = pwmd_save(pwm);
355 if (error) {
356 if (error == EPWMD_BADKEY || error == EPWMD_KEY)
357 goto save_again;
359 show_error(error);
360 ret = EXIT_FAILURE;
363 else if (error) {
364 show_error(error);
365 ret = EXIT_FAILURE;
368 pwmd_close(pwm);
370 if (socketpath)
371 xfree(socketpath);
373 exit(ret);