Ported to libassuan 2.0. This version supports building a DSO so no
[pwmd.git] / src / pinentry.c
blobbdc56ce856d11c1a0809af665e2adca7d9c5d604
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, gint which);
54 static gpg_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 gchar *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_new(&ctx);
219 if (rc)
220 return rc;
222 rc = assuan_pipe_connect(ctx, pin->path ? pin->path : tmp, argv,
223 child_list, NULL, NULL, 0);
224 g_free(tmp);
226 if (rc)
227 return rc;
229 pin->pid = assuan_get_pid(ctx);
230 pin->ctx = ctx;
231 rc = set_pinentry_options(pin);
232 return rc ? rc : set_pinentry_strings(pin, 0);
235 static gpg_error_t pinentry_command(struct pinentry_s *pin, gchar **result,
236 const gchar *cmd)
238 gpg_error_t rc = 0;
240 if (!pin->ctx)
241 rc = launch_pinentry(pin);
243 return rc ? rc : assuan_command(pin, result, cmd);
246 static gpg_error_t set_pinentry_strings(struct pinentry_s *pin, gint which)
248 gchar *buf;
249 gpg_error_t rc;
250 gchar *title = NULL;
252 #ifdef WITH_QUALITY
253 if (pin->which == PINENTRY_SAVE && which != 2) {
254 rc = pinentry_command(pin, NULL, "SETQUALITYBAR");
256 if (rc)
257 goto done;
259 pin->inquire_cb = quality_cb;
260 pin->inquire_data = pin;
262 #endif
264 if (which == 1)
265 title = g_strdup(N_("Passphrase mismatch, please try again."));
266 else if (!pin->title)
267 title = pin->title = g_strdup_printf(N_("Password Manager Daemon%s%s"),
268 pin->name ? ": " : "", pin->name ? pin->name : "");
269 else
270 title = pin->title;
272 if (!pin->prompt)
273 pin->prompt = g_strdup(N_("Passphrase:"));
275 if (!pin->desc && !which)
276 pin->desc = g_strdup_printf(pin->which == PINENTRY_OPEN ?
277 N_("A passphrase is required to open the file \"%s\". Please%%0Aenter the passphrase below.") :
278 N_("A passphrase is required to save to the file \"%s\". Please%%0Aenter the passphrase below."),
279 pin->filename);
281 if (which == 2)
282 buf = g_strdup_printf("SETERROR %s", N_("Please enter the passphrase again for confirmation."));
283 else
284 buf = g_strdup_printf("SETERROR %s", pin->desc);
286 rc = pinentry_command(pin, NULL, buf);
287 g_free(buf);
289 if (rc)
290 goto done;
292 buf = g_strdup_printf("SETPROMPT %s", pin->prompt);
293 rc = pinentry_command(pin, NULL, buf);
294 g_free(buf);
296 if (rc)
297 goto done;
299 buf = g_strdup_printf("SETDESC %s", title);
300 rc = pinentry_command(pin, NULL, buf);
301 g_free(buf);
303 done:
304 if (which == 1)
305 g_free(title);
307 return rc;
310 static void pinentry_disconnect(struct pinentry_s *pin)
312 if (!pin)
313 return;
315 if (pin->ctx)
316 assuan_release(pin->ctx);
318 pin->ctx = NULL;
319 pin->pid = 0;
322 static gpg_error_t do_getpin(struct pinentry_s *pin, gchar **result)
324 gpg_error_t rc;
326 *result = NULL;
327 rc = pinentry_command(pin, result, "GETPIN");
329 if (!*result)
330 *result = xstrdup("");
332 return rc;
335 gpg_error_t pinentry_getpin(struct pinentry_s *pin, gchar **result)
337 gint which = 0;
338 gpg_error_t rc = set_pinentry_strings(pin, which);
339 gchar *result1 = NULL;
341 if (rc)
342 goto done;
344 again:
345 rc = do_getpin(pin, result);
347 if (rc)
348 goto done;
350 if (pin->which == PINENTRY_SAVE) {
351 if (!result1) {
352 rc = set_pinentry_strings(pin, 2);
354 if (rc)
355 goto done;
357 result1 = g_strdup(*result);
358 goto again;
361 if (strcmp(result1, *result)) {
362 g_free(result1);
363 xfree(*result);
364 result1 = *result = NULL;
365 rc = set_pinentry_strings(pin, 1);
367 if (rc)
368 goto done;
370 goto again;
374 done:
375 g_free(result1);
376 pinentry_disconnect(pin);
377 return rc;
380 static gint write_result(gint fd, pinentry_key_s *pk, gchar *result)
382 gsize len;
384 if (pk->error) {
386 * libassuan handles GPG_ERR_EOF in assuan_process_done() and
387 * will disconnect the client even if the error isn't related
388 * to it. Use GPG_ERR_CANCELED instead.
390 if (gpg_err_code(pk->error) == GPG_ERR_EOF)
391 pk->error = GPG_ERR_CANCELED;
393 len = pth_write(fd, pk, sizeof(pinentry_key_s));
394 close(fd);
396 if (len != sizeof(pinentry_key_s))
397 log_write("%s(%i): write: len != sizeof(pk)", __FUNCTION__, __LINE__);
399 return 1;
402 if (pk->status == PINENTRY_PID)
403 pk->what.pid = atoi(result);
404 else
405 g_strlcpy(pk->what.key, result, sizeof(pk->what.key));
407 xfree(result);
408 len = pth_write(fd, pk, sizeof(pinentry_key_s));
410 if (len != sizeof(pinentry_key_s)) {
411 memset(pk, 0, sizeof(pinentry_key_s));
412 log_write("%s(%i): write: len != sizeof(pk)", __FUNCTION__, __LINE__);
413 close(fd);
414 return 1;
417 if (pk->status != PINENTRY_PID)
418 close(fd);
420 memset(pk, 0, sizeof(pinentry_key_s));
421 return 0;
424 static void reset(struct pinentry_s *pin)
426 gint status;
428 if (pin->pid)
429 waitpid(pin->pid, &status, 0);
431 if (pin->fd != -1)
432 close(pin->fd);
434 pin->fd = -1;
435 pin->pid = pin->pin_pid = 0;
436 pin->tid = 0;
437 pin->status = PINENTRY_NONE;
440 /* pin->status_mutex should be locked before calling this function. */
441 static void kill_pinentry(struct pinentry_s *pin)
443 if (pin->pin_pid == 0)
444 return;
446 if (kill(pin->pin_pid, 0) == 0)
447 if (kill(pin->pin_pid, SIGTERM) == 0)
448 if (kill(pin->pin_pid, 0) == 0)
449 kill(pin->pin_pid, SIGKILL);
451 pin->pin_pid = 0;
454 static void timeout_cleanup(void *arg)
456 pth_event_t ev = arg;
458 pth_event_free(ev, PTH_FREE_ALL);
461 static void *timeout_thread(void *arg)
463 struct pinentry_s *pin = arg;
464 pth_event_t ev;
465 pth_attr_t attr = pth_attr_of(pth_self());
467 pth_attr_set(attr, PTH_ATTR_NAME, __FUNCTION__);
468 pth_attr_destroy(attr);
469 ev = pth_event(PTH_EVENT_TIME, pth_timeout(pin->timeout, 0));
470 MUTEX_LOCK(&pin->cond_mutex);
471 pth_cleanup_push(timeout_cleanup, ev);
472 pth_cond_await(&pin->cond, &pin->cond_mutex, ev);
473 pth_cleanup_pop(1);
475 /* pth_cond_notify() was called from pinentry_iterate() (we have a
476 * key). */
477 if (pin->status == PINENTRY_NONE) {
478 MUTEX_UNLOCK(&pin->cond_mutex);
479 pth_exit(PTH_CANCELED);
480 return NULL;
483 MUTEX_LOCK(&pin->status_mutex);
484 kill_pinentry(pin);
485 pin->status = PINENTRY_TIMEOUT;
486 MUTEX_UNLOCK(&pin->cond_mutex);
487 MUTEX_UNLOCK(&pin->status_mutex);
488 pth_exit(PTH_CANCELED);
489 return NULL;
492 static void child_prepare(void *arg)
494 gint i;
495 gint n = g_slist_length(cn_thread_list);
496 struct pinentry_s *pin = arg;
498 for (i = 0; i < n; i++) {
499 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
500 pth_mutex_t *m;
502 cache_get_mutex(cn->cl->md5file, &m);
503 pth_mutex_release(m);
506 pth_mutex_release(&pin->status_mutex);
507 pth_mutex_release(&pin->cond_mutex);
508 free_client_list();
511 gpg_error_t pinentry_fork(assuan_context_t ctx)
513 struct client_s *client = assuan_get_pointer(ctx);
514 struct pinentry_s *pin = client->pinentry;
515 gpg_error_t rc = 0;
516 gint p[2];
517 pid_t pid;
518 pinentry_key_s pk;
519 gchar *result = NULL;
521 if (pipe(p) == -1)
522 return gpg_error_from_syserror();
524 pin->timeout = get_key_file_integer(pin->filename, "pinentry_timeout");
525 pth_atfork_push(NULL, NULL, child_prepare, pin);
526 pid = pth_fork();
528 switch (pid) {
529 case -1:
530 rc = gpg_error_from_syserror();
531 close(p[0]);
532 close(p[1]);
533 break;
534 case 0:
535 close(p[0]);
536 if (pin->timeout > 0 && pin->which == PINENTRY_OPEN) {
538 * Send the pid of the pinentry process back to pwmd so it can
539 * handle the pinentry timeout properly.
541 pk.status = PINENTRY_PID;
542 pk.error = pinentry_command(pin, &result, "GETINFO pid");
544 if (write_result(p[1], &pk, result))
545 _exit(EXIT_FAILURE);
548 pk.status = PINENTRY_RUNNING;
549 pk.error = pinentry_getpin(pin, &result);
551 if (write_result(p[1], &pk, result))
552 _exit(EXIT_FAILURE);
554 _exit(EXIT_SUCCESS);
555 default:
556 close(p[1]);
557 client->pinentry->fd = p[0];
558 client->pinentry->pid = pid;
559 client->pinentry->status = PINENTRY_INIT;
560 break;
564 * Don't call assuan_process_done() here. That should be done in
565 * the callback function which is called after the key has been read()
566 * in pinentry_iterate().
568 pth_atfork_pop();
569 return rc;
572 gpg_error_t lock_pin_mutex(struct client_s *client)
574 gpg_error_t rc = 0;
576 MUTEX_TRYLOCK(client->ctx, &pin_mutex, rc);
578 if (!rc)
579 client->pinentry->has_lock = TRUE;
581 return rc;
584 void unlock_pin_mutex(struct pinentry_s *pin)
586 if (pin->has_lock == FALSE)
587 return;
589 MUTEX_UNLOCK(&pin_mutex);
590 pin->has_lock = FALSE;
593 void cleanup_pinentry(struct pinentry_s *pin)
595 if (!pin)
596 return;
598 if (pin->ctx && pin->pid)
599 pinentry_disconnect(pin);
601 if (!pth_mutex_acquire(&pin->status_mutex, TRUE, NULL) && errno == EBUSY) {
602 MUTEX_UNLOCK(&pin->status_mutex);
604 else
605 pth_mutex_release(&pin->status_mutex);
607 MUTEX_LOCK(&pin->status_mutex);
608 kill_pinentry(pin);
609 MUTEX_UNLOCK(&pin->status_mutex);
610 unlock_pin_mutex(pin);
612 if (!pth_mutex_acquire(&pin->cond_mutex, TRUE, NULL) && errno == EBUSY) {
613 MUTEX_UNLOCK(&pin->cond_mutex);
615 else
616 pth_mutex_release(&pin->cond_mutex);
618 if (pin->name)
619 g_free(pin->name);
621 if (pin->ttyname)
622 g_free(pin->ttyname);
624 if (pin->ttytype)
625 g_free(pin->ttytype);
627 if (pin->desc)
628 g_free(pin->desc);
630 if (pin->title)
631 g_free(pin->title);
633 if (pin->prompt)
634 g_free(pin->prompt);
636 if (pin->path)
637 g_free(pin->path);
639 if (pin->display)
640 g_free(pin->display);
642 if (pin->filename)
643 g_free(pin->filename);
645 if (pin->lcctype)
646 g_free(pin->lcctype);
648 if (pin->lcmessages)
649 g_free(pin->lcmessages);
651 g_free(pin);
654 void reset_pin_defaults(struct pinentry_s *pin)
656 pin->enable = -1;
657 pin->timeout = get_key_file_integer("global", "pinentry_timeout");
660 void set_pinentry_defaults(struct pinentry_s *pin)
662 FILE *fp;
663 gchar buf[PATH_MAX];
664 gchar *p;
666 g_snprintf(buf, sizeof(buf), "%s/.pwmd/pinentry.conf", g_get_home_dir());
667 fp = fopen(buf, "r");
669 if (fp) {
670 while ((p = fgets(buf, sizeof(buf), fp)) != NULL) {
671 gchar name[32] = {0}, value[256] = {0};
673 if (*p == '#')
674 continue;
676 if (p[strlen(p)-1] == '\n')
677 p[strlen(p)-1] = 0;
679 if (sscanf(p, " %31[a-zA-Z] = %255s", name, value) != 2)
680 continue;
682 if (g_strcasecmp("TTYNAME", name) == 0) {
683 if (pin->ttyname)
684 g_free(pin->ttyname);
686 pin->ttyname = g_strdup(value);
688 else if (g_strcasecmp("TTYTYPE", name) == 0) {
689 if (pin->ttytype)
690 g_free(pin->ttytype);
692 pin->ttytype = g_strdup(value);
694 else if (g_strcasecmp("DISPLAY", name) == 0) {
695 if (pin->display)
696 g_free(pin->display);
698 pin->display = g_strdup(value);
700 else if (g_strcasecmp("PATH", name) == 0) {
701 if (pin->path)
702 g_free(pin->path);
704 pin->path = g_strdup(value);
706 else if (g_strcasecmp("LC_TYPE", name) == 0) {
707 if (pin->lcctype)
708 g_free(pin->lcctype);
710 pin->lcctype = g_strdup(value);
712 else if (g_strcasecmp("LC_MESSAGES", name) == 0) {
713 if (pin->lcmessages)
714 g_free(pin->lcmessages);
716 pin->lcmessages = g_strdup(value);
720 fclose(fp);
723 reset_pin_defaults(pin);
726 int pinentry_iterate(struct client_s *cl, gboolean read_ready)
728 gpg_error_t rc;
730 MUTEX_LOCK(&cl->pinentry->status_mutex);
732 /* Set from pinentry_timeout_thread(). */
733 if (cl->pinentry->status == PINENTRY_TIMEOUT) {
734 cl->pinentry->status = PINENTRY_NONE;
735 rc = send_error(cl->ctx, GPG_ERR_TIMEOUT);
736 cleanup_client(cl);
737 reset(cl->pinentry);
738 unlock_pin_mutex(cl->pinentry);
739 MUTEX_UNLOCK(&cl->pinentry->status_mutex);
742 if (cl->pinentry->status == PINENTRY_RUNNING) {
743 if (read_ready) {
744 guchar *shakey;
745 pinentry_key_s pk;
746 gsize len;
748 memset(&pk, 0, sizeof(pk));
749 len = pth_read(cl->pinentry->fd, &pk, sizeof(pk));
751 if (len == sizeof(pk)) {
752 guint hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
754 if (pk.error) {
755 if (cl->pinentry->status == PINENTRY_TIMEOUT)
756 pk.error = GPG_ERR_TIMEOUT;
758 rc = send_error(cl->ctx, pk.error);
760 else if (pk.status == PINENTRY_PID) {
761 gint n;
764 * Start the timeout thread for the pinentry process
765 * now that we know the pid of it.
767 pth_attr_t attr = pth_attr_new();
768 pth_attr_init(attr);
769 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
770 cl->pinentry->pin_pid = pk.what.pid;
771 cl->pinentry->tid = pth_spawn(attr, timeout_thread,
772 cl->pinentry);
773 n = errno;
774 pth_attr_destroy(attr);
776 if (!cl->pinentry->tid) {
777 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__,
778 _gpg_strerror(gpg_error_from_errno(n)));
779 pk.error = gpg_error_from_errno(n);
782 else {
783 if (cl->pinentry->tid) {
784 cl->pinentry->status = PINENTRY_NONE;
785 pth_cond_notify(&cl->pinentry->cond, FALSE);
788 shakey = gcry_malloc(hashlen);
790 if (!shakey)
791 pk.error = gpg_error_from_errno(ENOMEM);
792 else {
793 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey,
794 pk.what.key,
795 strlen(pk.what.key) ? strlen(pk.what.key) : 1);
796 rc = cl->pinentry->cb(cl->ctx, shakey, FALSE);
800 else if (len == -1) {
801 if (cl->pinentry->status == PINENTRY_TIMEOUT)
802 pk.error = GPG_ERR_TIMEOUT;
804 pk.error = gpg_err_code_from_syserror();
805 log_write("%s", _gpg_strerror(pk.error));
807 else if (len == 0) {
808 if (cl->pinentry->status == PINENTRY_TIMEOUT)
809 pk.error = GPG_ERR_TIMEOUT;
811 pk.error = GPG_ERR_EOF;
812 log_write("%s", _gpg_strerror(pk.error));
814 else
815 log_write(N_("read(): short byte count"));
817 if (pk.error) {
818 if (cl->pinentry->tid) {
819 cl->pinentry->status = PINENTRY_NONE;
820 pth_cond_notify(&cl->pinentry->cond, FALSE);
823 if (cl->pinentry->which == PINENTRY_OPEN)
824 cleanup_client(cl);
827 if (pk.error || pk.status == PINENTRY_RUNNING) {
828 reset(cl->pinentry);
829 unlock_file_mutex(cl);
830 unlock_pin_mutex(cl->pinentry);
833 memset(&pk, 0, sizeof(pk));
837 MUTEX_UNLOCK(&cl->pinentry->status_mutex);
838 return 0;
841 struct pinentry_s *pinentry_init()
843 struct pinentry_s *pin = g_malloc0(sizeof(struct pinentry_s));
845 if (!pin)
846 return NULL;
848 pth_mutex_init(&pin->status_mutex);
849 pth_mutex_init(&pin->cond_mutex);
850 pth_cond_init(&pin->cond);
851 set_pinentry_defaults(pin);
852 return pin;