Fixed a memory leak in pinentry_iterate().
[pwmd.git] / src / pinentry.c
blobd28ac4f79a9c160476eb33a8dd53b2982d2fa5ee
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 #ifdef __FreeBSD__
31 #include <sys/types.h>
32 #include <signal.h>
33 #endif
35 #ifdef WITH_QUALITY
36 #include <crack.h>
37 #include "misc.h"
38 #endif
40 #include "mem.h"
41 #include "common.h"
42 #include "commands.h"
43 #include "pinentry.h"
44 #include "misc.h"
45 #include "pwmd_error.h"
47 void free_client_list();
48 static gpg_error_t set_pinentry_strings(struct pinentry_s *pin, int which);
50 static int mem_realloc_cb(void *data, const void *buffer, size_t len)
52 membuf_t *mem = (membuf_t *)data;
53 void *p;
55 if (!buffer)
56 return 0;
58 if ((p = xrealloc(mem->buf, mem->len + len)) == NULL)
59 return 1;
61 mem->buf = p;
62 memcpy((char *)mem->buf + mem->len, buffer, len);
63 mem->len += len;
64 return 0;
67 #ifdef WITH_QUALITY
68 static int quality_cb(void *data, const char *line)
70 struct pinentry_s *pin = data;
71 const gchar *tmp;
72 gint score = 0;
73 gchar buf[5];
75 if (strncmp(line, "QUALITY ", 8) != 0)
76 return GPG_ERR_INV_ARG;
78 if (!(tmp = FascistCheck(line+8, CRACKLIB_DICT)))
79 return assuan_send_data(pin->ctx, "100", 3);
81 if (!strcmp(tmp, "it's WAY too short"))
82 score = 10;
83 else if (!strcmp(tmp, "it is too short"))
84 score = 20;
85 else if (!strcmp(tmp, "it is all whitespace"))
86 score = 25;
87 else if (!strcmp(tmp, "it is based on your username"))
88 score = 30;
89 else if (!strcmp(tmp, "it is based on a dictionary word"))
90 score = 40;
91 else if (!strcmp(tmp, "it is based upon your password entry"))
92 score = 50;
93 else if (!strcmp(tmp, "it's derived from your password entry"))
94 score = 50;
95 else if (!strcmp(tmp, "it is based on a (reversed) dictionary word"))
96 score = 60;
97 else if (!strcmp(tmp, "it is derivable from your password entry"))
98 score = 70;
99 else if (!strcmp(tmp, "it does not contain enough DIFFERENT characters"))
100 score = 80;
101 else if (!strcmp(tmp, "it is too simplistic/systematic"))
102 score = 90;
103 else
104 score = 0;
106 tmp = (const gchar *)print_fmt(buf, sizeof(buf), "%i", score);
107 return assuan_send_data(pin->ctx, tmp, strlen(tmp));
109 #endif
111 static gpg_error_t assuan_command(struct pinentry_s *pin, gchar **result,
112 const gchar *cmd)
114 gpg_error_t rc;
116 pin->data.len = 0;
117 pin->data.buf = NULL;
119 rc = assuan_transact(pin->ctx, cmd, mem_realloc_cb, &pin->data,
120 pin->inquire_cb, pin->inquire_data, NULL, NULL);
122 if (rc) {
123 if (pin->data.buf) {
124 xfree(pin->data.buf);
125 pin->data.buf = NULL;
128 else {
129 if (pin->data.buf) {
130 mem_realloc_cb(&pin->data, "", 1);
131 *result = (gchar *)pin->data.buf;
135 return rc;
138 static gpg_error_t set_pinentry_options(struct pinentry_s *pin)
140 gchar *display = getenv("DISPLAY");
141 gint have_display = 0;
142 gchar *tty = NULL, *ttytype = NULL;
143 gchar *opt, *val;
144 gpg_error_t rc;
145 gchar *result = NULL;
146 gchar cmd[ASSUAN_LINELENGTH];
148 if (pin->display || display)
149 have_display = 1;
150 else {
151 tty = pin->ttyname ? pin->ttyname : ttyname(STDOUT_FILENO);
153 if (!tty)
154 return GPG_ERR_CANCELED;
157 if (!have_display && !tty)
158 return GPG_ERR_CANCELED;
160 if (!have_display) {
161 gchar *p = getenv("TERM");
163 ttytype = pin->ttytype ? pin->ttytype : p;
165 if (!ttytype)
166 return GPG_ERR_CANCELED;
169 opt = have_display ? "DISPLAY" : "TTYNAME";
170 val = have_display ? pin->display ? pin->display : display : tty;
171 g_snprintf(cmd, sizeof(cmd), "OPTION %s=%s", g_ascii_strdown(opt, strlen(opt)), val);
172 rc = assuan_command(pin, &result, cmd);
174 if (rc)
175 return rc;
177 if (!have_display) {
178 g_snprintf(cmd, sizeof(cmd), "OPTION ttytype=%s", ttytype);
179 rc = assuan_command(pin, &result, cmd);
182 return rc;
185 static gpg_error_t launch_pinentry(struct pinentry_s *pin)
187 gpg_error_t rc;
188 assuan_context_t ctx;
189 gint child_list[] = {-1};
190 const gchar *argv[4];
192 argv[0] = "pinentry";
194 if (pin->display) {
195 argv[1] = "--display";
196 argv[2] = pin->display;
197 argv[3] = NULL;
199 else
200 argv[1] = NULL;
202 rc = assuan_pipe_connect(&ctx, pin->path ? pin->path : PINENTRY_PATH,
203 argv, child_list);
205 if (rc)
206 return rc;
208 pin->pid = assuan_get_pid(ctx);
209 pin->ctx = ctx;
210 rc = set_pinentry_options(pin);
211 return rc ? rc : set_pinentry_strings(pin, 0);
214 static gpg_error_t pinentry_command(struct pinentry_s *pin, gchar **result,
215 const gchar *cmd)
217 gpg_error_t rc = 0;
219 if (!pin->ctx)
220 rc = launch_pinentry(pin);
222 return rc ? rc : assuan_command(pin, result, cmd);
225 static gpg_error_t set_pinentry_strings(struct pinentry_s *pin, int which)
227 char *buf;
228 gpg_error_t rc;
229 gchar *title = NULL;
231 #ifdef WITH_QUALITY
232 if (pin->which == PINENTRY_SAVE && which != 2) {
233 rc = pinentry_command(pin, NULL, "SETQUALITYBAR");
235 if (rc)
236 goto done;
238 pin->inquire_cb = quality_cb;
239 pin->inquire_data = pin;
241 #endif
243 if (which == 1)
244 title = g_strdup(N_("Passphrase mismatch, please try again."));
245 else if (!pin->title)
246 title = pin->title = g_strdup(N_("Password Manager Daemon"));
247 else
248 title = pin->title;
250 if (!pin->prompt)
251 pin->prompt = g_strdup(N_("Passphrase:"));
253 if (!pin->desc && !which)
254 pin->desc = g_strdup_printf(pin->which == PINENTRY_OPEN ?
255 N_("A passphrase is required to open the file \"%s\". Please%%0Aenter the passphrase below.") :
256 N_("A passphrase is required to save to the file \"%s\". Please%%0Aenter the passphrase below."),
257 pin->filename);
259 if (which == 2)
260 buf = g_strdup_printf("SETERROR %s", N_("Please enter the passphrase again for confirmation."));
261 else
262 buf = g_strdup_printf("SETERROR %s", pin->desc);
264 rc = pinentry_command(pin, NULL, buf);
265 g_free(buf);
267 if (rc)
268 goto done;
270 buf = g_strdup_printf("SETPROMPT %s", pin->prompt);
271 rc = pinentry_command(pin, NULL, buf);
272 g_free(buf);
274 if (rc)
275 goto done;
277 buf = g_strdup_printf("SETDESC %s", title);
278 rc = pinentry_command(pin, NULL, buf);
279 g_free(buf);
281 done:
282 if (which == 1)
283 g_free(title);
285 return rc;
288 static void pinentry_disconnect(struct pinentry_s *pin)
290 if (!pin)
291 return;
293 if (pin->ctx)
294 assuan_disconnect(pin->ctx);
296 pin->ctx = NULL;
297 pin->pid = 0;
300 static gpg_error_t do_getpin(struct pinentry_s *pin, char **result)
302 gpg_error_t rc;
304 *result = NULL;
305 rc = pinentry_command(pin, result, "GETPIN");
307 if (!*result)
308 *result = xstrdup("");
310 return rc;
313 gpg_error_t pinentry_getpin(struct pinentry_s *pin, gchar **result)
315 gint which = 0;
316 gpg_error_t rc = set_pinentry_strings(pin, which);
317 gchar *result1 = NULL;
319 if (rc)
320 goto done;
322 again:
323 rc = do_getpin(pin, result);
325 if (rc)
326 goto done;
328 if (pin->which == PINENTRY_SAVE) {
329 if (!result1) {
330 rc = set_pinentry_strings(pin, 2);
332 if (rc)
333 goto done;
335 result1 = g_strdup(*result);
336 goto again;
339 if (strcmp(result1, *result)) {
340 g_free(result1);
341 xfree(*result);
342 result1 = *result = NULL;
343 rc = set_pinentry_strings(pin, 1);
345 if (rc)
346 goto done;
348 goto again;
352 done:
353 g_free(result1);
354 pinentry_disconnect(pin);
355 return rc;
358 static int write_result(int fd, pinentry_key_s *pk, char *result)
360 size_t len;
362 if (pk->error) {
364 * libassuan handles GPG_ERR_EOF in assuan_process_done() and
365 * will disconnect the client even if the error isn't related
366 * to it. Use GPG_ERR_CANCELED instead.
368 if (gpg_err_code(pk->error) == GPG_ERR_EOF)
369 pk->error = GPG_ERR_CANCELED;
371 len = pth_write(fd, pk, sizeof(pinentry_key_s));
372 close(fd);
374 if (len != sizeof(pinentry_key_s))
375 log_write("%s(%i): write: len != sizeof(pk)", __FUNCTION__, __LINE__);
377 return 1;
380 if (pk->status == PINENTRY_PID)
381 pk->what.pid = atoi(result);
382 else
383 g_strlcpy(pk->what.key, result, sizeof(pk->what.key));
385 xfree(result);
386 len = pth_write(fd, pk, sizeof(pinentry_key_s));
388 if (len != sizeof(pinentry_key_s)) {
389 memset(pk, 0, sizeof(pinentry_key_s));
390 log_write("%s(%i): write: len != sizeof(pk)", __FUNCTION__, __LINE__);
391 close(fd);
392 return 1;
395 if (pk->status != PINENTRY_PID)
396 close(fd);
398 memset(pk, 0, sizeof(pinentry_key_s));
399 return 0;
402 static void reset(struct pinentry_s *pin)
404 int status;
406 pth_waitpid(pin->pid, &status, 0);
407 close(pin->fd);
408 pin->fd = -1;
409 pin->pid = pin->pin_pid = 0;
410 pin->tid = 0;
411 pth_event_isolate(pin->ev);
412 pth_event_free(pin->ev, PTH_FREE_THIS);
413 pin->ev = NULL;
414 pin->status = PINENTRY_NONE;
417 static void *timeout_thread(void *arg)
419 struct pinentry_s *pin = arg;
420 pth_event_t ev = pth_event(PTH_EVENT_TIME, pth_timeout(pin->timeout, 0));
422 pth_wait(ev);
423 pth_event_free(ev, PTH_FREE_THIS);
424 pth_mutex_acquire(&pin->status_mutex, FALSE, NULL);
426 /* pth_cancel() was called from pinentry_iterate() (we have a key).
427 * pth_wait() was the cancelation point. */
428 if (pin->status == PINENTRY_NONE) {
429 reset(pin);
430 pth_mutex_release(&pin->status_mutex);
431 return NULL;
434 if (kill(pin->pin_pid, 0) == 0)
435 if (kill(pin->pin_pid, SIGTERM) == 0)
436 if (kill(pin->pin_pid, 0) == 0)
437 kill(pin->pin_pid, SIGKILL);
439 reset(pin);
440 pin->status = PINENTRY_TIMEOUT;
441 pth_mutex_release(&pin->status_mutex);
442 pth_exit(PTH_CANCELED);
443 return NULL;
446 gpg_error_t pinentry_fork(assuan_context_t ctx)
448 struct client_s *client = assuan_get_pointer(ctx);
449 struct pinentry_s *pin = client->pinentry;
450 gpg_error_t rc;
451 gint p[2];
452 pid_t pid;
453 pinentry_key_s pk;
454 gchar *result = NULL;
456 if (pipe(p) == -1)
457 return gpg_error_from_syserror();
459 pid = pth_fork();
461 switch (pid) {
462 case -1:
463 rc = gpg_error_from_syserror();
464 close(p[0]);
465 close(p[1]);
466 return rc;
467 case 0:
468 close(p[0]);
469 free_client_list();
471 if (pin->timeout > 0 && client->pinentry->which == PINENTRY_OPEN) {
473 * Send the pid of the pinentry process back to pwmd so it can
474 * handle the pinentry timeout properly.
476 pk.status = PINENTRY_PID;
477 pk.error = pinentry_command(pin, &result, "GETINFO pid");
479 if (write_result(p[1], &pk, result))
480 _exit(EXIT_FAILURE);
483 pk.status = PINENTRY_RUNNING;
484 pk.error = pinentry_getpin(pin, &result);
486 if (write_result(p[1], &pk, result))
487 _exit(EXIT_FAILURE);
489 _exit(EXIT_SUCCESS);
490 default:
491 close(p[1]);
492 client->pinentry->fd = p[0];
493 client->pinentry->pid = pid;
494 client->pinentry->status = PINENTRY_INIT;
495 break;
499 * Don't call assuan_process_done() here. That should be done in
500 * open_command_finalize() after the key has been read().
502 return 0;
505 gpg_error_t lock_pin_mutex(struct client_s *client)
507 while (pth_mutex_acquire(&pin_mutex, TRUE, NULL) == FALSE) {
508 if (client->ctx) {
509 gpg_error_t rc = send_status(client->ctx, STATUS_LOCKED, NULL);
511 if (rc)
512 return rc;
515 pth_sleep(1);
518 client->pinentry->has_lock = TRUE;
519 return 0;
522 void unlock_pin_mutex(struct pinentry_s *pin)
524 if (pin->has_lock == FALSE)
525 return;
527 pth_mutex_release(&pin_mutex);
528 pin->has_lock = FALSE;
531 void cleanup_pinentry(struct pinentry_s *pin)
533 if (!pin)
534 return;
536 unlock_pin_mutex(pin);
538 if (pin->ctx && pin->pid)
539 pinentry_disconnect(pin);
541 g_free(pin->ttyname);
542 g_free(pin->ttytype);
543 g_free(pin->desc);
544 g_free(pin->title);
545 g_free(pin->prompt);
546 g_free(pin->path);
547 g_free(pin->display);
548 g_free(pin->filename);
549 g_free(pin);
552 void set_pinentry_defaults(struct pinentry_s *pin)
554 FILE *fp;
555 gchar buf[PATH_MAX];
556 struct passwd *pw = getpwuid(getuid());
557 gchar *p;
559 pin->enable = -1;
560 g_snprintf(buf, sizeof(buf), "%s/.pwmd/pinentry.conf", pw->pw_dir);
561 fp = fopen(buf, "r");
563 if (fp) {
564 while ((p = fgets(buf, sizeof(buf), fp)) != NULL) {
565 gchar name[32] = {0}, value[256] = {0};
567 if (*p == '#')
568 continue;
570 if (p[strlen(p)-1] == '\n')
571 p[strlen(p)-1] = 0;
573 if (sscanf(p, " %31[a-zA-Z] = %255s", name, value) != 2)
574 continue;
576 if (g_strcasecmp("TTYNAME", name) == 0)
577 pin->ttyname = g_strdup(value);
578 else if (g_strcasecmp("TTYTYPE", name) == 0)
579 pin->ttytype = g_strdup(value);
580 else if (g_strcasecmp("DISPLAY", name) == 0)
581 pin->display = g_strdup(value);
582 else if (g_strcasecmp("PATH", name) == 0)
583 pin->path = g_strdup(value);
586 fclose(fp);
589 pin->timeout = get_key_file_integer("global", "pinentry_timeout");
592 pth_event_t pinentry_iterate(struct client_s *cl, pth_event_t ev)
594 gpg_error_t rc;
596 pth_mutex_acquire(&cl->pinentry->status_mutex, FALSE, NULL);
598 /* Set from pinentry_timeout_thread(). */
599 if (cl->pinentry->status == PINENTRY_TIMEOUT) {
600 cl->pinentry->status = PINENTRY_NONE;
601 rc = send_error(cl->ctx, GPG_ERR_TIMEOUT);
602 cleanup_client(cl);
603 reset(cl->pinentry);
604 unlock_pin_mutex(cl->pinentry);
607 if (cl->pinentry->status == PINENTRY_RUNNING) {
608 pth_event_isolate(cl->pinentry->ev);
610 if (pth_event_occurred(cl->pinentry->ev)) {
611 guchar *shakey;
612 pinentry_key_s pk;
613 gsize len;
615 memset(&pk, 0, sizeof(pk));
616 len = pth_read(cl->pinentry->fd, &pk, sizeof(pk));
618 if (len == sizeof(pk)) {
619 if (pk.error) {
620 if (cl->pinentry->status == PINENTRY_TIMEOUT)
621 pk.error = GPG_ERR_TIMEOUT;
623 rc = send_error(cl->ctx, pk.error);
625 else if (pk.status == PINENTRY_PID) {
627 * Start the timeout thread for the pinentry process
628 * now that we know the pid of it.
630 pth_attr_t attr = pth_attr_new();
632 pth_attr_init(attr);
633 pth_attr_set(attr, PTH_ATTR_JOINABLE, 0);
634 pth_attr_set(attr, PTH_ATTR_CANCEL_STATE,
635 PTH_CANCEL_ASYNCHRONOUS);
636 cl->pinentry->pin_pid = pk.what.pid;
637 cl->pinentry->tid = pth_spawn(attr, timeout_thread,
638 cl->pinentry);
639 pth_attr_destroy(attr);
641 else {
642 if (cl->pinentry->tid) {
643 cl->pinentry->status = PINENTRY_NONE;
644 pth_cancel(cl->pinentry->tid);
647 shakey = gcry_malloc(gcrykeysize);
649 if (!shakey)
650 pk.error = gpg_error_from_errno(ENOMEM);
651 else {
652 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey,
653 pk.what.key,
654 strlen(pk.what.key) == 0 ? 1 : strlen(pk.what.key));
655 rc = cl->pinentry->cb(cl->ctx, shakey, FALSE);
659 else if (len == -1) {
660 if (cl->pinentry->status == PINENTRY_TIMEOUT)
661 pk.error = GPG_ERR_TIMEOUT;
663 pk.error = gpg_err_code_from_syserror();
664 log_write("%s", gpg_strerror(pk.error));
666 else if (len == 0) {
667 if (cl->pinentry->status == PINENTRY_TIMEOUT)
668 pk.error = GPG_ERR_TIMEOUT;
670 pk.error = GPG_ERR_EOF;
671 log_write("%s", gpg_strerror(pk.error));
673 else
674 log_write(N_("pth_read(): short byte count"));
676 if (pk.error) {
677 if (cl->pinentry->tid) {
678 pth_cancel(cl->pinentry->tid);
679 cl->pinentry->status = PINENTRY_NONE;
681 else
682 reset(cl->pinentry);
684 if (cl->pinentry->which == PINENTRY_OPEN)
685 cleanup_client(cl);
687 else if (pk.status == PINENTRY_RUNNING)
688 reset(cl->pinentry);
690 if (pk.error || pk.status == PINENTRY_RUNNING) {
691 unlock_file_mutex(cl);
692 unlock_pin_mutex(cl->pinentry);
695 memset(&pk, 0, sizeof(pk));
698 pth_event_concat(ev, cl->pinentry->ev, NULL);
701 pth_mutex_release(&cl->pinentry->status_mutex);
702 return ev;
705 struct pinentry_s *pinentry_init()
707 struct pinentry_s *pin = g_malloc0(sizeof(struct pinentry_s));
709 if (!pin)
710 return NULL;
712 pth_mutex_init(&pin->status_mutex);
713 set_pinentry_defaults(pin);
714 return pin;