pwmc and g++ compilation fix.
[libpwmd.git] / pwmc.c
blob29b929a7012f0dbdb1d6f46f23d4787262990833
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>
28 #include <assuan.h>
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
34 #ifdef HAVE_LOCALE_H
35 #include <locale.h>
36 #endif
38 #include "gettext.h"
39 #define N_(msgid) gettext(msgid)
41 #ifndef MEM_DEBUG
42 #include "mem.h"
43 #else
44 #define xfree free
45 #define xrealloc realloc
46 #define xmalloc malloc
47 #define xstrdup strdup
48 #define xcalloc calloc
49 #endif
51 int timeout, elapsed;
52 pwm_t *pwm;
54 static void show_error(gpg_error_t error)
56 fprintf(stderr, "ERR %i %s\n", gpg_err_code(error), pwmd_strerror(error));
59 void catchsig(int sig)
61 gpg_error_t error;
63 switch (sig) {
64 case SIGALRM:
65 if (pwm && timeout > 0 && elapsed++ >= timeout) {
66 error = pwmd_terminate_pinentry(pwm);
68 if (error)
69 show_error(error);
71 break;
74 alarm(1);
75 break;
76 default:
77 break;
81 static void usage(const char *pn)
83 fprintf(stderr, N_(
84 "Reads PWMD protocol commands from standard input.\n\n"
85 "Usage: pwmc [-hvX] [-s <socket>] [[-a [-P -T -N -D] [-t <seconds>]] |\n"
86 " [-p <password>]] [-S] [-d <fd>] [-I <fd>] [filename]\n"
87 " -X disable showing of status messages from the server\n"
88 " -s socket path (~/.pwmd/socket)\n"
89 " -p password\n"
90 " -a use pinentry(1) for password retrieval\n"
91 " -P path to the pinentry binary (%s)\n"
92 " -T pinentry tty\n"
93 " -N pinentry terminal type\n"
94 " -D pinentry display\n"
95 " -t pinentry timeout\n"
96 " -d redirect command output to the specified file descriptor\n"
97 " -I read inquire data from the specified file descriptor\n"
98 " -S send the SAVE command before exiting\n"
99 " -v version\n"
100 " -h this help text\n"), PINENTRY_PATH);
101 exit(EXIT_FAILURE);
104 struct inquire_s {
105 FILE *fp;
106 char *data;
109 static gpg_error_t do_inquire(void *data, const char *keyword, gpg_error_t rc,
110 char **result, size_t *result_len)
112 int c;
113 static char buf[ASSUAN_LINELENGTH];
114 char *p;
115 size_t len = 0;
116 struct inquire_s *inq = (struct inquire_s *)data;
118 if (rc) {
119 memset(buf, 0, sizeof(buf));
120 return rc;
123 buf[0] = 0;
124 p = buf;
126 if (inq->data) {
127 snprintf(buf, sizeof(buf), "%s", inq->data);
128 xfree(inq->data);
129 inq->data = NULL;
130 len = strlen(buf);
131 p = buf + len;
134 while ((c = fgetc(inq->fp)) != EOF) {
135 if (len == sizeof(buf)) {
136 ungetc(c, inq->fp);
137 break;
140 *p++ = c;
141 len++;
144 if (!buf[0]) {
145 memset(buf, 0, sizeof(buf));
146 return GPG_ERR_EOF;
149 *result = buf;
150 *result_len = len;
151 return 0;
154 static int status_msg_cb(void *data, const char *line)
156 fprintf(stderr, "%s\n", line);
157 return 0;
160 int main(int argc, char *argv[])
162 int opt;
163 int use_pinentry = 0;
164 char *password = NULL;
165 char *filename = NULL;
166 char *socketpath = NULL;
167 char command[ASSUAN_LINELENGTH], *p;
168 int ret = EXIT_SUCCESS;
169 gpg_error_t error;
170 char *result = NULL;
171 int save = 0;
172 char *pinentry_path = NULL;
173 char *display = NULL, *tty = NULL, *ttytype = NULL;
174 struct termios term;
175 int outfd = STDOUT_FILENO;
176 FILE *outfp = stdout;
177 int inquirefd = STDIN_FILENO;
178 FILE *inquirefp = stdin;
179 int show_status = 1;
181 setlocale(LC_ALL, "");
182 bindtextdomain("libpwmd", LOCALEDIR);
183 timeout = -1;
185 while ((opt = getopt(argc, argv, "I:XT:N:D:hvaP:t:p:s:Sd:")) != EOF) {
186 switch (opt) {
187 case 'X':
188 show_status = 0;
189 break;
190 case 'T':
191 tty = optarg;
192 break;
193 case 'N':
194 ttytype = optarg;
195 break;
196 case 'D':
197 display = optarg;
198 break;
199 case 'I':
200 inquirefd = atoi(optarg);
201 inquirefp = fdopen(inquirefd, "r");
203 if (!inquirefp) {
204 xfree(password);
205 err(EXIT_FAILURE, "%i", inquirefd);
207 break;
208 case 'd':
209 outfd = atoi(optarg);
210 outfp = fdopen(outfd, "w");
212 if (!outfp) {
213 xfree(password);
214 err(EXIT_FAILURE, "%i", outfd);
216 break;
217 case 'S':
218 save = 1;
219 break;
220 case 's':
221 socketpath = xstrdup(optarg);
222 break;
223 case 'p':
224 password = xstrdup(optarg);
225 memset(optarg, 0, strlen(optarg));
226 break;
227 case 'a':
228 use_pinentry = 1;
229 break;
230 case 'P':
231 pinentry_path = xstrdup(optarg);
232 break;
233 case 't':
234 timeout = atoi(optarg);
235 break;
236 case 'v':
237 xfree(password);
238 printf("%s (pwmc)\n%s\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
239 exit(EXIT_SUCCESS);
240 case 'h':
241 default:
242 xfree(password);
243 usage(argv[0]);
247 if (use_pinentry && password) {
248 xfree(password);
249 usage(argv[0]);
252 filename = argv[optind];
253 pwmd_init();
255 if ((pwm = pwmd_connect(socketpath, &error)) == NULL) {
256 xfree(password);
257 errx(EXIT_FAILURE, "pwmd_connect(): %s", pwmd_strerror(error));
260 if (password) {
261 error = pwmd_setopt(pwm, PWMD_OPTION_PASSWORD, password);
263 if (error) {
264 xfree(password);
265 goto done;
268 xfree(password);
270 else if (use_pinentry) {
271 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY, 1);
273 if (error)
274 goto done;
276 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
278 if (error)
279 goto done;
281 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TITLE,
282 N_("Password Manager Daemon"));
284 if (error)
285 goto done;
287 snprintf(command, sizeof(command), N_("A password is required for the "
288 "file \"%s\". Please\nenter the password below."), filename);
290 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_DESC, command);
292 if (error)
293 goto done;
295 if (display) {
296 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_DISPLAY, display);
298 if (error)
299 goto done;
302 if (tty) {
303 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TTY, tty);
305 if (error)
306 goto done;
309 if (ttytype) {
310 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TERM, ttytype);
312 if (error)
313 goto done;
317 if (show_status) {
318 error = pwmd_setopt(pwm, PWMD_OPTION_STATUS_FUNC, status_msg_cb);
320 if (error)
321 goto done;
324 if (filename) {
325 if (use_pinentry && timeout != -1) {
326 tcgetattr(STDOUT_FILENO, &term);
327 signal(SIGALRM, catchsig);
328 alarm(1);
331 error = pwmd_open(pwm, filename);
333 if (error) {
334 if (error == GPG_ERR_TIMEOUT) {
335 tcsetattr(STDOUT_FILENO, 0, &term);
336 printf("\r\n");
339 goto done;
343 signal(SIGALRM, SIG_IGN);
344 elapsed = 0;
345 p = fgets(command, sizeof(command), stdin);
347 if (!p)
348 goto done;
351 * This is a known INQUIRE command. We use pwmd_inquire() to send the
352 * data from the do_inquire() callback function.
354 if (strncasecmp(p, "STORE ", 6) == 0) {
355 struct inquire_s *inq = (struct inquire_s *)malloc(sizeof(struct inquire_s));
357 if (!inq) {
358 error = gpg_error_from_errno(ENOMEM);
359 goto done;
362 inq->data = xstrdup(p+6);
363 inq->fp = inquirefp;
364 error = pwmd_inquire(pwm, "STORE", do_inquire, inq);
365 free(inq);
366 goto done;
369 if (strcasecmp(p, "BYE") == 0)
370 goto done;
372 error = pwmd_command(pwm, &result, command);
373 memset(command, 0, sizeof(command));
375 if (error)
376 goto done;
378 if (result) {
379 fwrite(result, 1, strlen(result), outfp);
380 pwmd_free_result(result);
383 done:
384 memset(command, 0, sizeof(command));
386 if (!error && save) {
387 save_again:
388 error = pwmd_save(pwm);
390 if (error) {
391 if (use_pinentry && (error == EPWMD_BADKEY || error == EPWMD_KEY))
392 goto save_again;
394 show_error(error);
395 ret = EXIT_FAILURE;
398 else if (error) {
399 show_error(error);
400 ret = EXIT_FAILURE;
403 pwmd_close(pwm);
405 if (socketpath)
406 xfree(socketpath);
408 exit(ret);