Update the log settings (path, enabled, etc) on each file reload.
[pwmd.git] / src / pinentry.c
blob29b2d91eb6c5fa8827ebe1877d0788e8da8f1b55
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2007-2008 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 <stdlib.h>
20 #include <gcrypt.h>
21 #include <glib.h>
22 #include <errno.h>
23 #include <pth.h>
24 #include <pwd.h>
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
30 #include "mem.h"
31 #include "common.h"
32 #include "pinentry.h"
33 #include "pwmd_error.h"
35 typedef struct {
36 size_t len;
37 void *buf;
38 } membuf_t;
40 void free_client_list();
41 static gpg_error_t set_pinentry_strings(struct pinentry_s *pin, int which);
43 static int mem_realloc_cb(void *data, const void *buffer, size_t len)
45 membuf_t *mem = (membuf_t *)data;
46 void *p;
48 if (!buffer)
49 return 0;
51 if ((p = xrealloc(mem->buf, mem->len + len)) == NULL)
52 return 1;
54 mem->buf = p;
55 memcpy((char *)mem->buf + mem->len, buffer, len);
56 mem->len += len;
57 return 0;
60 static gpg_error_t assuan_command(struct pinentry_s *pin, gchar **result,
61 const gchar *cmd)
63 membuf_t data;
64 gpg_error_t rc;
66 data.len = 0;
67 data.buf = NULL;
69 rc = assuan_transact(pin->ctx, cmd, mem_realloc_cb, &data, NULL, NULL,
70 NULL, NULL);
72 if (rc) {
73 if (data.buf) {
74 xfree(data.buf);
75 data.buf = NULL;
78 else {
79 if (data.buf) {
80 mem_realloc_cb(&data, "", 1);
81 *result = (gchar *)data.buf;
85 return rc;
88 static gpg_error_t set_pinentry_options(struct pinentry_s *pin)
90 gchar *display = getenv("DISPLAY");
91 gint have_display = 0;
92 gchar *tty = NULL, *ttytype = NULL;
93 gchar *opt, *val;
94 gpg_error_t rc;
95 gchar *result = NULL;
96 gchar cmd[ASSUAN_LINELENGTH];
98 if (pin->display || display)
99 have_display = 1;
100 else {
101 tty = pin->ttyname ? pin->ttyname : ttyname(STDOUT_FILENO);
103 if (!tty)
104 return GPG_ERR_CANCELED;
107 if (!have_display && !tty)
108 return GPG_ERR_CANCELED;
110 if (!have_display) {
111 gchar *p = getenv("TERM");
113 ttytype = pin->ttytype ? pin->ttytype : p;
115 if (!ttytype)
116 return GPG_ERR_CANCELED;
119 opt = have_display ? "DISPLAY" : "TTYNAME";
120 val = have_display ? pin->display ? pin->display : display : tty;
121 snprintf(cmd, sizeof(cmd), "OPTION %s=%s", g_ascii_strdown(opt, strlen(opt)), val);
122 rc = assuan_command(pin, &result, cmd);
124 if (rc)
125 return rc;
127 if (!have_display) {
128 snprintf(cmd, sizeof(cmd), "OPTION ttytype=%s", ttytype);
129 rc = assuan_command(pin, &result, cmd);
132 return rc;
135 static gpg_error_t launch_pinentry(struct pinentry_s *pin)
137 gpg_error_t rc;
138 assuan_context_t ctx;
139 gint child_list[] = {-1};
140 const gchar *argv[] = { "pinentry", NULL };
142 rc = assuan_pipe_connect(&ctx, pin->path ? pin->path : PINENTRY_PATH,
143 argv, child_list);
145 if (rc)
146 return rc;
148 pin->pid = assuan_get_pid(ctx);
149 pin->ctx = ctx;
150 rc = set_pinentry_options(pin);
151 return rc ? rc : set_pinentry_strings(pin, 0);
154 static gpg_error_t pinentry_command(struct pinentry_s *pin, gchar **result,
155 const gchar *cmd)
157 gpg_error_t error = 0;
159 if (!pin->ctx)
160 error = launch_pinentry(pin);
162 return error ? error : assuan_command(pin, result, cmd);
165 static gpg_error_t set_pinentry_strings(struct pinentry_s *pin, int which)
167 char *buf;
168 gpg_error_t error;
169 gchar *title = NULL;
171 if (which == 1)
172 title = g_strdup(N_("Password mismatch, please try again."));
173 else if (!pin->title)
174 title = pin->title = g_strdup(N_("Password Manager Daemon"));
175 else
176 title = pin->title;
178 if (!pin->prompt)
179 pin->prompt = g_strdup(N_("Password:"));
181 if (!pin->desc && !which)
182 pin->desc = g_strdup_printf(pin->which == PINENTRY_OPEN ?
183 N_("A password is required to open the file \"%s\". Please%%0Aenter the password below.") :
184 N_("A password is required to save to the file \"%s\". Please%%0Aenter the password below."),
185 pin->filename);
187 if (which == 2)
188 buf = g_strdup_printf("SETERROR %s", N_("Please type the password again for confirmation."));
189 else
190 buf = g_strdup_printf("SETERROR %s", pin->desc);
192 error = pinentry_command(pin, NULL, buf);
193 g_free(buf);
195 if (error)
196 goto done;
198 buf = g_strdup_printf("SETPROMPT %s", pin->prompt);
199 error = pinentry_command(pin, NULL, buf);
200 g_free(buf);
202 if (error)
203 goto done;
205 buf = g_strdup_printf("SETDESC %s", title);
206 error = pinentry_command(pin, NULL, buf);
207 g_free(buf);
209 done:
210 if (which == 1)
211 g_free(title);
213 return error;
216 static void pinentry_disconnect(struct pinentry_s *pin)
218 if (!pin)
219 return;
221 if (pin->ctx)
222 assuan_disconnect(pin->ctx);
224 pin->ctx = NULL;
225 pin->pid = 0;
228 static gpg_error_t do_getpin(struct pinentry_s *pin, char **result)
230 gpg_error_t error;
232 *result = NULL;
233 error = pinentry_command(pin, result, "GETPIN");
235 if (!*result)
236 *result = xstrdup("");
238 return error;
241 gpg_error_t pinentry_getpin(struct pinentry_s *pin, gchar **result)
243 gint which = 0;
244 gpg_error_t error = set_pinentry_strings(pin, which);
245 gchar *result1 = NULL;
247 if (error) {
248 pinentry_disconnect(pin);
249 return error;
252 again:
253 error = do_getpin(pin, result);
255 if (error)
256 goto done;
258 if (pin->which == PINENTRY_SAVE) {
259 if (!result1) {
260 error = set_pinentry_strings(pin, 2);
262 if (error)
263 goto done;
265 result1 = g_strdup(*result);
266 goto again;
269 if (strcmp(result1, *result)) {
270 g_free(result1);
271 xfree(*result);
272 result1 = *result = NULL;
273 error = set_pinentry_strings(pin, 1);
275 if (error)
276 goto done;
278 goto again;
282 done:
283 g_free(result1);
284 pinentry_disconnect(pin);
285 return error;
288 gpg_error_t pinentry_fork(assuan_context_t ctx)
290 struct client_s *client = assuan_get_pointer(ctx);
291 struct pinentry_s *pin = client->pinentry;
292 gpg_error_t error;
293 gint p[2];
294 pid_t pid;
295 pinentry_key_s pk;
296 gsize len;
297 gchar *result = NULL;
299 if (pipe(p) == -1)
300 return gpg_error_from_syserror();
302 pid = pth_fork();
304 switch (pid) {
305 case -1:
306 error = gpg_error_from_syserror();
307 close(p[0]);
308 close(p[1]);
309 return error;
310 case 0:
311 close(p[0]);
312 free_client_list();
313 pk.error = pinentry_getpin(pin, &result);
315 if (pk.error) {
316 xfree(result);
317 len = pth_write(p[1], &pk, sizeof(pk));
318 close(p[1]);
320 if (len != sizeof(pk))
321 log_write("%s(%i): write: len != sizeof(pk)", __FUNCTION__, __LINE__);
323 _exit(1);
326 pk.error = 0;
327 strncpy(pk.key, result, sizeof(pk.key));
328 xfree(result);
329 len = pth_write(p[1], &pk, sizeof(pk));
330 memset(&pk, 0, sizeof(pk));
331 close(p[1]);
333 if (len != sizeof(pk))
334 log_write("%s(%i): write: len != sizeof(pk)", __FUNCTION__, __LINE__);
336 _exit(0);
337 default:
338 close(p[1]);
339 client->pinentry->fd = p[0];
340 client->pinentry->pid = pid;
341 client->pinentry->status = PINENTRY_INIT;
342 break;
346 * Don't call assuan_process_done() here. That should be done in
347 * open_command_finalize() after the key has been read().
349 return 0;
352 void cleanup_pinentry(struct pinentry_s *pin)
354 if (!pin)
355 return;
357 if (pin->ctx && pin->pid)
358 pinentry_disconnect(pin);
360 g_free(pin->ttyname);
361 g_free(pin->ttytype);
362 g_free(pin->desc);
363 g_free(pin->title);
364 g_free(pin->prompt);
365 g_free(pin->path);
366 g_free(pin->display);
367 g_free(pin->filename);
368 g_free(pin);
371 void set_pinentry_defaults(struct pinentry_s *pin)
373 FILE *fp;
374 gchar buf[PATH_MAX];
375 struct passwd *pw = getpwuid(getuid());
376 gchar *p;
378 g_snprintf(buf, sizeof(buf), "%s/.pwmd/pinentry.conf", pw->pw_dir);
379 fp = fopen(buf, "r");
381 if (fp) {
382 while ((p = fgets(buf, sizeof(buf), fp)) != NULL) {
383 gchar name[32] = {0}, value[256] = {0};
385 if (*p == '#')
386 continue;
388 if (p[strlen(p)-1] == '\n')
389 p[strlen(p)-1] = 0;
391 if (sscanf(p, " %31[a-zA-Z] = %255s", name, value) != 2)
392 continue;
394 if (g_strcasecmp("TTYNAME", name) == 0)
395 pin->ttyname = g_strdup(value);
396 else if (g_strcasecmp("TTYTYPE", name) == 0)
397 pin->ttytype = g_strdup(value);
398 else if (g_strcasecmp("DISPLAY", name) == 0)
399 pin->display = g_strdup(value);
400 else if (g_strcasecmp("PATH", name) == 0)
401 pin->path = g_strdup(value);
404 fclose(fp);