If the client thread terminates while a pinentry is running, terminate
[pwmd.git] / src / pinentry.c
bloba5c2cdf0f266b1d37c25b41326ab19248568c853
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 <pthread.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[4];
196 argv[0] = "pinentry";
198 if (pin->display) {
199 argv[1] = "--display";
200 argv[2] = pin->display;
201 argv[3] = NULL;
203 else
204 argv[1] = NULL;
206 rc = assuan_pipe_connect(&ctx, pin->path ? pin->path : PINENTRY_PATH,
207 argv, child_list);
209 if (rc)
210 return rc;
212 pin->pid = assuan_get_pid(ctx);
213 pin->ctx = ctx;
214 rc = set_pinentry_options(pin);
215 return rc ? rc : set_pinentry_strings(pin, 0);
218 static gpg_error_t pinentry_command(struct pinentry_s *pin, gchar **result,
219 const gchar *cmd)
221 gpg_error_t rc = 0;
223 if (!pin->ctx)
224 rc = launch_pinentry(pin);
226 return rc ? rc : assuan_command(pin, result, cmd);
229 static gpg_error_t set_pinentry_strings(struct pinentry_s *pin, int which)
231 char *buf;
232 gpg_error_t rc;
233 gchar *title = NULL;
235 #ifdef WITH_QUALITY
236 if (pin->which == PINENTRY_SAVE && which != 2) {
237 rc = pinentry_command(pin, NULL, "SETQUALITYBAR");
239 if (rc)
240 goto done;
242 pin->inquire_cb = quality_cb;
243 pin->inquire_data = pin;
245 #endif
247 if (which == 1)
248 title = g_strdup(N_("Passphrase mismatch, please try again."));
249 else if (!pin->title)
250 title = pin->title = g_strdup(N_("Password Manager Daemon"));
251 else
252 title = pin->title;
254 if (!pin->prompt)
255 pin->prompt = g_strdup(N_("Passphrase:"));
257 if (!pin->desc && !which)
258 pin->desc = g_strdup_printf(pin->which == PINENTRY_OPEN ?
259 N_("A passphrase is required to open the file \"%s\". Please%%0Aenter the passphrase below.") :
260 N_("A passphrase is required to save to the file \"%s\". Please%%0Aenter the passphrase below."),
261 pin->filename);
263 if (which == 2)
264 buf = g_strdup_printf("SETERROR %s", N_("Please enter the passphrase again for confirmation."));
265 else
266 buf = g_strdup_printf("SETERROR %s", pin->desc);
268 rc = pinentry_command(pin, NULL, buf);
269 g_free(buf);
271 if (rc)
272 goto done;
274 buf = g_strdup_printf("SETPROMPT %s", pin->prompt);
275 rc = pinentry_command(pin, NULL, buf);
276 g_free(buf);
278 if (rc)
279 goto done;
281 buf = g_strdup_printf("SETDESC %s", title);
282 rc = pinentry_command(pin, NULL, buf);
283 g_free(buf);
285 done:
286 if (which == 1)
287 g_free(title);
289 return rc;
292 static void pinentry_disconnect(struct pinentry_s *pin)
294 if (!pin)
295 return;
297 if (pin->ctx)
298 assuan_disconnect(pin->ctx);
300 pin->ctx = NULL;
301 pin->pid = 0;
304 static gpg_error_t do_getpin(struct pinentry_s *pin, char **result)
306 gpg_error_t rc;
308 *result = NULL;
309 rc = pinentry_command(pin, result, "GETPIN");
311 if (!*result)
312 *result = xstrdup("");
314 return rc;
317 gpg_error_t pinentry_getpin(struct pinentry_s *pin, gchar **result)
319 gint which = 0;
320 gpg_error_t rc = set_pinentry_strings(pin, which);
321 gchar *result1 = NULL;
323 if (rc)
324 goto done;
326 again:
327 rc = do_getpin(pin, result);
329 if (rc)
330 goto done;
332 if (pin->which == PINENTRY_SAVE) {
333 if (!result1) {
334 rc = set_pinentry_strings(pin, 2);
336 if (rc)
337 goto done;
339 result1 = g_strdup(*result);
340 goto again;
343 if (strcmp(result1, *result)) {
344 g_free(result1);
345 xfree(*result);
346 result1 = *result = NULL;
347 rc = set_pinentry_strings(pin, 1);
349 if (rc)
350 goto done;
352 goto again;
356 done:
357 g_free(result1);
358 pinentry_disconnect(pin);
359 return rc;
362 static int write_result(int fd, pinentry_key_s *pk, char *result)
364 size_t len;
366 if (pk->error) {
368 * libassuan handles GPG_ERR_EOF in assuan_process_done() and
369 * will disconnect the client even if the error isn't related
370 * to it. Use GPG_ERR_CANCELED instead.
372 if (gpg_err_code(pk->error) == GPG_ERR_EOF)
373 pk->error = GPG_ERR_CANCELED;
375 len = write(fd, pk, sizeof(pinentry_key_s));
376 close(fd);
378 if (len != sizeof(pinentry_key_s))
379 log_write("%s(%i): write: len != sizeof(pk)", __FUNCTION__, __LINE__);
381 return 1;
384 if (pk->status == PINENTRY_PID)
385 pk->what.pid = atoi(result);
386 else
387 g_strlcpy(pk->what.key, result, sizeof(pk->what.key));
389 xfree(result);
390 len = write(fd, pk, sizeof(pinentry_key_s));
392 if (len != sizeof(pinentry_key_s)) {
393 memset(pk, 0, sizeof(pinentry_key_s));
394 log_write("%s(%i): write: len != sizeof(pk)", __FUNCTION__, __LINE__);
395 close(fd);
396 return 1;
399 if (pk->status != PINENTRY_PID)
400 close(fd);
402 memset(pk, 0, sizeof(pinentry_key_s));
403 return 0;
406 static void reset(struct pinentry_s *pin)
408 int status;
410 if (pin->pid)
411 waitpid(pin->pid, &status, 0);
413 if (pin->fd != -1)
414 close(pin->fd);
416 pin->fd = -1;
417 pin->pid = pin->pin_pid = 0;
418 pin->tid = 0;
419 pin->status = PINENTRY_NONE;
422 /* pin->status_mutex should be locked before calling this function. */
423 static void kill_pinentry(struct pinentry_s *pin)
425 if (pin->pin_pid == 0)
426 return;
428 if (kill(pin->pin_pid, 0) == 0)
429 if (kill(pin->pin_pid, SIGTERM) == 0)
430 if (kill(pin->pin_pid, 0) == 0)
431 kill(pin->pin_pid, SIGKILL);
433 pin->pin_pid = 0;
436 static void *timeout_thread(void *arg)
438 struct pinentry_s *pin = arg;
439 struct timespec ts;
441 clock_gettime(CLOCK_REALTIME, &ts);
442 ts.tv_sec += pin->timeout;
443 MUTEX_LOCK(&pin->cond_mutex);
444 pthread_cond_timedwait(&pin->cond, &pin->cond_mutex, &ts);
446 /* pthread_cond_signal() was called from pinentry_iterate() (we have a
447 * key). */
448 if (pin->status == PINENTRY_NONE) {
449 MUTEX_UNLOCK(&pin->cond_mutex);
450 pthread_exit(PTHREAD_CANCELED);
451 return NULL;
454 MUTEX_LOCK(&pin->status_mutex);
455 kill_pinentry(pin);
456 pin->status = PINENTRY_TIMEOUT;
457 MUTEX_UNLOCK(&pin->cond_mutex);
458 MUTEX_UNLOCK(&pin->status_mutex);
459 pthread_exit(PTHREAD_CANCELED);
460 return NULL;
463 gpg_error_t pinentry_fork(assuan_context_t ctx)
465 struct client_s *client = assuan_get_pointer(ctx);
466 struct pinentry_s *pin = client->pinentry;
467 gpg_error_t rc;
468 gint p[2];
469 pid_t pid;
470 pinentry_key_s pk;
471 gchar *result = NULL;
473 if (pipe(p) == -1)
474 return gpg_error_from_syserror();
476 pid = fork();
478 switch (pid) {
479 case -1:
480 rc = gpg_error_from_syserror();
481 close(p[0]);
482 close(p[1]);
483 return rc;
484 case 0:
485 close(p[0]);
486 free_client_list();
488 if (pin->timeout > 0 && client->pinentry->which == PINENTRY_OPEN) {
490 * Send the pid of the pinentry process back to pwmd so it can
491 * handle the pinentry timeout properly.
493 pk.status = PINENTRY_PID;
494 pk.error = pinentry_command(pin, &result, "GETINFO pid");
496 if (write_result(p[1], &pk, result))
497 _exit(EXIT_FAILURE);
500 pk.status = PINENTRY_RUNNING;
501 pk.error = pinentry_getpin(pin, &result);
503 if (write_result(p[1], &pk, result))
504 _exit(EXIT_FAILURE);
506 _exit(EXIT_SUCCESS);
507 default:
508 close(p[1]);
509 client->pinentry->fd = p[0];
510 client->pinentry->pid = pid;
511 client->pinentry->status = PINENTRY_INIT;
512 break;
516 * Don't call assuan_process_done() here. That should be done in
517 * open_command_finalize() after the key has been read().
519 return 0;
522 gpg_error_t lock_pin_mutex(struct client_s *client)
524 if (pthread_mutex_trylock(&pin_mutex) == EBUSY) {
525 if (client->ctx) {
527 * If a client disconnects unexpectedly while waiting for a
528 * lock, this lets the thread terminate because send_status()
529 * will return an error.
531 while (pthread_mutex_trylock(&pin_mutex) == EBUSY) {
532 gpg_error_t rc = send_status(client->ctx, STATUS_LOCKED, NULL);
534 if (rc)
535 return rc;
537 sleep(1);
540 else
541 MUTEX_LOCK(&pin_mutex);
543 else
544 MUTEX_LOCK_DEBUG;
546 client->pinentry->has_lock = TRUE;
547 return 0;
550 void unlock_pin_mutex(struct pinentry_s *pin)
552 if (pin->has_lock == FALSE)
553 return;
555 MUTEX_UNLOCK(&pin_mutex);
556 pin->has_lock = FALSE;
559 void cleanup_pinentry(struct pinentry_s *pin)
561 if (!pin)
562 return;
564 if (pin->ctx && pin->pid)
565 pinentry_disconnect(pin);
567 if (pthread_mutex_trylock(&pin->status_mutex) == EBUSY) {
568 MUTEX_UNLOCK(&pin->status_mutex);
570 else
571 pthread_mutex_unlock(&pin->status_mutex);
573 MUTEX_LOCK(&pin->status_mutex);
574 kill_pinentry(pin);
575 MUTEX_UNLOCK(&pin->status_mutex);
576 unlock_pin_mutex(pin);
577 pthread_mutex_destroy(&pin->status_mutex);
579 if (pthread_mutex_trylock(&pin->cond_mutex) == EBUSY) {
580 MUTEX_UNLOCK(&pin->cond_mutex);
582 else
583 pthread_mutex_unlock(&pin->cond_mutex);
585 pthread_mutex_destroy(&pin->cond_mutex);
586 pthread_cond_destroy(&pin->cond);
587 g_free(pin->ttyname);
588 g_free(pin->ttytype);
589 g_free(pin->desc);
590 g_free(pin->title);
591 g_free(pin->prompt);
592 g_free(pin->path);
593 g_free(pin->display);
594 g_free(pin->filename);
595 g_free(pin);
598 void set_pinentry_defaults(struct pinentry_s *pin)
600 FILE *fp;
601 gchar buf[PATH_MAX];
602 struct passwd *pw = getpwuid(getuid());
603 gchar *p;
605 pin->enable = -1;
606 g_snprintf(buf, sizeof(buf), "%s/.pwmd/pinentry.conf", pw->pw_dir);
607 fp = fopen(buf, "r");
609 if (fp) {
610 while ((p = fgets(buf, sizeof(buf), fp)) != NULL) {
611 gchar name[32] = {0}, value[256] = {0};
613 if (*p == '#')
614 continue;
616 if (p[strlen(p)-1] == '\n')
617 p[strlen(p)-1] = 0;
619 if (sscanf(p, " %31[a-zA-Z] = %255s", name, value) != 2)
620 continue;
622 if (g_strcasecmp("TTYNAME", name) == 0)
623 pin->ttyname = g_strdup(value);
624 else if (g_strcasecmp("TTYTYPE", name) == 0)
625 pin->ttytype = g_strdup(value);
626 else if (g_strcasecmp("DISPLAY", name) == 0)
627 pin->display = g_strdup(value);
628 else if (g_strcasecmp("PATH", name) == 0)
629 pin->path = g_strdup(value);
632 fclose(fp);
635 pin->timeout = get_key_file_integer("global", "pinentry_timeout");
638 int pinentry_iterate(struct client_s *cl, gboolean read_ready)
640 gpg_error_t rc;
642 MUTEX_LOCK(&cl->pinentry->status_mutex);
644 /* Set from pinentry_timeout_thread(). */
645 if (cl->pinentry->status == PINENTRY_TIMEOUT) {
646 cl->pinentry->status = PINENTRY_NONE;
647 rc = send_error(cl->ctx, GPG_ERR_TIMEOUT);
648 cleanup_client(cl);
649 reset(cl->pinentry);
650 unlock_pin_mutex(cl->pinentry);
651 MUTEX_UNLOCK(&cl->pinentry->status_mutex);
654 if (cl->pinentry->status == PINENTRY_RUNNING) {
655 if (read_ready) {
656 guchar *shakey;
657 pinentry_key_s pk;
658 gsize len;
660 memset(&pk, 0, sizeof(pk));
661 len = read(cl->pinentry->fd, &pk, sizeof(pk));
662 pthread_testcancel();
664 if (len == sizeof(pk)) {
665 if (pk.error) {
666 if (cl->pinentry->status == PINENTRY_TIMEOUT)
667 pk.error = GPG_ERR_TIMEOUT;
669 rc = send_error(cl->ctx, pk.error);
671 else if (pk.status == PINENTRY_PID) {
673 * Start the timeout thread for the pinentry process
674 * now that we know the pid of it.
676 pthread_attr_t attr;
677 pthread_attr_init(&attr);
678 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
679 cl->pinentry->pin_pid = pk.what.pid;
680 pthread_create(&cl->pinentry->tid, &attr, timeout_thread,
681 cl->pinentry);
682 pthread_attr_destroy(&attr);
684 else {
685 if (cl->pinentry->tid) {
686 cl->pinentry->status = PINENTRY_NONE;
687 pthread_cond_signal(&cl->pinentry->cond);
690 shakey = gcry_malloc(gcrykeysize);
692 if (!shakey)
693 pk.error = gpg_error_from_errno(ENOMEM);
694 else {
695 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey,
696 pk.what.key,
697 strlen(pk.what.key) == 0 ? 1 : strlen(pk.what.key));
698 rc = cl->pinentry->cb(cl->ctx, shakey, FALSE);
702 else if (len == -1) {
703 if (cl->pinentry->status == PINENTRY_TIMEOUT)
704 pk.error = GPG_ERR_TIMEOUT;
706 pk.error = gpg_err_code_from_syserror();
707 log_write("%s", gpg_strerror(pk.error));
709 else if (len == 0) {
710 if (cl->pinentry->status == PINENTRY_TIMEOUT)
711 pk.error = GPG_ERR_TIMEOUT;
713 pk.error = GPG_ERR_EOF;
714 log_write("%s", gpg_strerror(pk.error));
716 else
717 log_write(N_("read(): short byte count"));
719 if (pk.error) {
720 if (cl->pinentry->tid) {
721 cl->pinentry->status = PINENTRY_NONE;
722 //pthread_cancel(cl->pinentry->tid, NULL);
723 pthread_cond_signal(&cl->pinentry->cond);
726 if (cl->pinentry->which == PINENTRY_OPEN)
727 cleanup_client(cl);
730 if (pk.error || pk.status == PINENTRY_RUNNING) {
731 reset(cl->pinentry);
732 unlock_file_mutex(cl);
733 unlock_pin_mutex(cl->pinentry);
736 memset(&pk, 0, sizeof(pk));
740 MUTEX_UNLOCK(&cl->pinentry->status_mutex);
741 return 0;
744 struct pinentry_s *pinentry_init()
746 struct pinentry_s *pin = g_malloc0(sizeof(struct pinentry_s));
748 if (!pin)
749 return NULL;
751 pthread_mutex_init(&pin->status_mutex, NULL);
752 pthread_mutex_init(&pin->cond_mutex, NULL);
753 pthread_cond_init(&pin->cond, NULL);
754 set_pinentry_defaults(pin);
755 return pin;