Changed how "GETCONFIG ITERATIONS" works. If there is a file specified,
[pwmd.git] / src / pinentry.c
blobec56691ef443cf6c1e71f112b7805193a3b12a7a
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 int 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 int 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, "it's WAY too short"))
86 score = 10;
87 else if (!strcmp(tmp, "it is too short"))
88 score = 20;
89 else if (!strcmp(tmp, "it is all whitespace"))
90 score = 25;
91 else if (!strcmp(tmp, "it is based on your username"))
92 score = 30;
93 else if (!strcmp(tmp, "it is based on a dictionary word"))
94 score = 40;
95 else if (!strcmp(tmp, "it is based upon your password entry"))
96 score = 50;
97 else if (!strcmp(tmp, "it's derived from your password entry"))
98 score = 50;
99 else if (!strcmp(tmp, "it is based on a (reversed) dictionary word"))
100 score = 60;
101 else if (!strcmp(tmp, "it is derivable from your password entry"))
102 score = 70;
103 else if (!strcmp(tmp, "it does not contain enough DIFFERENT characters"))
104 score = 80;
105 else if (!strcmp(tmp, "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;
197 *p++ = "pinentry";
199 if (pin->display) {
200 *p++ = "--display";
201 *p++ = pin->display;
204 if (pin->lcctype) {
205 *p++ = "--lc-ctype";
206 *p++ = pin->lcctype;
209 if (pin->lcmessages) {
210 *p++ = "--lc-messages";
211 *p++ = pin->lcmessages;
214 *p = NULL;
215 rc = assuan_pipe_connect(&ctx, pin->path ? pin->path : PINENTRY_PATH,
216 argv, child_list);
218 if (rc)
219 return rc;
221 pin->pid = assuan_get_pid(ctx);
222 pin->ctx = ctx;
223 rc = set_pinentry_options(pin);
224 return rc ? rc : set_pinentry_strings(pin, 0);
227 static gpg_error_t pinentry_command(struct pinentry_s *pin, gchar **result,
228 const gchar *cmd)
230 gpg_error_t rc = 0;
232 if (!pin->ctx)
233 rc = launch_pinentry(pin);
235 return rc ? rc : assuan_command(pin, result, cmd);
238 static gpg_error_t set_pinentry_strings(struct pinentry_s *pin, int which)
240 char *buf;
241 gpg_error_t rc;
242 gchar *title = NULL;
244 #ifdef WITH_QUALITY
245 if (pin->which == PINENTRY_SAVE && which != 2) {
246 rc = pinentry_command(pin, NULL, "SETQUALITYBAR");
248 if (rc)
249 goto done;
251 pin->inquire_cb = quality_cb;
252 pin->inquire_data = pin;
254 #endif
256 if (which == 1)
257 title = g_strdup(N_("Passphrase mismatch, please try again."));
258 else if (!pin->title)
259 title = pin->title = g_strdup_printf(N_("Password Manager Daemon%s%s"),
260 pin->name ? ": " : "", pin->name ? pin->name : "");
261 else
262 title = pin->title;
264 if (!pin->prompt)
265 pin->prompt = g_strdup(N_("Passphrase:"));
267 if (!pin->desc && !which)
268 pin->desc = g_strdup_printf(pin->which == PINENTRY_OPEN ?
269 N_("A passphrase is required to open the file \"%s\". Please%%0Aenter the passphrase below.") :
270 N_("A passphrase is required to save to the file \"%s\". Please%%0Aenter the passphrase below."),
271 pin->filename);
273 if (which == 2)
274 buf = g_strdup_printf("SETERROR %s", N_("Please enter the passphrase again for confirmation."));
275 else
276 buf = g_strdup_printf("SETERROR %s", pin->desc);
278 rc = pinentry_command(pin, NULL, buf);
279 g_free(buf);
281 if (rc)
282 goto done;
284 buf = g_strdup_printf("SETPROMPT %s", pin->prompt);
285 rc = pinentry_command(pin, NULL, buf);
286 g_free(buf);
288 if (rc)
289 goto done;
291 buf = g_strdup_printf("SETDESC %s", title);
292 rc = pinentry_command(pin, NULL, buf);
293 g_free(buf);
295 done:
296 if (which == 1)
297 g_free(title);
299 return rc;
302 static void pinentry_disconnect(struct pinentry_s *pin)
304 if (!pin)
305 return;
307 if (pin->ctx)
308 assuan_disconnect(pin->ctx);
310 pin->ctx = NULL;
311 pin->pid = 0;
314 static gpg_error_t do_getpin(struct pinentry_s *pin, char **result)
316 gpg_error_t rc;
318 *result = NULL;
319 rc = pinentry_command(pin, result, "GETPIN");
321 if (!*result)
322 *result = xstrdup("");
324 return rc;
327 gpg_error_t pinentry_getpin(struct pinentry_s *pin, gchar **result)
329 gint which = 0;
330 gpg_error_t rc = set_pinentry_strings(pin, which);
331 gchar *result1 = NULL;
333 if (rc)
334 goto done;
336 again:
337 rc = do_getpin(pin, result);
339 if (rc)
340 goto done;
342 if (pin->which == PINENTRY_SAVE) {
343 if (!result1) {
344 rc = set_pinentry_strings(pin, 2);
346 if (rc)
347 goto done;
349 result1 = g_strdup(*result);
350 goto again;
353 if (strcmp(result1, *result)) {
354 g_free(result1);
355 xfree(*result);
356 result1 = *result = NULL;
357 rc = set_pinentry_strings(pin, 1);
359 if (rc)
360 goto done;
362 goto again;
366 done:
367 g_free(result1);
368 pinentry_disconnect(pin);
369 return rc;
372 static int write_result(int fd, pinentry_key_s *pk, char *result)
374 size_t len;
376 if (pk->error) {
378 * libassuan handles GPG_ERR_EOF in assuan_process_done() and
379 * will disconnect the client even if the error isn't related
380 * to it. Use GPG_ERR_CANCELED instead.
382 if (gpg_err_code(pk->error) == GPG_ERR_EOF)
383 pk->error = GPG_ERR_CANCELED;
385 len = pth_write(fd, pk, sizeof(pinentry_key_s));
386 close(fd);
388 if (len != sizeof(pinentry_key_s))
389 log_write("%s(%i): write: len != sizeof(pk)", __FUNCTION__, __LINE__);
391 return 1;
394 if (pk->status == PINENTRY_PID)
395 pk->what.pid = atoi(result);
396 else
397 g_strlcpy(pk->what.key, result, sizeof(pk->what.key));
399 xfree(result);
400 len = pth_write(fd, pk, sizeof(pinentry_key_s));
402 if (len != sizeof(pinentry_key_s)) {
403 memset(pk, 0, sizeof(pinentry_key_s));
404 log_write("%s(%i): write: len != sizeof(pk)", __FUNCTION__, __LINE__);
405 close(fd);
406 return 1;
409 if (pk->status != PINENTRY_PID)
410 close(fd);
412 memset(pk, 0, sizeof(pinentry_key_s));
413 return 0;
416 static void reset(struct pinentry_s *pin)
418 int status;
420 if (pin->pid)
421 waitpid(pin->pid, &status, 0);
423 if (pin->fd != -1)
424 close(pin->fd);
426 pin->fd = -1;
427 pin->pid = pin->pin_pid = 0;
428 pin->tid = 0;
429 pin->status = PINENTRY_NONE;
432 /* pin->status_mutex should be locked before calling this function. */
433 static void kill_pinentry(struct pinentry_s *pin)
435 if (pin->pin_pid == 0)
436 return;
438 if (kill(pin->pin_pid, 0) == 0)
439 if (kill(pin->pin_pid, SIGTERM) == 0)
440 if (kill(pin->pin_pid, 0) == 0)
441 kill(pin->pin_pid, SIGKILL);
443 pin->pin_pid = 0;
446 static void timeout_cleanup(void *arg)
448 pth_event_t ev = arg;
450 pth_event_free(ev, PTH_FREE_ALL);
453 static void *timeout_thread(void *arg)
455 struct pinentry_s *pin = arg;
456 pth_event_t ev;
457 pth_attr_t attr = pth_attr_of(pth_self());
459 pth_attr_set(attr, PTH_ATTR_NAME, __FUNCTION__);
460 pth_attr_destroy(attr);
461 ev = pth_event(PTH_EVENT_TIME, pth_timeout(pin->timeout, 0));
462 MUTEX_LOCK(&pin->cond_mutex);
463 pth_cleanup_push(timeout_cleanup, ev);
464 pth_cond_await(&pin->cond, &pin->cond_mutex, ev);
465 pth_cleanup_pop(1);
467 /* pth_cond_notify() was called from pinentry_iterate() (we have a
468 * key). */
469 if (pin->status == PINENTRY_NONE) {
470 MUTEX_UNLOCK(&pin->cond_mutex);
471 pth_exit(PTH_CANCELED);
472 return NULL;
475 MUTEX_LOCK(&pin->status_mutex);
476 kill_pinentry(pin);
477 pin->status = PINENTRY_TIMEOUT;
478 MUTEX_UNLOCK(&pin->cond_mutex);
479 MUTEX_UNLOCK(&pin->status_mutex);
480 pth_exit(PTH_CANCELED);
481 return NULL;
484 gpg_error_t pinentry_fork(assuan_context_t ctx)
486 struct client_s *client = assuan_get_pointer(ctx);
487 struct pinentry_s *pin = client->pinentry;
488 gpg_error_t rc;
489 gint p[2];
490 pid_t pid;
491 pinentry_key_s pk;
492 gchar *result = NULL;
494 if (pipe(p) == -1)
495 return gpg_error_from_syserror();
497 pid = pth_fork();
499 switch (pid) {
500 case -1:
501 rc = gpg_error_from_syserror();
502 close(p[0]);
503 close(p[1]);
504 return rc;
505 case 0:
506 close(p[0]);
507 /* FIXME segfaults in libpth at pth_ring_append() (xmalloc).
508 this is probably only a symptom of another problem. */
509 //free_client_list();
511 if (pin->timeout > 0 && pin->which == PINENTRY_OPEN) {
513 * Send the pid of the pinentry process back to pwmd so it can
514 * handle the pinentry timeout properly.
516 pk.status = PINENTRY_PID;
517 pk.error = pinentry_command(pin, &result, "GETINFO pid");
519 if (write_result(p[1], &pk, result))
520 _exit(EXIT_FAILURE);
523 pk.status = PINENTRY_RUNNING;
524 pk.error = pinentry_getpin(pin, &result);
526 if (write_result(p[1], &pk, result))
527 _exit(EXIT_FAILURE);
529 _exit(EXIT_SUCCESS);
530 default:
531 close(p[1]);
532 client->pinentry->fd = p[0];
533 client->pinentry->pid = pid;
534 client->pinentry->status = PINENTRY_INIT;
535 break;
539 * Don't call assuan_process_done() here. That should be done in
540 * the callback function which is called after the key has been read()
541 * in pinentry_iterate().
543 return 0;
546 gpg_error_t lock_pin_mutex(struct client_s *client)
548 gpg_error_t rc = 0;
550 MUTEX_TRYLOCK(client->ctx, &pin_mutex, rc);
552 if (!rc)
553 client->pinentry->has_lock = TRUE;
555 return rc;
558 void unlock_pin_mutex(struct pinentry_s *pin)
560 if (pin->has_lock == FALSE)
561 return;
563 MUTEX_UNLOCK(&pin_mutex);
564 pin->has_lock = FALSE;
567 void cleanup_pinentry(struct pinentry_s *pin)
569 if (!pin)
570 return;
572 if (pin->ctx && pin->pid)
573 pinentry_disconnect(pin);
575 if (!pth_mutex_acquire(&pin->status_mutex, TRUE, NULL) && errno == EBUSY) {
576 MUTEX_UNLOCK(&pin->status_mutex);
578 else
579 pth_mutex_release(&pin->status_mutex);
581 MUTEX_LOCK(&pin->status_mutex);
582 kill_pinentry(pin);
583 MUTEX_UNLOCK(&pin->status_mutex);
584 unlock_pin_mutex(pin);
586 if (!pth_mutex_acquire(&pin->cond_mutex, TRUE, NULL) && errno == EBUSY) {
587 MUTEX_UNLOCK(&pin->cond_mutex);
589 else
590 pth_mutex_release(&pin->cond_mutex);
592 if (pin->name)
593 g_free(pin->name);
595 g_free(pin->ttyname);
596 g_free(pin->ttytype);
597 g_free(pin->desc);
598 g_free(pin->title);
599 g_free(pin->prompt);
600 g_free(pin->path);
601 g_free(pin->display);
602 g_free(pin->filename);
603 g_free(pin->lcctype);
604 g_free(pin->lcmessages);
605 g_free(pin);
608 void set_pinentry_defaults(struct pinentry_s *pin)
610 FILE *fp;
611 gchar buf[PATH_MAX];
612 gchar *p;
614 pin->enable = -1;
615 g_snprintf(buf, sizeof(buf), "%s/.pwmd/pinentry.conf", g_get_home_dir());
616 fp = fopen(buf, "r");
618 if (fp) {
619 while ((p = fgets(buf, sizeof(buf), fp)) != NULL) {
620 gchar name[32] = {0}, value[256] = {0};
622 if (*p == '#')
623 continue;
625 if (p[strlen(p)-1] == '\n')
626 p[strlen(p)-1] = 0;
628 if (sscanf(p, " %31[a-zA-Z] = %255s", name, value) != 2)
629 continue;
631 if (g_strcasecmp("TTYNAME", name) == 0)
632 pin->ttyname = g_strdup(value);
633 else if (g_strcasecmp("TTYTYPE", name) == 0)
634 pin->ttytype = g_strdup(value);
635 else if (g_strcasecmp("DISPLAY", name) == 0)
636 pin->display = g_strdup(value);
637 else if (g_strcasecmp("PATH", name) == 0)
638 pin->path = g_strdup(value);
639 else if (g_strcasecmp("LC_TYPE", name) == 0)
640 pin->lcctype = g_strdup(value);
641 else if (g_strcasecmp("LC_MESSAGES", name) == 0)
642 pin->lcmessages = g_strdup(value);
645 fclose(fp);
648 pin->timeout = get_key_file_integer("global", "pinentry_timeout");
651 int pinentry_iterate(struct client_s *cl, gboolean read_ready)
653 gpg_error_t rc;
655 MUTEX_LOCK(&cl->pinentry->status_mutex);
657 /* Set from pinentry_timeout_thread(). */
658 if (cl->pinentry->status == PINENTRY_TIMEOUT) {
659 cl->pinentry->status = PINENTRY_NONE;
660 rc = send_error(cl->ctx, GPG_ERR_TIMEOUT);
661 cleanup_client(cl);
662 reset(cl->pinentry);
663 unlock_pin_mutex(cl->pinentry);
664 MUTEX_UNLOCK(&cl->pinentry->status_mutex);
667 if (cl->pinentry->status == PINENTRY_RUNNING) {
668 if (read_ready) {
669 guchar *shakey;
670 pinentry_key_s pk;
671 gsize len;
673 memset(&pk, 0, sizeof(pk));
674 len = pth_read(cl->pinentry->fd, &pk, sizeof(pk));
675 pth_cancel_point();
677 if (len == sizeof(pk)) {
678 if (pk.error) {
679 if (cl->pinentry->status == PINENTRY_TIMEOUT)
680 pk.error = GPG_ERR_TIMEOUT;
682 rc = send_error(cl->ctx, pk.error);
684 else if (pk.status == PINENTRY_PID) {
685 gint n;
688 * Start the timeout thread for the pinentry process
689 * now that we know the pid of it.
691 pth_attr_t attr = pth_attr_new();
692 pth_attr_init(attr);
693 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
694 cl->pinentry->pin_pid = pk.what.pid;
695 cl->pinentry->tid = pth_spawn(attr, timeout_thread,
696 cl->pinentry);
697 n = errno;
698 pth_attr_destroy(attr);
700 if (!cl->pinentry->tid) {
701 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__,
702 _gpg_strerror(gpg_error_from_errno(n)));
703 pk.error = gpg_error_from_errno(n);
706 else {
707 if (cl->pinentry->tid) {
708 cl->pinentry->status = PINENTRY_NONE;
709 pth_cond_notify(&cl->pinentry->cond, FALSE);
712 shakey = gcry_malloc(gcrykeysize);
714 if (!shakey)
715 pk.error = gpg_error_from_errno(ENOMEM);
716 else {
717 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey,
718 pk.what.key,
719 strlen(pk.what.key) == 0 ? 1 : strlen(pk.what.key));
720 rc = cl->pinentry->cb(cl->ctx, shakey, FALSE);
724 else if (len == -1) {
725 if (cl->pinentry->status == PINENTRY_TIMEOUT)
726 pk.error = GPG_ERR_TIMEOUT;
728 pk.error = gpg_err_code_from_syserror();
729 log_write("%s", _gpg_strerror(pk.error));
731 else if (len == 0) {
732 if (cl->pinentry->status == PINENTRY_TIMEOUT)
733 pk.error = GPG_ERR_TIMEOUT;
735 pk.error = GPG_ERR_EOF;
736 log_write("%s", _gpg_strerror(pk.error));
738 else
739 log_write(N_("read(): short byte count"));
741 if (pk.error) {
742 if (cl->pinentry->tid) {
743 cl->pinentry->status = PINENTRY_NONE;
744 pth_cond_notify(&cl->pinentry->cond, FALSE);
747 if (cl->pinentry->which == PINENTRY_OPEN)
748 cleanup_client(cl);
751 if (pk.error || pk.status == PINENTRY_RUNNING) {
752 reset(cl->pinentry);
753 unlock_file_mutex(cl);
754 unlock_pin_mutex(cl->pinentry);
757 memset(&pk, 0, sizeof(pk));
761 MUTEX_UNLOCK(&cl->pinentry->status_mutex);
762 return 0;
765 struct pinentry_s *pinentry_init()
767 struct pinentry_s *pin = g_malloc0(sizeof(struct pinentry_s));
769 if (!pin)
770 return NULL;
772 pth_mutex_init(&pin->status_mutex);
773 pth_mutex_init(&pin->cond_mutex);
774 pth_cond_init(&pin->cond);
775 set_pinentry_defaults(pin);
776 return pin;