The default pinentry path can be specified by passing
[libpwmd.git] / pwmc.c
blob6c5e7f487d44c4a4ad5b3eaa59d857c9781e9da5
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, "%s", N_(
79 "Reads PWMD protocol commands from standard input.\n\n"
80 "Usage: pwmc [-hv] [-E] [-s <socket>] [[-a [-P pinentry] [-t <seconds>]] |\n"
81 " [-p <password>]] [-S] [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 (/usr/bin/pinentry)\n"
87 " -t pinentry timeout\n"
88 " -S send the SAVE command after all others\n"
89 " -v version\n"
90 " -h this help text\n"));
91 exit(EXIT_FAILURE);
94 int main(int argc, char *argv[])
96 int opt;
97 int use_pinentry = 0;
98 char *password = NULL;
99 char *filename = NULL;
100 char *socketpath = NULL;
101 char command[8196], *p;
102 int ret = EXIT_SUCCESS;
103 gpg_error_t error;
104 char *result = NULL;
105 int save = 0;
106 char *buf = NULL;
107 int total = 0;
108 int do_exit = 0;
109 char *pinentry_path = NULL;
110 struct termios term;
112 setlocale(LC_ALL, "");
113 bindtextdomain("libpwmd", LOCALEDIR);
114 timeout = -1;
116 while ((opt = getopt(argc, argv, "EhvaP:t:p:s:S")) != EOF) {
117 switch (opt) {
118 case 'E':
119 do_exit = 1;
120 break;
121 case 'S':
122 save = 1;
123 break;
124 case 's':
125 socketpath = xstrdup(optarg);
126 break;
127 case 'p':
128 password = xstrdup(optarg);
129 break;
130 case 'a':
131 use_pinentry = 1;
132 break;
133 case 'P':
134 pinentry_path = xstrdup(optarg);
135 break;
136 case 't':
137 timeout = atoi(optarg);
138 break;
139 case 'v':
140 printf("%s (pwmc)\n%s\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
141 exit(EXIT_SUCCESS);
142 case 'h':
143 default:
144 usage(argv[0]);
148 if (use_pinentry && password) {
149 xfree(password);
150 usage(argv[0]);
153 filename = argv[optind];
154 pwmd_init();
156 if ((pwm = pwmd_connect(socketpath, &error)) == NULL) {
157 xfree(password);
158 errx(EXIT_FAILURE, "pwmd_connect(): %s", pwmd_strerror(error));
161 if (use_pinentry) {
162 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY, 1);
164 if (error) {
165 xfree(password);
166 show_error(error);
167 pwmd_close(pwm);
168 exit(EXIT_FAILURE);
171 if (pinentry_path) {
172 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_PATH, pinentry_path);
174 if (error) {
175 xfree(password);
176 show_error(error);
177 pwmd_close(pwm);
178 exit(EXIT_FAILURE);
182 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TITLE, N_("Password Manager Daemon"));
184 if (error) {
185 xfree(password);
186 show_error(error);
187 pwmd_close(pwm);
188 exit(EXIT_FAILURE);
191 snprintf(command, sizeof(command), N_("A password is required for the "
192 "file \"%s\". Please\nenter the password below."), filename);
194 error = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_DESC, command);
196 if (error) {
197 xfree(password);
198 show_error(error);
199 pwmd_close(pwm);
200 exit(EXIT_FAILURE);
203 else if (password) {
204 error = pwmd_setopt(pwm, PWMD_OPTION_PASSWORD, password);
206 if (error) {
207 xfree(password);
208 show_error(error);
209 pwmd_close(pwm);
210 exit(EXIT_FAILURE);
213 xfree(password);
216 if (filename) {
217 if (use_pinentry && timeout != -1) {
218 tcgetattr(STDOUT_FILENO, &term);
219 signal(SIGALRM, catchsig);
220 alarm(1);
223 error = pwmd_open(pwm, filename);
225 if (error) {
226 if (error == GPG_ERR_TIMEOUT) {
227 tcsetattr(STDOUT_FILENO, 0, &term);
228 printf("\r\n");
231 show_error(error);
232 pwmd_close(pwm);
233 exit(EXIT_FAILURE);
237 signal(SIGALRM, SIG_IGN);
238 elapsed = 0;
240 while ((p = fgets(command, sizeof(command), stdin)) != NULL) {
241 int len = strlen(p);
242 char *t;
244 if (p[len - 1] != '\n' && feof(stdin) != 1) {
245 if ((t = (char *)xrealloc(buf, (total + len + 1) * sizeof(char))) == NULL) {
246 if (buf)
247 xfree(buf);
249 memset(&command, 0, sizeof(command));
250 err(EXIT_FAILURE, "xrealloc()");
253 buf = t;
254 memcpy(&buf[total], p, len);
255 total += len;
256 buf[total] = 0;
257 continue;
259 else {
260 if (buf) {
261 if ((t = (char *)xrealloc(buf, (total + len + 1) * sizeof(char))) == NULL) {
262 if (buf)
263 xfree(buf);
265 memset(&command, 0, sizeof(command));
266 err(EXIT_FAILURE, "xrealloc()");
269 buf = t;
270 memcpy(&buf[total], p, len);
271 total += len;
272 buf[total] = 0;
276 p = buf ? buf : command;
278 if (p[strlen(p) - 1] == '\n')
279 p[strlen(p) - 1] = 0;
281 if (strcasecmp(p, "BYE") == 0)
282 break;
284 error = pwmd_command(pwm, &result, p);
286 if (error) {
287 if (buf) {
288 xfree(buf);
289 buf = NULL;
290 total = 0;
293 memset(&command, 0, sizeof(command));
294 show_error(error);
296 if (do_exit) {
297 pwmd_close(pwm);
298 exit(EXIT_FAILURE);
301 ret = EXIT_FAILURE;
303 else {
304 if (buf) {
305 xfree(buf);
306 buf = NULL;
307 total = 0;
311 memset(&command, 0, sizeof(command));
313 if (result) {
314 if (result[strlen(result) - 1] == '\n')
315 result[strlen(result) - 1] = 0;
317 fwrite(result, 1, strlen(result), stdout);
318 pwmd_free_result(result);
319 fputc('\n', stdout);
323 if (buf)
324 xfree(buf);
326 memset(&command, 0, sizeof(command));
328 if (save) {
329 save_again:
330 error = pwmd_save(pwm);
332 if (error) {
333 if (use_pinentry && (error == EPWMD_BADKEY || error == EPWMD_KEY))
334 goto save_again;
336 show_error(error);
337 pwmd_close(pwm);
338 exit(EXIT_FAILURE);
342 pwmd_close(pwm);
344 if (socketpath)
345 xfree(socketpath);
347 exit(ret);