Changed the Debian package dependency to require pwmd 1.4 or later.
[libpwmd.git] / pwmc.c
blobce93496296b212f01b442a5fba9bf531ddb331da
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 #include "gettext.h"
34 #define N_(msgid) gettext(msgid)
36 #ifndef MEM_DEBUG
37 #include "mem.h"
38 #else
39 #define xfree free
40 #define xrealloc realloc
41 #define xmalloc malloc
42 #define xstrdup strdup
43 #define xcalloc calloc
44 #endif
46 int timeout, elapsed;
47 pwm_t *pwm;
49 static void show_error(gpg_error_t error)
51 fprintf(stderr, "ERR %i %s\n", gpg_err_code(error), pwmd_strerror(error));
54 void catchsig(int sig)
56 gpg_error_t error;
58 switch (sig) {
59 case SIGALRM:
60 if (pwm && timeout > 0 && elapsed++ >= timeout) {
61 error = pwmd_terminate_pinentry(pwm);
63 if (error)
64 show_error(error);
66 break;
69 alarm(1);
70 break;
71 default:
72 break;
76 static void usage(const char *pn)
78 fprintf(stderr, N_(
79 "Reads PWMD protocol commands from standard input.\n\n"
80 "Usage: pwmc [-hv] [-E] [-s <socket>] [[-a [-P -T -N -D] [-t <seconds>]] |\n"
81 " [-p <password>]] [-S] [-d <descriptor>] [filename]\n"
82 " -E exit after a command failure\n"
83 " -s socket path\n"
84 " -p password\n"
85 " -a use pinentry(1) for password retrieval\n"
86 " -P path to the pinentry binary (%s)\n"
87 " -T pinentry tty\n"
88 " -N pinentry terminal type\n"
89 " -D pinentry display\n"
90 " -t pinentry timeout\n"
91 " -d redirect command output to the specified file descriptor\n"
92 " -S send the SAVE command after all others\n"
93 " -v version\n"
94 " -h this help text\n"), PINENTRY_PATH);
95 exit(EXIT_FAILURE);
98 int set_pinentry_option(int option, char *value)
100 gpg_error_t error;
102 error = pwmd_setopt(pwm, option, value);
104 if (error) {
105 show_error(error);
106 pwmd_close(pwm);
107 return 1;
110 return 0;
113 int main(int argc, char *argv[])
115 int opt;
116 int use_pinentry = 0;
117 char *password = NULL;
118 char *filename = NULL;
119 char *socketpath = NULL;
120 char command[8196], *p;
121 int ret = EXIT_SUCCESS;
122 gpg_error_t error;
123 char *result = NULL;
124 int save = 0;
125 char *buf = NULL;
126 int total = 0;
127 int do_exit = 0;
128 char *pinentry_path = NULL;
129 char *display = NULL, *tty = NULL, *ttytype = NULL;
130 struct termios term;
131 int outfd = -1;
132 FILE *outfp = stdout;
134 setlocale(LC_ALL, "");
135 bindtextdomain("libpwmd", LOCALEDIR);
136 timeout = -1;
138 while ((opt = getopt(argc, argv, "T:N:D:EhvaP:t:p:s:Sd:")) != EOF) {
139 switch (opt) {
140 case 'T':
141 tty = optarg;
142 break;
143 case 'N':
144 ttytype = optarg;
145 break;
146 case 'D':
147 display = optarg;
148 break;
149 case 'd':
150 outfd = atoi(optarg);
151 break;
152 case 'E':
153 do_exit = 1;
154 break;
155 case 'S':
156 save = 1;
157 break;
158 case 's':
159 socketpath = xstrdup(optarg);
160 break;
161 case 'p':
162 password = xstrdup(optarg);
163 break;
164 case 'a':
165 use_pinentry = 1;
166 break;
167 case 'P':
168 pinentry_path = xstrdup(optarg);
169 break;
170 case 't':
171 timeout = atoi(optarg);
172 break;
173 case 'v':
174 printf("%s (pwmc)\n%s\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
175 exit(EXIT_SUCCESS);
176 case 'h':
177 default:
178 usage(argv[0]);
182 if (use_pinentry && password) {
183 xfree(password);
184 usage(argv[0]);
187 filename = argv[optind];
188 pwmd_init();
190 if ((pwm = pwmd_connect(socketpath, &error)) == NULL) {
191 xfree(password);
192 errx(EXIT_FAILURE, "pwmd_connect(): %s", pwmd_strerror(error));
195 if (password) {
196 if (set_pinentry_option(PWMD_OPTION_PASSWORD, password)) {
197 xfree(password);
198 exit(EXIT_FAILURE);
201 xfree(password);
203 else if (use_pinentry) {
204 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY, 1);
206 if (error) {
207 show_error(error);
208 pwmd_close(pwm);
209 exit(EXIT_FAILURE);
212 if (set_pinentry_option(PWMD_OPTION_PINENTRY_PATH, pinentry_path))
213 exit(EXIT_FAILURE);
215 if (set_pinentry_option(PWMD_OPTION_PINENTRY_TITLE,
216 N_("Password Manager Daemon")))
217 exit(EXIT_FAILURE);
219 snprintf(command, sizeof(command), N_("A password is required for the "
220 "file \"%s\". Please\nenter the password below."), filename);
222 if (set_pinentry_option(PWMD_OPTION_PINENTRY_DESC, command))
223 exit(EXIT_FAILURE);
225 if (display) {
226 if (set_pinentry_option(PWMD_OPTION_PINENTRY_DISPLAY, display))
227 exit(EXIT_FAILURE);
230 if (tty) {
231 if (set_pinentry_option(PWMD_OPTION_PINENTRY_TTY, tty))
232 exit(EXIT_FAILURE);
235 if (ttytype) {
236 if (set_pinentry_option(PWMD_OPTION_PINENTRY_TERM, ttytype))
237 exit(EXIT_FAILURE);
241 if (filename) {
242 if (use_pinentry && timeout != -1) {
243 tcgetattr(STDOUT_FILENO, &term);
244 signal(SIGALRM, catchsig);
245 alarm(1);
248 error = pwmd_open(pwm, filename);
250 if (error) {
251 if (error == GPG_ERR_TIMEOUT) {
252 tcsetattr(STDOUT_FILENO, 0, &term);
253 printf("\r\n");
256 show_error(error);
257 pwmd_close(pwm);
258 exit(EXIT_FAILURE);
262 signal(SIGALRM, SIG_IGN);
263 elapsed = 0;
265 if (outfd != -1)
266 outfp = fdopen(outfd, "w");
268 while ((p = fgets(command, sizeof(command), stdin)) != NULL) {
269 int len = strlen(p);
270 char *t;
272 if (p[len - 1] != '\n' && feof(stdin) != 1) {
273 if ((t = (char *)xrealloc(buf, (total + len + 1) * sizeof(char))) == NULL) {
274 if (buf)
275 xfree(buf);
277 memset(&command, 0, sizeof(command));
278 err(EXIT_FAILURE, "xrealloc()");
281 buf = t;
282 memcpy(&buf[total], p, len);
283 total += len;
284 buf[total] = 0;
285 continue;
287 else {
288 if (buf) {
289 if ((t = (char *)xrealloc(buf, (total + len + 1) * sizeof(char))) == NULL) {
290 if (buf)
291 xfree(buf);
293 memset(&command, 0, sizeof(command));
294 err(EXIT_FAILURE, "xrealloc()");
297 buf = t;
298 memcpy(&buf[total], p, len);
299 total += len;
300 buf[total] = 0;
304 p = buf ? buf : command;
306 if (p[strlen(p) - 1] == '\n')
307 p[strlen(p) - 1] = 0;
309 if (strcasecmp(p, "BYE") == 0)
310 break;
312 error = pwmd_command(pwm, &result, p);
314 if (error) {
315 if (buf) {
316 xfree(buf);
317 buf = NULL;
318 total = 0;
321 memset(&command, 0, sizeof(command));
322 show_error(error);
324 if (do_exit) {
325 pwmd_close(pwm);
326 exit(EXIT_FAILURE);
329 ret = EXIT_FAILURE;
331 else {
332 if (buf) {
333 xfree(buf);
334 buf = NULL;
335 total = 0;
339 memset(&command, 0, sizeof(command));
341 if (result) {
342 if (result[strlen(result) - 1] == '\n')
343 result[strlen(result) - 1] = 0;
345 fwrite(result, 1, strlen(result), outfp);
346 pwmd_free_result(result);
347 fputc('\n', outfp);
351 if (buf)
352 xfree(buf);
354 memset(&command, 0, sizeof(command));
356 if (save) {
357 save_again:
358 error = pwmd_save(pwm);
360 if (error) {
361 if (use_pinentry && (error == EPWMD_BADKEY || error == EPWMD_KEY))
362 goto save_again;
364 show_error(error);
365 pwmd_close(pwm);
366 exit(EXIT_FAILURE);
370 pwmd_close(pwm);
372 if (socketpath)
373 xfree(socketpath);
375 exit(ret);