Use thread-safe libgcrypt and libgpg-error functions. Only call the new
[pwmd.git] / src / pinentry.c
blobadde24bd722667b3223ef95447ec80531b583e49
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 #endif
39 #include "mem.h"
40 #include "common.h"
41 #include "commands.h"
42 #include "pinentry.h"
43 #include "misc.h"
44 #include "pwmd_error.h"
46 void free_client_list();
47 static gpg_error_t set_pinentry_strings(struct pinentry_s *pin, int which);
49 static int mem_realloc_cb(void *data, const void *buffer, size_t len)
51 membuf_t *mem = (membuf_t *)data;
52 void *p;
54 if (!buffer)
55 return 0;
57 if ((p = xrealloc(mem->buf, mem->len + len)) == NULL)
58 return 1;
60 mem->buf = p;
61 memcpy((char *)mem->buf + mem->len, buffer, len);
62 mem->len += len;
63 return 0;
66 #ifdef WITH_QUALITY
67 static int quality_cb(void *data, const char *line)
69 struct pinentry_s *pin = data;
70 const gchar *tmp;
71 gint score = 0;
72 gchar buf[5];
74 if (strncmp(line, "QUALITY ", 8) != 0)
75 return GPG_ERR_INV_ARG;
77 if (!(tmp = FascistCheck(line+8, CRACKLIB_DICT)))
78 return assuan_send_data(pin->ctx, "100", 3);
80 if (!strcmp(tmp, "it's WAY too short"))
81 score = 10;
82 else if (!strcmp(tmp, "it is too short"))
83 score = 20;
84 else if (!strcmp(tmp, "it is all whitespace"))
85 score = 25;
86 else if (!strcmp(tmp, "it is based on your username"))
87 score = 30;
88 else if (!strcmp(tmp, "it is based on a dictionary word"))
89 score = 40;
90 else if (!strcmp(tmp, "it is based upon your password entry"))
91 score = 50;
92 else if (!strcmp(tmp, "it's derived from your password entry"))
93 score = 50;
94 else if (!strcmp(tmp, "it is based on a (reversed) dictionary word"))
95 score = 60;
96 else if (!strcmp(tmp, "it is derivable from your password entry"))
97 score = 70;
98 else if (!strcmp(tmp, "it does not contain enough DIFFERENT characters"))
99 score = 80;
100 else if (!strcmp(tmp, "it is too simplistic/systematic"))
101 score = 90;
102 else
103 score = 0;
105 tmp = (const gchar *)print_fmt(buf, sizeof(buf), "%i", score);
106 return assuan_send_data(pin->ctx, tmp, strlen(tmp));
108 #endif
110 static gpg_error_t assuan_command(struct pinentry_s *pin, gchar **result,
111 const gchar *cmd)
113 gpg_error_t rc;
115 pin->data.len = 0;
116 pin->data.buf = NULL;
118 rc = assuan_transact(pin->ctx, cmd, mem_realloc_cb, &pin->data,
119 pin->inquire_cb, pin->inquire_data, NULL, NULL);
121 if (rc) {
122 if (pin->data.buf) {
123 xfree(pin->data.buf);
124 pin->data.buf = NULL;
127 else {
128 if (pin->data.buf) {
129 mem_realloc_cb(&pin->data, "", 1);
130 *result = (gchar *)pin->data.buf;
134 return rc;
137 static gpg_error_t set_pinentry_options(struct pinentry_s *pin)
139 gchar *display = getenv("DISPLAY");
140 gint have_display = 0;
141 gchar *tty = NULL, *ttytype = NULL;
142 gchar *opt, *val;
143 gpg_error_t rc;
144 gchar *result = NULL;
145 gchar cmd[ASSUAN_LINELENGTH];
147 if (pin->display || display)
148 have_display = 1;
149 else {
150 tty = pin->ttyname ? pin->ttyname : ttyname(STDOUT_FILENO);
152 if (!tty)
153 return GPG_ERR_CANCELED;
156 if (!have_display && !tty)
157 return GPG_ERR_CANCELED;
159 if (!have_display) {
160 gchar *p = getenv("TERM");
162 ttytype = pin->ttytype ? pin->ttytype : p;
164 if (!ttytype)
165 return GPG_ERR_CANCELED;
168 opt = have_display ? "DISPLAY" : "TTYNAME";
169 val = have_display ? pin->display ? pin->display : display : tty;
170 g_snprintf(cmd, sizeof(cmd), "OPTION %s=%s", g_ascii_strdown(opt, strlen(opt)), val);
171 rc = assuan_command(pin, &result, cmd);
173 if (rc)
174 return rc;
176 if (!have_display) {
177 g_snprintf(cmd, sizeof(cmd), "OPTION ttytype=%s", ttytype);
178 rc = assuan_command(pin, &result, cmd);
181 return rc;
184 static gpg_error_t launch_pinentry(struct pinentry_s *pin)
186 gpg_error_t rc;
187 assuan_context_t ctx;
188 gint child_list[] = {-1};
189 const gchar *argv[8];
190 const gchar **p = argv;
192 *p++ = "pinentry";
194 if (pin->display) {
195 *p++ = "--display";
196 *p++ = pin->display;
199 if (pin->lcctype) {
200 *p++ = "--lc-ctype";
201 *p++ = pin->lcctype;
204 if (pin->lcmessages) {
205 *p++ = "--lc-messages";
206 *p++ = pin->lcmessages;
209 *p = NULL;
210 rc = assuan_pipe_connect(&ctx, pin->path ? pin->path : PINENTRY_PATH,
211 argv, child_list);
213 if (rc)
214 return rc;
216 pin->pid = assuan_get_pid(ctx);
217 pin->ctx = ctx;
218 rc = set_pinentry_options(pin);
219 return rc ? rc : set_pinentry_strings(pin, 0);
222 static gpg_error_t pinentry_command(struct pinentry_s *pin, gchar **result,
223 const gchar *cmd)
225 gpg_error_t rc = 0;
227 if (!pin->ctx)
228 rc = launch_pinentry(pin);
230 return rc ? rc : assuan_command(pin, result, cmd);
233 static gpg_error_t set_pinentry_strings(struct pinentry_s *pin, int which)
235 char *buf;
236 gpg_error_t rc;
237 gchar *title = NULL;
239 #ifdef WITH_QUALITY
240 if (pin->which == PINENTRY_SAVE && which != 2) {
241 rc = pinentry_command(pin, NULL, "SETQUALITYBAR");
243 if (rc)
244 goto done;
246 pin->inquire_cb = quality_cb;
247 pin->inquire_data = pin;
249 #endif
251 if (which == 1)
252 title = g_strdup(N_("Passphrase mismatch, please try again."));
253 else if (!pin->title)
254 title = pin->title = g_strdup(N_("Password Manager Daemon"));
255 else
256 title = pin->title;
258 if (!pin->prompt)
259 pin->prompt = g_strdup(N_("Passphrase:"));
261 if (!pin->desc && !which)
262 pin->desc = g_strdup_printf(pin->which == PINENTRY_OPEN ?
263 N_("A passphrase is required to open the file \"%s\". Please%%0Aenter the passphrase below.") :
264 N_("A passphrase is required to save to the file \"%s\". Please%%0Aenter a passphrase below."),
265 pin->filename);
267 if (which == 2)
268 buf = g_strdup_printf("SETERROR %s", N_("Please type the passphrase again for confirmation."));
269 else
270 buf = g_strdup_printf("SETERROR %s", pin->desc);
272 rc = pinentry_command(pin, NULL, buf);
273 g_free(buf);
275 if (rc)
276 goto done;
278 buf = g_strdup_printf("SETPROMPT %s", pin->prompt);
279 rc = pinentry_command(pin, NULL, buf);
280 g_free(buf);
282 if (rc)
283 goto done;
285 buf = g_strdup_printf("SETDESC %s", title);
286 rc = pinentry_command(pin, NULL, buf);
287 g_free(buf);
289 done:
290 if (which == 1)
291 g_free(title);
293 return rc;
296 static void pinentry_disconnect(struct pinentry_s *pin)
298 if (!pin)
299 return;
301 if (pin->ctx)
302 assuan_disconnect(pin->ctx);
304 pin->ctx = NULL;
305 pin->pid = 0;
308 static gpg_error_t do_getpin(struct pinentry_s *pin, char **result)
310 gpg_error_t rc;
312 *result = NULL;
313 rc = pinentry_command(pin, result, "GETPIN");
315 if (!*result)
316 *result = xstrdup("");
318 return rc;
321 gpg_error_t pinentry_getpin(struct pinentry_s *pin, gchar **result)
323 gint which = 0;
324 gpg_error_t rc = set_pinentry_strings(pin, which);
325 gchar *result1 = NULL;
327 if (rc)
328 goto done;
330 again:
331 rc = do_getpin(pin, result);
333 if (rc)
334 goto done;
336 if (pin->which == PINENTRY_SAVE) {
337 if (!result1) {
338 rc = set_pinentry_strings(pin, 2);
340 if (rc)
341 goto done;
343 result1 = g_strdup(*result);
344 goto again;
347 if (strcmp(result1, *result)) {
348 g_free(result1);
349 xfree(*result);
350 result1 = *result = NULL;
351 rc = set_pinentry_strings(pin, 1);
353 if (rc)
354 goto done;
356 goto again;
360 done:
361 g_free(result1);
362 pinentry_disconnect(pin);
363 return rc;
366 static int write_result(int fd, pinentry_key_s *pk, char *result)
368 size_t len;
370 if (pk->error) {
372 * libassuan handles GPG_ERR_EOF in assuan_process_done() and
373 * will disconnect the client even if the error isn't related
374 * to it. Use GPG_ERR_CANCELED instead.
376 if (gpg_err_code(pk->error) == GPG_ERR_EOF)
377 pk->error = GPG_ERR_CANCELED;
379 len = pth_write(fd, pk, sizeof(pinentry_key_s));
380 close(fd);
382 if (len != sizeof(pinentry_key_s))
383 log_write("%s(%i): write: len != sizeof(pk)", __FUNCTION__, __LINE__);
385 return 1;
388 if (pk->status == PINENTRY_PID)
389 pk->what.pid = atoi(result);
390 else
391 g_strlcpy(pk->what.key, result, sizeof(pk->what.key));
393 xfree(result);
394 len = pth_write(fd, pk, sizeof(pinentry_key_s));
396 if (len != sizeof(pinentry_key_s)) {
397 memset(pk, 0, sizeof(pinentry_key_s));
398 log_write("%s(%i): write: len != sizeof(pk)", __FUNCTION__, __LINE__);
399 close(fd);
400 return 1;
403 if (pk->status != PINENTRY_PID)
404 close(fd);
406 memset(pk, 0, sizeof(pinentry_key_s));
407 return 0;
410 static void reset(struct pinentry_s *pin)
412 int status;
414 if (pin->pid)
415 pth_waitpid(pin->pid, &status, 0);
417 if (pin->fd != -1)
418 close(pin->fd);
420 pin->fd = -1;
421 pin->pid = pin->pin_pid = 0;
422 pin->tid = NULL;
424 if (pin->ev) {
425 pth_event_isolate(pin->ev);
426 pth_event_free(pin->ev, PTH_FREE_THIS);
429 pin->ev = NULL;
430 pin->status = PINENTRY_NONE;
433 static void *timeout_thread(void *arg)
435 struct pinentry_s *pin = arg;
436 pth_event_t ev = pth_event(PTH_EVENT_TIME, pth_timeout(pin->timeout, 0));
438 pth_wait(ev);
439 pth_event_free(ev, PTH_FREE_THIS);
440 pth_mutex_acquire(&pin->status_mutex, FALSE, NULL);
442 /* pth_cancel() was called from pinentry_iterate() (we have a key).
443 * pth_wait() was the cancelation point. */
444 if (pin->status == PINENTRY_NONE) {
445 pth_mutex_release(&pin->status_mutex);
446 pth_exit(PTH_CANCELED);
447 return NULL;
450 if (kill(pin->pin_pid, 0) == 0)
451 if (kill(pin->pin_pid, SIGTERM) == 0)
452 if (kill(pin->pin_pid, 0) == 0)
453 kill(pin->pin_pid, SIGKILL);
455 pin->status = PINENTRY_TIMEOUT;
456 pth_mutex_release(&pin->status_mutex);
457 pth_exit(PTH_CANCELED);
458 return NULL;
461 gpg_error_t pinentry_fork(assuan_context_t ctx)
463 struct client_s *client = assuan_get_pointer(ctx);
464 struct pinentry_s *pin = client->pinentry;
465 gpg_error_t rc;
466 gint p[2];
467 pid_t pid;
468 pinentry_key_s pk;
469 gchar *result = NULL;
471 if (pipe(p) == -1)
472 return gpg_error_from_syserror();
474 pid = pth_fork();
476 switch (pid) {
477 case -1:
478 rc = gpg_error_from_syserror();
479 close(p[0]);
480 close(p[1]);
481 return rc;
482 case 0:
483 close(p[0]);
484 free_client_list();
486 if (pin->timeout > 0 && client->pinentry->which == PINENTRY_OPEN) {
488 * Send the pid of the pinentry process back to pwmd so it can
489 * handle the pinentry timeout properly.
491 pk.status = PINENTRY_PID;
492 pk.error = pinentry_command(pin, &result, "GETINFO pid");
494 if (write_result(p[1], &pk, result))
495 _exit(EXIT_FAILURE);
498 pk.status = PINENTRY_RUNNING;
499 pk.error = pinentry_getpin(pin, &result);
501 if (write_result(p[1], &pk, result))
502 _exit(EXIT_FAILURE);
504 _exit(EXIT_SUCCESS);
505 default:
506 close(p[1]);
507 client->pinentry->fd = p[0];
508 client->pinentry->pid = pid;
509 client->pinentry->status = PINENTRY_INIT;
510 break;
514 * Don't call assuan_process_done() here. That should be done in
515 * open_command_finalize() after the key has been read().
517 return 0;
520 gpg_error_t lock_pin_mutex(struct client_s *client)
522 while (pth_mutex_acquire(&pin_mutex, TRUE, NULL) == FALSE) {
523 if (client->ctx) {
524 gpg_error_t rc = send_status(client->ctx, STATUS_LOCKED);
526 if (rc)
527 return rc;
530 pth_sleep(1);
533 client->pinentry->has_lock = TRUE;
534 return 0;
537 void unlock_pin_mutex(struct pinentry_s *pin)
539 if (pin->has_lock == FALSE)
540 return;
542 pth_mutex_release(&pin_mutex);
543 pin->has_lock = FALSE;
546 void cleanup_pinentry(struct pinentry_s *pin)
548 if (!pin)
549 return;
551 unlock_pin_mutex(pin);
553 if (pin->ctx && pin->pid)
554 pinentry_disconnect(pin);
556 g_free(pin->ttyname);
557 g_free(pin->ttytype);
558 g_free(pin->desc);
559 g_free(pin->title);
560 g_free(pin->prompt);
561 g_free(pin->path);
562 g_free(pin->display);
563 g_free(pin->filename);
564 g_free(pin->lcctype);
565 g_free(pin->lcmessages);
566 g_free(pin);
569 void set_pinentry_defaults(struct pinentry_s *pin)
571 FILE *fp;
572 gchar buf[PATH_MAX];
573 struct passwd *pw = getpwuid(getuid());
574 gchar *p;
576 pin->enable = -1;
577 g_snprintf(buf, sizeof(buf), "%s/.pwmd/pinentry.conf", pw->pw_dir);
578 fp = fopen(buf, "r");
580 if (fp) {
581 while ((p = fgets(buf, sizeof(buf), fp)) != NULL) {
582 gchar name[32] = {0}, value[256] = {0};
584 if (*p == '#')
585 continue;
587 if (p[strlen(p)-1] == '\n')
588 p[strlen(p)-1] = 0;
590 if (sscanf(p, " %31[a-zA-Z] = %255s", name, value) != 2)
591 continue;
593 if (g_strcasecmp("TTYNAME", name) == 0)
594 pin->ttyname = g_strdup(value);
595 else if (g_strcasecmp("TTYTYPE", name) == 0)
596 pin->ttytype = g_strdup(value);
597 else if (g_strcasecmp("DISPLAY", name) == 0)
598 pin->display = g_strdup(value);
599 else if (g_strcasecmp("PATH", name) == 0)
600 pin->path = g_strdup(value);
601 else if (g_strcasecmp("LC_TYPE", name) == 0)
602 pin->lcctype = g_strdup(value);
603 else if (g_strcasecmp("LC_MESSAGES", name) == 0)
604 pin->lcmessages = g_strdup(value);
607 fclose(fp);
610 pin->timeout = get_key_file_integer("global", "pinentry_timeout");
613 pth_event_t pinentry_iterate(struct client_s *cl, pth_event_t ev)
615 gpg_error_t rc;
617 pth_mutex_acquire(&cl->pinentry->status_mutex, FALSE, NULL);
619 /* Set from pinentry_timeout_thread(). */
620 if (cl->pinentry->status == PINENTRY_TIMEOUT) {
621 cl->pinentry->status = PINENTRY_NONE;
622 rc = send_error(cl->ctx, GPG_ERR_TIMEOUT);
623 cleanup_client(cl);
624 reset(cl->pinentry);
625 unlock_pin_mutex(cl->pinentry);
628 if (cl->pinentry->status == PINENTRY_RUNNING) {
629 pth_event_isolate(cl->pinentry->ev);
631 if (pth_event_occurred(cl->pinentry->ev)) {
632 guchar shakey[gcrykeysize];
633 pinentry_key_s pk;
634 gsize len;
636 memset(&pk, 0, sizeof(pk));
637 len = pth_read(cl->pinentry->fd, &pk, sizeof(pk));
639 if (len == sizeof(pk)) {
640 if (pk.error) {
641 if (cl->pinentry->status == PINENTRY_TIMEOUT)
642 pk.error = GPG_ERR_TIMEOUT;
644 rc = send_error(cl->ctx, pk.error);
646 else if (pk.status == PINENTRY_PID) {
648 * Start the timeout thread for the pinentry process
649 * now that we know the pid of it.
651 pth_attr_t attr = pth_attr_new();
652 pth_attr_init(attr);
653 pth_attr_set(attr, PTH_ATTR_JOINABLE, 0);
654 pth_attr_set(attr, PTH_ATTR_CANCEL_STATE,
655 PTH_CANCEL_ASYNCHRONOUS);
656 cl->pinentry->pin_pid = pk.what.pid;
657 cl->pinentry->tid = pth_spawn(attr, timeout_thread,
658 cl->pinentry);
659 pth_attr_destroy(attr);
661 else {
662 if (cl->pinentry->tid) {
663 cl->pinentry->status = PINENTRY_NONE;
664 pth_cancel(cl->pinentry->tid);
667 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, pk.what.key,
668 strlen(pk.what.key) == 0 ? 1 : strlen(pk.what.key));
669 rc = cl->pinentry->cb(cl->ctx, shakey, FALSE);
670 memset(shakey, 0, sizeof(shakey));
673 else if (len == -1) {
674 if (cl->pinentry->status == PINENTRY_TIMEOUT)
675 pk.error = GPG_ERR_TIMEOUT;
677 pk.error = gpg_err_code_from_syserror();
678 log_write("%s", _gpg_strerror(pk.error));
680 else if (len == 0) {
681 if (cl->pinentry->status == PINENTRY_TIMEOUT)
682 pk.error = GPG_ERR_TIMEOUT;
684 pk.error = GPG_ERR_EOF;
685 log_write("%s", _gpg_strerror(pk.error));
687 else
688 log_write(N_("pth_read(): short byte count"));
690 if (pk.error) {
691 if (cl->pinentry->tid) {
692 cl->pinentry->status = PINENTRY_NONE;
693 pth_cancel(cl->pinentry->tid);
696 if (cl->pinentry->which == PINENTRY_OPEN)
697 cleanup_client(cl);
700 if (pk.error || pk.status == PINENTRY_RUNNING) {
701 reset(cl->pinentry);
702 unlock_file_mutex(cl);
703 unlock_pin_mutex(cl->pinentry);
706 memset(&pk, 0, sizeof(pk));
709 pth_event_concat(ev, cl->pinentry->ev, NULL);
712 pth_mutex_release(&cl->pinentry->status_mutex);
713 return ev;
716 struct pinentry_s *pinentry_init()
718 struct pinentry_s *pin = g_malloc0(sizeof(struct pinentry_s));
720 if (!pin)
721 return NULL;
723 pth_mutex_init(&pin->status_mutex);
724 set_pinentry_defaults(pin);
725 return pin;