Use assuan_register_pre_cmd_notify(). This is a patch to libassuan.
[pwmd.git] / src / pinentry.c
blobbc940ef2418ed7d597b60e5b2eb723a3e1821169
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>
25 #include <signal.h>
26 #include <sys/types.h>
27 #include <sys/wait.h>
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
33 #ifdef __FreeBSD__
34 #include <sys/types.h>
35 #include <signal.h>
36 #endif
38 #ifdef WITH_QUALITY
39 #include <crack.h>
40 #include "misc.h"
41 #endif
43 #include "mem.h"
44 #include "common.h"
45 #include "commands.h"
46 #include "pinentry.h"
47 #include "misc.h"
48 #include "pwmd_error.h"
49 #include "lock.h"
51 void free_client_list();
52 static gpg_error_t set_pinentry_strings(struct pinentry_s *pin, int which);
54 static assuan_error_t mem_realloc_cb(void *data, const void *buffer, size_t len)
56 membuf_t *mem = (membuf_t *)data;
57 void *p;
59 if (!buffer)
60 return 0;
62 if ((p = xrealloc(mem->buf, mem->len + len)) == NULL)
63 return 1;
65 mem->buf = p;
66 memcpy((char *)mem->buf + mem->len, buffer, len);
67 mem->len += len;
68 return 0;
71 #ifdef WITH_QUALITY
72 static assuan_error_t quality_cb(void *data, const char *line)
74 struct pinentry_s *pin = data;
75 const gchar *tmp;
76 gint score = 0;
77 gchar buf[5];
79 if (strncmp(line, "QUALITY ", 8) != 0)
80 return GPG_ERR_INV_ARG;
82 if (!(tmp = FascistCheck(line+8, CRACKLIB_DICT)))
83 return assuan_send_data(pin->ctx, "100", 3);
85 if (!strcmp(tmp, N_("it's WAY too short")))
86 score = 10;
87 else if (!strcmp(tmp, N_("it is too short")))
88 score = 20;
89 else if (!strcmp(tmp, N_("it is all whitespace")))
90 score = 25;
91 else if (!strcmp(tmp, N_("it is based on your username")))
92 score = 30;
93 else if (!strcmp(tmp, N_("it is based on a dictionary word")))
94 score = 40;
95 else if (!strcmp(tmp, N_("it is based upon your password entry")))
96 score = 50;
97 else if (!strcmp(tmp, N_("it's derived from your password entry")))
98 score = 50;
99 else if (!strcmp(tmp, N_("it is based on a (reversed) dictionary word")))
100 score = 60;
101 else if (!strcmp(tmp, N_("it is derivable from your password entry")))
102 score = 70;
103 else if (!strcmp(tmp, N_("it does not contain enough DIFFERENT characters")))
104 score = 80;
105 else if (!strcmp(tmp, N_("it is too simplistic/systematic")))
106 score = 90;
107 else
108 score = 0;
110 tmp = (const gchar *)print_fmt(buf, sizeof(buf), "%i", score);
111 return assuan_send_data(pin->ctx, tmp, strlen(tmp));
113 #endif
115 static gpg_error_t assuan_command(struct pinentry_s *pin, gchar **result,
116 const gchar *cmd)
118 gpg_error_t rc;
120 pin->data.len = 0;
121 pin->data.buf = NULL;
123 rc = assuan_transact(pin->ctx, cmd, mem_realloc_cb, &pin->data,
124 pin->inquire_cb, pin->inquire_data, NULL, NULL);
126 if (rc) {
127 if (pin->data.buf) {
128 xfree(pin->data.buf);
129 pin->data.buf = NULL;
132 else {
133 if (pin->data.buf) {
134 mem_realloc_cb(&pin->data, "", 1);
135 *result = (gchar *)pin->data.buf;
139 return rc;
142 static gpg_error_t set_pinentry_options(struct pinentry_s *pin)
144 gchar *display = getenv("DISPLAY");
145 gint have_display = 0;
146 gchar *tty = NULL, *ttytype = NULL;
147 gchar *opt, *val;
148 gpg_error_t rc;
149 gchar *result = NULL;
150 gchar cmd[ASSUAN_LINELENGTH];
152 if (pin->display || display)
153 have_display = 1;
154 else {
155 tty = pin->ttyname ? pin->ttyname : ttyname(STDOUT_FILENO);
157 if (!tty)
158 return GPG_ERR_CANCELED;
161 if (!have_display && !tty)
162 return GPG_ERR_CANCELED;
164 if (!have_display) {
165 gchar *p = getenv("TERM");
167 ttytype = pin->ttytype ? pin->ttytype : p;
169 if (!ttytype)
170 return GPG_ERR_CANCELED;
173 opt = have_display ? "DISPLAY" : "TTYNAME";
174 val = have_display ? pin->display ? pin->display : display : tty;
175 g_snprintf(cmd, sizeof(cmd), "OPTION %s=%s", g_ascii_strdown(opt, strlen(opt)), val);
176 rc = assuan_command(pin, &result, cmd);
178 if (rc)
179 return rc;
181 if (!have_display) {
182 g_snprintf(cmd, sizeof(cmd), "OPTION ttytype=%s", ttytype);
183 rc = assuan_command(pin, &result, cmd);
186 return rc;
189 static gpg_error_t launch_pinentry(struct pinentry_s *pin)
191 gpg_error_t rc;
192 assuan_context_t ctx;
193 gint child_list[] = {-1};
194 const gchar *argv[8];
195 const gchar **p = argv;
196 gchar *tmp;
198 *p++ = "pinentry";
200 if (pin->display) {
201 *p++ = "--display";
202 *p++ = pin->display;
205 if (pin->lcctype) {
206 *p++ = "--lc-ctype";
207 *p++ = pin->lcctype;
210 if (pin->lcmessages) {
211 *p++ = "--lc-messages";
212 *p++ = pin->lcmessages;
215 *p = NULL;
216 tmp = get_key_file_string("global", "pinentry_path");
217 rc = assuan_pipe_connect(&ctx, pin->path ? pin->path : tmp, argv,
218 child_list);
219 g_free(tmp);
221 if (rc)
222 return rc;
224 pin->pid = assuan_get_pid(ctx);
225 pin->ctx = ctx;
226 rc = set_pinentry_options(pin);
227 return rc ? rc : set_pinentry_strings(pin, 0);
230 static gpg_error_t pinentry_command(struct pinentry_s *pin, gchar **result,
231 const gchar *cmd)
233 gpg_error_t rc = 0;
235 if (!pin->ctx)
236 rc = launch_pinentry(pin);
238 return rc ? rc : assuan_command(pin, result, cmd);
241 static gpg_error_t set_pinentry_strings(struct pinentry_s *pin, int which)
243 char *buf;
244 gpg_error_t rc;
245 gchar *title = NULL;
247 #ifdef WITH_QUALITY
248 if (pin->which == PINENTRY_SAVE && which != 2) {
249 rc = pinentry_command(pin, NULL, "SETQUALITYBAR");
251 if (rc)
252 goto done;
254 pin->inquire_cb = quality_cb;
255 pin->inquire_data = pin;
257 #endif
259 if (which == 1)
260 title = g_strdup(N_("Passphrase mismatch, please try again."));
261 else if (!pin->title)
262 title = pin->title = g_strdup_printf(N_("Password Manager Daemon%s%s"),
263 pin->name ? ": " : "", pin->name ? pin->name : "");
264 else
265 title = pin->title;
267 if (!pin->prompt)
268 pin->prompt = g_strdup(N_("Passphrase:"));
270 if (!pin->desc && !which)
271 pin->desc = g_strdup_printf(pin->which == PINENTRY_OPEN ?
272 N_("A passphrase is required to open the file \"%s\". Please%%0Aenter the passphrase below.") :
273 N_("A passphrase is required to save to the file \"%s\". Please%%0Aenter the passphrase below."),
274 pin->filename);
276 if (which == 2)
277 buf = g_strdup_printf("SETERROR %s", N_("Please enter the passphrase again for confirmation."));
278 else
279 buf = g_strdup_printf("SETERROR %s", pin->desc);
281 rc = pinentry_command(pin, NULL, buf);
282 g_free(buf);
284 if (rc)
285 goto done;
287 buf = g_strdup_printf("SETPROMPT %s", pin->prompt);
288 rc = pinentry_command(pin, NULL, buf);
289 g_free(buf);
291 if (rc)
292 goto done;
294 buf = g_strdup_printf("SETDESC %s", title);
295 rc = pinentry_command(pin, NULL, buf);
296 g_free(buf);
298 done:
299 if (which == 1)
300 g_free(title);
302 return rc;
305 static void pinentry_disconnect(struct pinentry_s *pin)
307 if (!pin)
308 return;
310 if (pin->ctx)
311 assuan_disconnect(pin->ctx);
313 pin->ctx = NULL;
314 pin->pid = 0;
317 static gpg_error_t do_getpin(struct pinentry_s *pin, char **result)
319 gpg_error_t rc;
321 *result = NULL;
322 rc = pinentry_command(pin, result, "GETPIN");
324 if (!*result)
325 *result = xstrdup("");
327 return rc;
330 gpg_error_t pinentry_getpin(struct pinentry_s *pin, gchar **result)
332 gint which = 0;
333 gpg_error_t rc = set_pinentry_strings(pin, which);
334 gchar *result1 = NULL;
336 if (rc)
337 goto done;
339 again:
340 rc = do_getpin(pin, result);
342 if (rc)
343 goto done;
345 if (pin->which == PINENTRY_SAVE) {
346 if (!result1) {
347 rc = set_pinentry_strings(pin, 2);
349 if (rc)
350 goto done;
352 result1 = g_strdup(*result);
353 goto again;
356 if (strcmp(result1, *result)) {
357 g_free(result1);
358 xfree(*result);
359 result1 = *result = NULL;
360 rc = set_pinentry_strings(pin, 1);
362 if (rc)
363 goto done;
365 goto again;
369 done:
370 g_free(result1);
371 pinentry_disconnect(pin);
372 return rc;
375 static int write_result(int fd, pinentry_key_s *pk, char *result)
377 size_t len;
379 if (pk->error) {
381 * libassuan handles GPG_ERR_EOF in assuan_process_done() and
382 * will disconnect the client even if the error isn't related
383 * to it. Use GPG_ERR_CANCELED instead.
385 if (gpg_err_code(pk->error) == GPG_ERR_EOF)
386 pk->error = GPG_ERR_CANCELED;
388 len = pth_write(fd, pk, sizeof(pinentry_key_s));
389 close(fd);
391 if (len != sizeof(pinentry_key_s))
392 log_write("%s(%i): write: len != sizeof(pk)", __FUNCTION__, __LINE__);
394 return 1;
397 if (pk->status == PINENTRY_PID)
398 pk->what.pid = atoi(result);
399 else
400 g_strlcpy(pk->what.key, result, sizeof(pk->what.key));
402 xfree(result);
403 len = pth_write(fd, pk, sizeof(pinentry_key_s));
405 if (len != sizeof(pinentry_key_s)) {
406 memset(pk, 0, sizeof(pinentry_key_s));
407 log_write("%s(%i): write: len != sizeof(pk)", __FUNCTION__, __LINE__);
408 close(fd);
409 return 1;
412 if (pk->status != PINENTRY_PID)
413 close(fd);
415 memset(pk, 0, sizeof(pinentry_key_s));
416 return 0;
419 static void reset(struct pinentry_s *pin)
421 int status;
423 if (pin->pid)
424 waitpid(pin->pid, &status, 0);
426 if (pin->fd != -1)
427 close(pin->fd);
429 pin->fd = -1;
430 pin->pid = pin->pin_pid = 0;
431 pin->tid = 0;
432 pin->status = PINENTRY_NONE;
435 /* pin->status_mutex should be locked before calling this function. */
436 static void kill_pinentry(struct pinentry_s *pin)
438 if (pin->pin_pid == 0)
439 return;
441 if (kill(pin->pin_pid, 0) == 0)
442 if (kill(pin->pin_pid, SIGTERM) == 0)
443 if (kill(pin->pin_pid, 0) == 0)
444 kill(pin->pin_pid, SIGKILL);
446 pin->pin_pid = 0;
449 static void timeout_cleanup(void *arg)
451 pth_event_t ev = arg;
453 pth_event_free(ev, PTH_FREE_ALL);
456 static void *timeout_thread(void *arg)
458 struct pinentry_s *pin = arg;
459 pth_event_t ev;
460 pth_attr_t attr = pth_attr_of(pth_self());
462 pth_attr_set(attr, PTH_ATTR_NAME, __FUNCTION__);
463 pth_attr_destroy(attr);
464 ev = pth_event(PTH_EVENT_TIME, pth_timeout(pin->timeout, 0));
465 MUTEX_LOCK(&pin->cond_mutex);
466 pth_cleanup_push(timeout_cleanup, ev);
467 pth_cond_await(&pin->cond, &pin->cond_mutex, ev);
468 pth_cleanup_pop(1);
470 /* pth_cond_notify() was called from pinentry_iterate() (we have a
471 * key). */
472 if (pin->status == PINENTRY_NONE) {
473 MUTEX_UNLOCK(&pin->cond_mutex);
474 pth_exit(PTH_CANCELED);
475 return NULL;
478 MUTEX_LOCK(&pin->status_mutex);
479 kill_pinentry(pin);
480 pin->status = PINENTRY_TIMEOUT;
481 MUTEX_UNLOCK(&pin->cond_mutex);
482 MUTEX_UNLOCK(&pin->status_mutex);
483 pth_exit(PTH_CANCELED);
484 return NULL;
487 static void child_prepare(void *arg)
489 gint i;
490 gint n = g_slist_length(cn_thread_list);
491 struct pinentry_s *pin = arg;
493 for (i = 0; i < n; i++) {
494 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
495 pth_mutex_t *m;
497 cache_get_mutex(cn->cl->md5file, &m);
498 pth_mutex_release(m);
501 pth_mutex_release(&pin->status_mutex);
502 pth_mutex_release(&pin->cond_mutex);
503 free_client_list();
506 gpg_error_t pinentry_fork(assuan_context_t ctx)
508 struct client_s *client = assuan_get_pointer(ctx);
509 struct pinentry_s *pin = client->pinentry;
510 gpg_error_t rc = 0;
511 gint p[2];
512 pid_t pid;
513 pinentry_key_s pk;
514 gchar *result = NULL;
516 if (pipe(p) == -1)
517 return gpg_error_from_syserror();
519 pth_atfork_push(NULL, NULL, child_prepare, pin);
520 pid = pth_fork();
522 switch (pid) {
523 case -1:
524 rc = gpg_error_from_syserror();
525 close(p[0]);
526 close(p[1]);
527 break;
528 case 0:
529 close(p[0]);
530 pin->timeout = get_key_file_integer(pin->filename,
531 "pinentry_timeout");
533 if (pin->timeout > 0 && pin->which == PINENTRY_OPEN) {
535 * Send the pid of the pinentry process back to pwmd so it can
536 * handle the pinentry timeout properly.
538 pk.status = PINENTRY_PID;
539 pk.error = pinentry_command(pin, &result, "GETINFO pid");
541 if (write_result(p[1], &pk, result))
542 _exit(EXIT_FAILURE);
545 pk.status = PINENTRY_RUNNING;
546 pk.error = pinentry_getpin(pin, &result);
548 if (write_result(p[1], &pk, result))
549 _exit(EXIT_FAILURE);
551 _exit(EXIT_SUCCESS);
552 default:
553 close(p[1]);
554 client->pinentry->fd = p[0];
555 client->pinentry->pid = pid;
556 client->pinentry->status = PINENTRY_INIT;
557 break;
561 * Don't call assuan_process_done() here. That should be done in
562 * the callback function which is called after the key has been read()
563 * in pinentry_iterate().
565 pth_atfork_pop();
566 return rc;
569 gpg_error_t lock_pin_mutex(struct client_s *client)
571 gpg_error_t rc = 0;
573 MUTEX_TRYLOCK(client->ctx, &pin_mutex, rc);
575 if (!rc)
576 client->pinentry->has_lock = TRUE;
578 return rc;
581 void unlock_pin_mutex(struct pinentry_s *pin)
583 if (pin->has_lock == FALSE)
584 return;
586 MUTEX_UNLOCK(&pin_mutex);
587 pin->has_lock = FALSE;
590 void cleanup_pinentry(struct pinentry_s *pin)
592 if (!pin)
593 return;
595 if (pin->ctx && pin->pid)
596 pinentry_disconnect(pin);
598 if (!pth_mutex_acquire(&pin->status_mutex, TRUE, NULL) && errno == EBUSY) {
599 MUTEX_UNLOCK(&pin->status_mutex);
601 else
602 pth_mutex_release(&pin->status_mutex);
604 MUTEX_LOCK(&pin->status_mutex);
605 kill_pinentry(pin);
606 MUTEX_UNLOCK(&pin->status_mutex);
607 unlock_pin_mutex(pin);
609 if (!pth_mutex_acquire(&pin->cond_mutex, TRUE, NULL) && errno == EBUSY) {
610 MUTEX_UNLOCK(&pin->cond_mutex);
612 else
613 pth_mutex_release(&pin->cond_mutex);
615 if (pin->name)
616 g_free(pin->name);
618 g_free(pin->ttyname);
619 g_free(pin->ttytype);
620 g_free(pin->desc);
621 g_free(pin->title);
622 g_free(pin->prompt);
623 g_free(pin->path);
624 g_free(pin->display);
625 g_free(pin->filename);
626 g_free(pin->lcctype);
627 g_free(pin->lcmessages);
628 g_free(pin);
631 void reset_pin_defaults(struct pinentry_s *pin)
633 pin->enable = -1;
634 pin->timeout = get_key_file_integer("global", "pinentry_timeout");
637 void set_pinentry_defaults(struct pinentry_s *pin)
639 FILE *fp;
640 gchar buf[PATH_MAX];
641 gchar *p;
643 g_snprintf(buf, sizeof(buf), "%s/.pwmd/pinentry.conf", g_get_home_dir());
644 fp = fopen(buf, "r");
646 if (fp) {
647 while ((p = fgets(buf, sizeof(buf), fp)) != NULL) {
648 gchar name[32] = {0}, value[256] = {0};
650 if (*p == '#')
651 continue;
653 if (p[strlen(p)-1] == '\n')
654 p[strlen(p)-1] = 0;
656 if (sscanf(p, " %31[a-zA-Z] = %255s", name, value) != 2)
657 continue;
659 if (g_strcasecmp("TTYNAME", name) == 0)
660 pin->ttyname = g_strdup(value);
661 else if (g_strcasecmp("TTYTYPE", name) == 0)
662 pin->ttytype = g_strdup(value);
663 else if (g_strcasecmp("DISPLAY", name) == 0)
664 pin->display = g_strdup(value);
665 else if (g_strcasecmp("PATH", name) == 0)
666 pin->path = g_strdup(value);
667 else if (g_strcasecmp("LC_TYPE", name) == 0)
668 pin->lcctype = g_strdup(value);
669 else if (g_strcasecmp("LC_MESSAGES", name) == 0)
670 pin->lcmessages = g_strdup(value);
673 fclose(fp);
676 reset_pin_defaults(pin);
679 int pinentry_iterate(struct client_s *cl, gboolean read_ready)
681 gpg_error_t rc;
683 MUTEX_LOCK(&cl->pinentry->status_mutex);
685 /* Set from pinentry_timeout_thread(). */
686 if (cl->pinentry->status == PINENTRY_TIMEOUT) {
687 cl->pinentry->status = PINENTRY_NONE;
688 rc = send_error(cl->ctx, GPG_ERR_TIMEOUT);
689 cleanup_client(cl);
690 reset(cl->pinentry);
691 unlock_pin_mutex(cl->pinentry);
692 MUTEX_UNLOCK(&cl->pinentry->status_mutex);
695 if (cl->pinentry->status == PINENTRY_RUNNING) {
696 if (read_ready) {
697 guchar *shakey;
698 pinentry_key_s pk;
699 gsize len;
701 memset(&pk, 0, sizeof(pk));
702 len = pth_read(cl->pinentry->fd, &pk, sizeof(pk));
704 if (len == sizeof(pk)) {
705 if (pk.error) {
706 if (cl->pinentry->status == PINENTRY_TIMEOUT)
707 pk.error = GPG_ERR_TIMEOUT;
709 rc = send_error(cl->ctx, pk.error);
711 else if (pk.status == PINENTRY_PID) {
712 gint n;
715 * Start the timeout thread for the pinentry process
716 * now that we know the pid of it.
718 pth_attr_t attr = pth_attr_new();
719 pth_attr_init(attr);
720 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
721 cl->pinentry->pin_pid = pk.what.pid;
722 cl->pinentry->tid = pth_spawn(attr, timeout_thread,
723 cl->pinentry);
724 n = errno;
725 pth_attr_destroy(attr);
727 if (!cl->pinentry->tid) {
728 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__,
729 _gpg_strerror(gpg_error_from_errno(n)));
730 pk.error = gpg_error_from_errno(n);
733 else {
734 if (cl->pinentry->tid) {
735 cl->pinentry->status = PINENTRY_NONE;
736 pth_cond_notify(&cl->pinentry->cond, FALSE);
739 shakey = gcry_malloc(gcrykeysize);
741 if (!shakey)
742 pk.error = gpg_error_from_errno(ENOMEM);
743 else {
744 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey,
745 pk.what.key,
746 strlen(pk.what.key) == 0 ? 1 : strlen(pk.what.key));
747 rc = cl->pinentry->cb(cl->ctx, shakey, FALSE);
751 else if (len == -1) {
752 if (cl->pinentry->status == PINENTRY_TIMEOUT)
753 pk.error = GPG_ERR_TIMEOUT;
755 pk.error = gpg_err_code_from_syserror();
756 log_write("%s", _gpg_strerror(pk.error));
758 else if (len == 0) {
759 if (cl->pinentry->status == PINENTRY_TIMEOUT)
760 pk.error = GPG_ERR_TIMEOUT;
762 pk.error = GPG_ERR_EOF;
763 log_write("%s", _gpg_strerror(pk.error));
765 else
766 log_write(N_("read(): short byte count"));
768 if (pk.error) {
769 if (cl->pinentry->tid) {
770 cl->pinentry->status = PINENTRY_NONE;
771 pth_cond_notify(&cl->pinentry->cond, FALSE);
774 if (cl->pinentry->which == PINENTRY_OPEN)
775 cleanup_client(cl);
778 if (pk.error || pk.status == PINENTRY_RUNNING) {
779 reset(cl->pinentry);
780 unlock_file_mutex(cl);
781 unlock_pin_mutex(cl->pinentry);
784 memset(&pk, 0, sizeof(pk));
788 MUTEX_UNLOCK(&cl->pinentry->status_mutex);
789 return 0;
792 struct pinentry_s *pinentry_init()
794 struct pinentry_s *pin = g_malloc0(sizeof(struct pinentry_s));
796 if (!pin)
797 return NULL;
799 pth_mutex_init(&pin->status_mutex);
800 pth_mutex_init(&pin->cond_mutex);
801 pth_cond_init(&pin->cond);
802 set_pinentry_defaults(pin);
803 return pin;