Updated the FSF address in the copyright header.
[pwmd.git] / src / pinentry.c
blobbb5255732991913b2e001baef6d5f2a24191260b
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 02110-1301 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 "commands.h"
33 #include "pinentry.h"
34 #include "pwmd_error.h"
36 typedef struct {
37 size_t len;
38 void *buf;
39 } membuf_t;
41 void free_client_list();
42 static gpg_error_t set_pinentry_strings(struct pinentry_s *pin, int which);
44 static int mem_realloc_cb(void *data, const void *buffer, size_t len)
46 membuf_t *mem = (membuf_t *)data;
47 void *p;
49 if (!buffer)
50 return 0;
52 if ((p = xrealloc(mem->buf, mem->len + len)) == NULL)
53 return 1;
55 mem->buf = p;
56 memcpy((char *)mem->buf + mem->len, buffer, len);
57 mem->len += len;
58 return 0;
61 static gpg_error_t assuan_command(struct pinentry_s *pin, gchar **result,
62 const gchar *cmd)
64 membuf_t data;
65 gpg_error_t rc;
67 data.len = 0;
68 data.buf = NULL;
70 rc = assuan_transact(pin->ctx, cmd, mem_realloc_cb, &data, NULL, NULL,
71 NULL, NULL);
73 if (rc) {
74 if (data.buf) {
75 xfree(data.buf);
76 data.buf = NULL;
79 else {
80 if (data.buf) {
81 mem_realloc_cb(&data, "", 1);
82 *result = (gchar *)data.buf;
86 return rc;
89 static gpg_error_t set_pinentry_options(struct pinentry_s *pin)
91 gchar *display = getenv("DISPLAY");
92 gint have_display = 0;
93 gchar *tty = NULL, *ttytype = NULL;
94 gchar *opt, *val;
95 gpg_error_t rc;
96 gchar *result = NULL;
97 gchar cmd[ASSUAN_LINELENGTH];
99 if (pin->display || display)
100 have_display = 1;
101 else {
102 tty = pin->ttyname ? pin->ttyname : ttyname(STDOUT_FILENO);
104 if (!tty)
105 return GPG_ERR_CANCELED;
108 if (!have_display && !tty)
109 return GPG_ERR_CANCELED;
111 if (!have_display) {
112 gchar *p = getenv("TERM");
114 ttytype = pin->ttytype ? pin->ttytype : p;
116 if (!ttytype)
117 return GPG_ERR_CANCELED;
120 opt = have_display ? "DISPLAY" : "TTYNAME";
121 val = have_display ? pin->display ? pin->display : display : tty;
122 g_snprintf(cmd, sizeof(cmd), "OPTION %s=%s", g_ascii_strdown(opt, strlen(opt)), val);
123 rc = assuan_command(pin, &result, cmd);
125 if (rc)
126 return rc;
128 if (!have_display) {
129 g_snprintf(cmd, sizeof(cmd), "OPTION ttytype=%s", ttytype);
130 rc = assuan_command(pin, &result, cmd);
133 return rc;
136 static gpg_error_t launch_pinentry(struct pinentry_s *pin)
138 gpg_error_t rc;
139 assuan_context_t ctx;
140 gint child_list[] = {-1};
141 const gchar *argv[4];
143 argv[0] = "pinentry";
145 if (pin->display) {
146 argv[1] = "--display";
147 argv[2] = pin->display;
148 argv[3] = NULL;
150 else
151 argv[1] = NULL;
153 rc = assuan_pipe_connect(&ctx, pin->path ? pin->path : PINENTRY_PATH,
154 argv, child_list);
156 if (rc)
157 return rc;
159 pin->pid = assuan_get_pid(ctx);
160 pin->ctx = ctx;
161 rc = set_pinentry_options(pin);
162 return rc ? rc : set_pinentry_strings(pin, 0);
165 static gpg_error_t pinentry_command(struct pinentry_s *pin, gchar **result,
166 const gchar *cmd)
168 gpg_error_t rc = 0;
170 if (!pin->ctx)
171 rc = launch_pinentry(pin);
173 return rc ? rc : assuan_command(pin, result, cmd);
176 static gpg_error_t set_pinentry_strings(struct pinentry_s *pin, int which)
178 char *buf;
179 gpg_error_t rc;
180 gchar *title = NULL;
182 if (which == 1)
183 title = g_strdup(N_("Password mismatch, please try again."));
184 else if (!pin->title)
185 title = pin->title = g_strdup(N_("Password Manager Daemon"));
186 else
187 title = pin->title;
189 if (!pin->prompt)
190 pin->prompt = g_strdup(N_("Password:"));
192 if (!pin->desc && !which)
193 pin->desc = g_strdup_printf(pin->which == PINENTRY_OPEN ?
194 N_("A password is required to open the file \"%s\". Please%%0Aenter the password below.") :
195 N_("A password is required to save to the file \"%s\". Please%%0Aenter the password below."),
196 pin->filename);
198 if (which == 2)
199 buf = g_strdup_printf("SETERROR %s", N_("Please type the password again for confirmation."));
200 else
201 buf = g_strdup_printf("SETERROR %s", pin->desc);
203 rc = pinentry_command(pin, NULL, buf);
204 g_free(buf);
206 if (rc)
207 goto done;
209 buf = g_strdup_printf("SETPROMPT %s", pin->prompt);
210 rc = pinentry_command(pin, NULL, buf);
211 g_free(buf);
213 if (rc)
214 goto done;
216 buf = g_strdup_printf("SETDESC %s", title);
217 rc = pinentry_command(pin, NULL, buf);
218 g_free(buf);
220 done:
221 if (which == 1)
222 g_free(title);
224 return rc;
227 static void pinentry_disconnect(struct pinentry_s *pin)
229 if (!pin)
230 return;
232 if (pin->ctx)
233 assuan_disconnect(pin->ctx);
235 pin->ctx = NULL;
236 pin->pid = 0;
239 static gpg_error_t do_getpin(struct pinentry_s *pin, char **result)
241 gpg_error_t rc;
243 *result = NULL;
244 rc = pinentry_command(pin, result, "GETPIN");
246 if (!*result)
247 *result = xstrdup("");
249 return rc;
252 gpg_error_t pinentry_getpin(struct pinentry_s *pin, gchar **result)
254 gint which = 0;
255 gpg_error_t rc = set_pinentry_strings(pin, which);
256 gchar *result1 = NULL;
258 if (rc) {
259 pinentry_disconnect(pin);
260 return rc;
263 again:
264 rc = do_getpin(pin, result);
266 if (rc)
267 goto done;
269 if (pin->which == PINENTRY_SAVE) {
270 if (!result1) {
271 rc = set_pinentry_strings(pin, 2);
273 if (rc)
274 goto done;
276 result1 = g_strdup(*result);
277 goto again;
280 if (strcmp(result1, *result)) {
281 g_free(result1);
282 xfree(*result);
283 result1 = *result = NULL;
284 rc = set_pinentry_strings(pin, 1);
286 if (rc)
287 goto done;
289 goto again;
293 done:
294 g_free(result1);
295 pinentry_disconnect(pin);
296 return rc;
299 static int write_result(int fd, pinentry_key_s *pk, char *result)
301 size_t len;
303 if (pk->error) {
305 * libassuan handles GPG_ERR_EOF in assuan_process_done() and
306 * will disconnect the client even if the error isn't related
307 * to it. Use GPG_ERR_CANCELED instead.
309 if (gpg_err_code(pk->error) == GPG_ERR_EOF)
310 pk->error = GPG_ERR_CANCELED;
312 len = pth_write(fd, pk, sizeof(pinentry_key_s));
313 close(fd);
315 if (len != sizeof(pinentry_key_s))
316 log_write("%s(%i): write: len != sizeof(pk)", __FUNCTION__, __LINE__);
318 return 1;
321 if (pk->status == PINENTRY_PID)
322 pk->what.pid = atoi(result);
323 else
324 g_strlcpy(pk->what.key, result, sizeof(pk->what.key));
326 xfree(result);
327 len = pth_write(fd, pk, sizeof(pinentry_key_s));
329 if (len != sizeof(pinentry_key_s)) {
330 memset(pk, 0, sizeof(pinentry_key_s));
331 log_write("%s(%i): write: len != sizeof(pk)", __FUNCTION__, __LINE__);
332 close(fd);
333 return 1;
336 if (pk->status != PINENTRY_PID)
337 close(fd);
339 memset(pk, 0, sizeof(pinentry_key_s));
340 return 0;
343 static void reset(struct pinentry_s *pin)
345 int status;
347 pth_waitpid(pin->pid, &status, 0);
348 close(pin->fd);
349 pin->fd = -1;
350 pin->pid = pin->pin_pid = 0;
351 pin->tid = 0;
352 pth_event_isolate(pin->ev);
353 pth_event_free(pin->ev, PTH_FREE_THIS);
354 pin->ev = NULL;
355 pin->status = PINENTRY_NONE;
358 static void *timeout_thread(void *arg)
360 struct pinentry_s *pin = arg;
361 pth_event_t ev = pth_event(PTH_EVENT_TIME, pth_timeout(pin->timeout, 0));
363 pth_wait(ev);
364 pth_event_free(ev, PTH_FREE_THIS);
365 pth_mutex_acquire(&pin->status_mutex, FALSE, NULL);
367 /* pth_cancel() was called from pinentry_iterate() (we have a key).
368 * pth_wait() was the cancelation point. */
369 if (pin->status == PINENTRY_NONE) {
370 reset(pin);
371 pth_mutex_release(&pin->status_mutex);
372 return NULL;
375 if (kill(pin->pin_pid, 0) == 0)
376 if (kill(pin->pin_pid, SIGTERM) == 0)
377 if (kill(pin->pin_pid, 0) == 0)
378 kill(pin->pin_pid, SIGKILL);
380 reset(pin);
381 pin->status = PINENTRY_TIMEOUT;
382 pth_mutex_release(&pin->status_mutex);
383 pth_exit(PTH_CANCELED);
384 return NULL;
387 gpg_error_t pinentry_fork(assuan_context_t ctx)
389 struct client_s *client = assuan_get_pointer(ctx);
390 struct pinentry_s *pin = client->pinentry;
391 gpg_error_t rc;
392 gint p[2];
393 pid_t pid;
394 pinentry_key_s pk;
395 gchar *result = NULL;
397 if (pipe(p) == -1)
398 return gpg_error_from_syserror();
400 pid = pth_fork();
402 switch (pid) {
403 case -1:
404 rc = gpg_error_from_syserror();
405 close(p[0]);
406 close(p[1]);
407 return rc;
408 case 0:
409 close(p[0]);
410 free_client_list();
412 if (pin->timeout > 0) {
414 * Send the pid of the pinentry process back to pwmd so it can
415 * handle the pinentry timeout properly.
417 pk.status = PINENTRY_PID;
418 pk.error = pinentry_command(pin, &result, "GETINFO pid");
420 if (write_result(p[1], &pk, result))
421 _exit(EXIT_FAILURE);
424 pk.status = PINENTRY_RUNNING;
425 pk.error = pinentry_getpin(pin, &result);
427 if (write_result(p[1], &pk, result))
428 _exit(EXIT_FAILURE);
430 _exit(EXIT_SUCCESS);
431 default:
432 close(p[1]);
433 client->pinentry->fd = p[0];
434 client->pinentry->pid = pid;
435 client->pinentry->status = PINENTRY_INIT;
436 break;
440 * Don't call assuan_process_done() here. That should be done in
441 * open_command_finalize() after the key has been read().
443 return 0;
446 gpg_error_t lock_pin_mutex(struct client_s *client)
448 while (pth_mutex_acquire(&pin_mutex, TRUE, NULL) == FALSE) {
449 if (client->ctx) {
450 gpg_error_t rc = send_status(client->ctx, STATUS_LOCKED);
452 if (rc)
453 return rc;
456 pth_sleep(1);
459 client->pinentry->has_lock = TRUE;
460 return 0;
463 void unlock_pin_mutex(struct pinentry_s *pin)
465 if (pin->has_lock == FALSE)
466 return;
468 pth_mutex_release(&pin_mutex);
469 pin->has_lock = FALSE;
472 void cleanup_pinentry(struct pinentry_s *pin)
474 if (!pin)
475 return;
477 unlock_pin_mutex(pin);
479 if (pin->ctx && pin->pid)
480 pinentry_disconnect(pin);
482 g_free(pin->ttyname);
483 g_free(pin->ttytype);
484 g_free(pin->desc);
485 g_free(pin->title);
486 g_free(pin->prompt);
487 g_free(pin->path);
488 g_free(pin->display);
489 g_free(pin->filename);
490 g_free(pin);
493 static void set_pinentry_defaults(struct pinentry_s *pin)
495 FILE *fp;
496 gchar buf[PATH_MAX];
497 struct passwd *pw = getpwuid(getuid());
498 gchar *p;
500 pin->enable = -1;
501 g_snprintf(buf, sizeof(buf), "%s/.pwmd/pinentry.conf", pw->pw_dir);
502 fp = fopen(buf, "r");
504 if (fp) {
505 while ((p = fgets(buf, sizeof(buf), fp)) != NULL) {
506 gchar name[32] = {0}, value[256] = {0};
508 if (*p == '#')
509 continue;
511 if (p[strlen(p)-1] == '\n')
512 p[strlen(p)-1] = 0;
514 if (sscanf(p, " %31[a-zA-Z] = %255s", name, value) != 2)
515 continue;
517 if (g_strcasecmp("TTYNAME", name) == 0)
518 pin->ttyname = g_strdup(value);
519 else if (g_strcasecmp("TTYTYPE", name) == 0)
520 pin->ttytype = g_strdup(value);
521 else if (g_strcasecmp("DISPLAY", name) == 0)
522 pin->display = g_strdup(value);
523 else if (g_strcasecmp("PATH", name) == 0)
524 pin->path = g_strdup(value);
527 fclose(fp);
530 pin->timeout = get_key_file_integer("global", "pinentry_timeout");
533 pth_event_t pinentry_iterate(struct client_s *cl, pth_event_t ev)
535 gpg_error_t rc;
537 pth_mutex_acquire(&cl->pinentry->status_mutex, FALSE, NULL);
539 /* Set from pinentry_timeout_thread(). */
540 if (cl->pinentry->status == PINENTRY_TIMEOUT) {
541 rc = send_error(cl->ctx, GPG_ERR_TIMEOUT);
543 if (cl->pinentry->which == PINENTRY_OPEN)
544 cleanup_client(cl);
546 reset(cl->pinentry);
547 unlock_pin_mutex(cl->pinentry);
550 if (cl->pinentry->status == PINENTRY_RUNNING) {
551 pth_event_isolate(cl->pinentry->ev);
553 if (pth_event_occurred(cl->pinentry->ev)) {
554 guchar shakey[gcrykeysize];
555 pinentry_key_s pk;
556 gsize len;
558 memset(&pk, 0, sizeof(pk));
559 len = pth_read(cl->pinentry->fd, &pk, sizeof(pk));
561 if (len == sizeof(pk)) {
562 if (pk.error) {
563 if (cl->pinentry->status == PINENTRY_TIMEOUT)
564 pk.error = GPG_ERR_TIMEOUT;
566 rc = send_error(cl->ctx, pk.error);
568 else if (pk.status == PINENTRY_PID) {
570 * Start the timeout thread for the pinentry process
571 * now that we know the pid of it.
573 pth_attr_t attr = pth_attr_new();
575 pth_attr_init(attr);
576 pth_attr_set(attr, PTH_ATTR_JOINABLE, 0);
577 pth_attr_set(attr, PTH_ATTR_CANCEL_STATE,
578 PTH_CANCEL_ASYNCHRONOUS);
579 cl->pinentry->pin_pid = pk.what.pid;
580 cl->pinentry->tid = pth_spawn(attr, timeout_thread,
581 cl->pinentry);
583 else {
584 if (cl->pinentry->tid) {
585 cl->pinentry->status = PINENTRY_NONE;
586 pth_cancel(cl->pinentry->tid);
589 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, pk.what.key,
590 strlen(pk.what.key) == 0 ? 1 : strlen(pk.what.key));
591 rc = cl->pinentry->cb(cl->ctx, shakey, FALSE);
592 memset(shakey, 0, sizeof(shakey));
595 else if (len == -1) {
596 if (cl->pinentry->status == PINENTRY_TIMEOUT)
597 pk.error = GPG_ERR_TIMEOUT;
599 pk.error = gpg_err_code_from_syserror();
600 log_write("%s", gpg_strerror(pk.error));
602 else if (len == 0) {
603 if (cl->pinentry->status == PINENTRY_TIMEOUT)
604 pk.error = GPG_ERR_TIMEOUT;
606 pk.error = GPG_ERR_EOF;
607 log_write("%s", gpg_strerror(pk.error));
609 else
610 log_write(N_("pth_read(): short byte count"));
612 if (pk.error) {
613 if (cl->pinentry->tid) {
614 pth_cancel(cl->pinentry->tid);
615 cl->pinentry->status = PINENTRY_NONE;
617 else
618 reset(cl->pinentry);
620 if (cl->pinentry->which == PINENTRY_OPEN)
621 cleanup_client(cl);
623 else if (pk.status == PINENTRY_RUNNING)
624 reset(cl->pinentry);
626 if (pk.error || pk.status == PINENTRY_RUNNING) {
627 unlock_file_mutex(cl);
628 unlock_pin_mutex(cl->pinentry);
631 memset(&pk, 0, sizeof(pk));
634 pth_event_concat(ev, cl->pinentry->ev, NULL);
637 pth_mutex_release(&cl->pinentry->status_mutex);
638 return ev;
641 struct pinentry_s *pinentry_init()
643 struct pinentry_s *pin = g_malloc0(sizeof(struct pinentry_s));
645 if (!pin)
646 return NULL;
648 pth_mutex_init(&pin->status_mutex);
649 set_pinentry_defaults(pin);
650 return pin;