Make sure the file specified file descriptor to pwmc doesn't fail when
[libpwmd.git] / pwmc.c
blob6c3b18c281a067fa2f0fbd23d3e96b0de46339fd
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 [-hv] [-E] [-s <socket>] [[-a [-P -T -N -D] [-t <seconds>]] |\n"
85 " [-p <password>]] [-S] [-d <descriptor>] [filename]\n"
86 " -E exit after a command failure\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 " -S send the SAVE command after all others\n"
97 " -v version\n"
98 " -h this help text\n"), PINENTRY_PATH);
99 exit(EXIT_FAILURE);
102 int set_pinentry_option(pwmd_option_t option, char *value)
104 gpg_error_t error;
106 error = pwmd_setopt(pwm, option, value);
108 if (error) {
109 show_error(error);
110 pwmd_close(pwm);
111 return 1;
114 return 0;
117 int main(int argc, char *argv[])
119 int opt;
120 int use_pinentry = 0;
121 char *password = NULL;
122 char *filename = NULL;
123 char *socketpath = NULL;
124 char command[8196], *p;
125 int ret = EXIT_SUCCESS;
126 gpg_error_t error;
127 char *result = NULL;
128 int save = 0;
129 char *buf = NULL;
130 int total = 0;
131 int do_exit = 0;
132 char *pinentry_path = NULL;
133 char *display = NULL, *tty = NULL, *ttytype = NULL;
134 struct termios term;
135 int outfd = STDOUT_FILENO;
136 FILE *outfp = stdout;
138 setlocale(LC_ALL, "");
139 bindtextdomain("libpwmd", LOCALEDIR);
140 timeout = -1;
142 while ((opt = getopt(argc, argv, "T:N:D:EhvaP:t:p:s:Sd:")) != EOF) {
143 switch (opt) {
144 case 'T':
145 tty = optarg;
146 break;
147 case 'N':
148 ttytype = optarg;
149 break;
150 case 'D':
151 display = optarg;
152 break;
153 case 'd':
154 outfd = atoi(optarg);
155 outfp = fdopen(outfd, "w");
157 if (!outfp)
158 err(EXIT_FAILURE, "%i", outfd);
159 break;
160 case 'E':
161 do_exit = 1;
162 break;
163 case 'S':
164 save = 1;
165 break;
166 case 's':
167 socketpath = xstrdup(optarg);
168 break;
169 case 'p':
170 password = xstrdup(optarg);
171 break;
172 case 'a':
173 use_pinentry = 1;
174 break;
175 case 'P':
176 pinentry_path = xstrdup(optarg);
177 break;
178 case 't':
179 timeout = atoi(optarg);
180 break;
181 case 'v':
182 printf("%s (pwmc)\n%s\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
183 exit(EXIT_SUCCESS);
184 case 'h':
185 default:
186 usage(argv[0]);
190 if (use_pinentry && password) {
191 xfree(password);
192 usage(argv[0]);
195 filename = argv[optind];
196 pwmd_init();
198 if ((pwm = pwmd_connect(socketpath, &error)) == NULL) {
199 xfree(password);
200 errx(EXIT_FAILURE, "pwmd_connect(): %s", pwmd_strerror(error));
203 if (password) {
204 if (set_pinentry_option(PWMD_OPTION_PASSWORD, password)) {
205 xfree(password);
206 exit(EXIT_FAILURE);
209 xfree(password);
211 else if (use_pinentry) {
212 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY, 1);
214 if (error) {
215 show_error(error);
216 pwmd_close(pwm);
217 exit(EXIT_FAILURE);
220 if (set_pinentry_option(PWMD_OPTION_PINENTRY_PATH, pinentry_path))
221 exit(EXIT_FAILURE);
223 if (set_pinentry_option(PWMD_OPTION_PINENTRY_TITLE,
224 N_("Password Manager Daemon")))
225 exit(EXIT_FAILURE);
227 snprintf(command, sizeof(command), N_("A password is required for the "
228 "file \"%s\". Please\nenter the password below."), filename);
230 if (set_pinentry_option(PWMD_OPTION_PINENTRY_DESC, command))
231 exit(EXIT_FAILURE);
233 if (display) {
234 if (set_pinentry_option(PWMD_OPTION_PINENTRY_DISPLAY, display))
235 exit(EXIT_FAILURE);
238 if (tty) {
239 if (set_pinentry_option(PWMD_OPTION_PINENTRY_TTY, tty))
240 exit(EXIT_FAILURE);
243 if (ttytype) {
244 if (set_pinentry_option(PWMD_OPTION_PINENTRY_TERM, ttytype))
245 exit(EXIT_FAILURE);
249 if (filename) {
250 if (use_pinentry && timeout != -1) {
251 tcgetattr(STDOUT_FILENO, &term);
252 signal(SIGALRM, catchsig);
253 alarm(1);
256 error = pwmd_open(pwm, filename);
258 if (error) {
259 if (error == GPG_ERR_TIMEOUT) {
260 tcsetattr(STDOUT_FILENO, 0, &term);
261 printf("\r\n");
264 show_error(error);
265 pwmd_close(pwm);
266 exit(EXIT_FAILURE);
270 signal(SIGALRM, SIG_IGN);
271 elapsed = 0;
273 while ((p = fgets(command, sizeof(command), stdin)) != NULL) {
274 int len = strlen(p);
275 char *t;
277 if (p[len - 1] != '\n' && feof(stdin) != 1) {
278 if ((t = (char *)xrealloc(buf, (total + len + 1) * sizeof(char))) == NULL) {
279 if (buf)
280 xfree(buf);
282 memset(&command, 0, sizeof(command));
283 err(EXIT_FAILURE, "xrealloc()");
286 buf = t;
287 memcpy(&buf[total], p, len);
288 total += len;
289 buf[total] = 0;
290 continue;
292 else {
293 if (buf) {
294 if ((t = (char *)xrealloc(buf, (total + len + 1) * sizeof(char))) == NULL) {
295 if (buf)
296 xfree(buf);
298 memset(&command, 0, sizeof(command));
299 err(EXIT_FAILURE, "xrealloc()");
302 buf = t;
303 memcpy(&buf[total], p, len);
304 total += len;
305 buf[total] = 0;
309 p = buf ? buf : command;
311 if (p[strlen(p) - 1] == '\n')
312 p[strlen(p) - 1] = 0;
314 if (strcasecmp(p, "BYE") == 0)
315 break;
317 error = pwmd_command(pwm, &result, p);
319 if (error) {
320 if (buf) {
321 xfree(buf);
322 buf = NULL;
323 total = 0;
326 memset(&command, 0, sizeof(command));
327 show_error(error);
329 if (do_exit) {
330 pwmd_close(pwm);
331 exit(EXIT_FAILURE);
334 ret = EXIT_FAILURE;
336 else {
337 if (buf) {
338 xfree(buf);
339 buf = NULL;
340 total = 0;
344 memset(&command, 0, sizeof(command));
346 if (result) {
347 if (result[strlen(result) - 1] == '\n')
348 result[strlen(result) - 1] = 0;
350 fwrite(result, 1, strlen(result), outfp);
351 pwmd_free_result(result);
352 fputc('\n', outfp);
356 if (buf)
357 xfree(buf);
359 memset(&command, 0, sizeof(command));
361 if (save) {
362 save_again:
363 error = pwmd_save(pwm);
365 if (error) {
366 if (use_pinentry && (error == EPWMD_BADKEY || error == EPWMD_KEY))
367 goto save_again;
369 show_error(error);
370 pwmd_close(pwm);
371 exit(EXIT_FAILURE);
375 pwmd_close(pwm);
377 if (socketpath)
378 xfree(socketpath);
380 exit(ret);