1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
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
26 #include <sys/types.h>
34 #include <sys/types.h>
48 #include "pwmd_error.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
;
62 if ((p
= xrealloc(mem
->buf
, mem
->len
+ len
)) == NULL
)
66 memcpy((char *)mem
->buf
+ mem
->len
, buffer
, len
);
72 static assuan_error_t
quality_cb(void *data
, const gchar
*line
)
74 struct pinentry_s
*pin
= data
;
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")))
87 else if (!strcmp(tmp
, N_("it is too short")))
89 else if (!strcmp(tmp
, N_("it is all whitespace")))
91 else if (!strcmp(tmp
, N_("it is based on your username")))
93 else if (!strcmp(tmp
, N_("it is based on a dictionary word")))
95 else if (!strcmp(tmp
, N_("it is based upon your password entry")))
97 else if (!strcmp(tmp
, N_("it's derived from your password entry")))
99 else if (!strcmp(tmp
, N_("it is based on a (reversed) dictionary word")))
101 else if (!strcmp(tmp
, N_("it is derivable from your password entry")))
103 else if (!strcmp(tmp
, N_("it does not contain enough DIFFERENT characters")))
105 else if (!strcmp(tmp
, N_("it is too simplistic/systematic")))
110 tmp
= (const gchar
*)print_fmt(buf
, sizeof(buf
), "%i", score
);
111 return assuan_send_data(pin
->ctx
, tmp
, strlen(tmp
));
115 static gpg_error_t
assuan_command(struct pinentry_s
*pin
, gchar
**result
,
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
);
128 xfree(pin
->data
.buf
);
129 pin
->data
.buf
= NULL
;
134 mem_realloc_cb(&pin
->data
, "", 1);
135 *result
= (gchar
*)pin
->data
.buf
;
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
;
149 gchar
*result
= NULL
;
150 gchar cmd
[ASSUAN_LINELENGTH
];
152 if (pin
->display
|| display
)
155 tty
= pin
->ttyname
? pin
->ttyname
: ttyname(STDOUT_FILENO
);
158 return GPG_ERR_CANCELED
;
161 if (!have_display
&& !tty
)
162 return GPG_ERR_CANCELED
;
165 gchar
*p
= getenv("TERM");
167 ttytype
= pin
->ttytype
? pin
->ttytype
: p
;
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
);
182 g_snprintf(cmd
, sizeof(cmd
), "OPTION ttytype=%s", ttytype
);
183 rc
= assuan_command(pin
, &result
, cmd
);
189 static gpg_error_t
launch_pinentry(struct pinentry_s
*pin
)
192 assuan_context_t ctx
;
193 gint child_list
[] = {-1};
194 const gchar
*argv
[8];
195 const gchar
**p
= argv
;
210 if (pin
->lcmessages
) {
211 *p
++ = "--lc-messages";
212 *p
++ = pin
->lcmessages
;
216 tmp
= get_key_file_string("global", "pinentry_path");
217 rc
= assuan_new(&ctx
);
222 rc
= assuan_pipe_connect(ctx
, pin
->path
? pin
->path
: tmp
, argv
,
223 child_list
, NULL
, NULL
, 0);
229 pin
->pid
= assuan_get_pid(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
,
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
)
253 if (pin
->which
== PINENTRY_SAVE
&& which
!= 2) {
254 rc
= pinentry_command(pin
, NULL
, "SETQUALITYBAR");
259 pin
->inquire_cb
= quality_cb
;
260 pin
->inquire_data
= pin
;
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
: "");
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."),
282 buf
= g_strdup_printf("SETERROR %s", N_("Please enter the passphrase again for confirmation."));
284 buf
= g_strdup_printf("SETERROR %s", pin
->desc
);
286 rc
= pinentry_command(pin
, NULL
, buf
);
292 buf
= g_strdup_printf("SETPROMPT %s", pin
->prompt
);
293 rc
= pinentry_command(pin
, NULL
, buf
);
299 buf
= g_strdup_printf("SETDESC %s", title
);
300 rc
= pinentry_command(pin
, NULL
, buf
);
310 static void pinentry_disconnect(struct pinentry_s
*pin
)
316 assuan_release(pin
->ctx
);
322 static gpg_error_t
do_getpin(struct pinentry_s
*pin
, gchar
**result
)
327 rc
= pinentry_command(pin
, result
, "GETPIN");
330 *result
= xstrdup("");
335 gpg_error_t
pinentry_getpin(struct pinentry_s
*pin
, gchar
**result
)
338 gpg_error_t rc
= set_pinentry_strings(pin
, which
);
339 gchar
*result1
= NULL
;
345 rc
= do_getpin(pin
, result
);
350 if (pin
->which
== PINENTRY_SAVE
) {
352 rc
= set_pinentry_strings(pin
, 2);
357 result1
= g_strdup(*result
);
361 if (strcmp(result1
, *result
)) {
364 result1
= *result
= NULL
;
365 rc
= set_pinentry_strings(pin
, 1);
376 pinentry_disconnect(pin
);
380 static gint
write_result(gint fd
, pinentry_key_s
*pk
, gchar
*result
)
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
));
396 if (len
!= sizeof(pinentry_key_s
))
397 log_write("%s(%i): write: len != sizeof(pk)", __FUNCTION__
, __LINE__
);
402 if (pk
->status
== PINENTRY_PID
)
403 pk
->what
.pid
= atoi(result
);
405 g_strlcpy(pk
->what
.key
, result
, sizeof(pk
->what
.key
));
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__
);
417 if (pk
->status
!= PINENTRY_PID
)
420 memset(pk
, 0, sizeof(pinentry_key_s
));
424 static void reset(struct pinentry_s
*pin
)
429 waitpid(pin
->pid
, &status
, 0);
435 pin
->pid
= pin
->pin_pid
= 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)
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
);
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
;
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
);
475 /* pth_cond_notify() was called from pinentry_iterate() (we have a
477 if (pin
->status
== PINENTRY_NONE
) {
478 MUTEX_UNLOCK(&pin
->cond_mutex
);
479 pth_exit(PTH_CANCELED
);
483 MUTEX_LOCK(&pin
->status_mutex
);
485 pin
->status
= PINENTRY_TIMEOUT
;
486 MUTEX_UNLOCK(&pin
->cond_mutex
);
487 MUTEX_UNLOCK(&pin
->status_mutex
);
488 pth_exit(PTH_CANCELED
);
492 static void child_prepare(void *arg
)
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
);
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
);
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
;
519 gchar
*result
= NULL
;
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
);
530 rc
= gpg_error_from_syserror();
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
))
548 pk
.status
= PINENTRY_RUNNING
;
549 pk
.error
= pinentry_getpin(pin
, &result
);
551 if (write_result(p
[1], &pk
, result
))
557 client
->pinentry
->fd
= p
[0];
558 client
->pinentry
->pid
= pid
;
559 client
->pinentry
->status
= PINENTRY_INIT
;
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().
572 gpg_error_t
lock_pin_mutex(struct client_s
*client
)
576 MUTEX_TRYLOCK(client
->ctx
, &pin_mutex
, rc
);
579 client
->pinentry
->has_lock
= TRUE
;
584 void unlock_pin_mutex(struct pinentry_s
*pin
)
586 if (pin
->has_lock
== FALSE
)
589 MUTEX_UNLOCK(&pin_mutex
);
590 pin
->has_lock
= FALSE
;
593 void cleanup_pinentry(struct pinentry_s
*pin
)
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
);
605 pth_mutex_release(&pin
->status_mutex
);
607 MUTEX_LOCK(&pin
->status_mutex
);
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
);
616 pth_mutex_release(&pin
->cond_mutex
);
622 g_free(pin
->ttyname
);
625 g_free(pin
->ttytype
);
640 g_free(pin
->display
);
643 g_free(pin
->filename
);
646 g_free(pin
->lcctype
);
649 g_free(pin
->lcmessages
);
654 void reset_pin_defaults(struct pinentry_s
*pin
)
657 pin
->timeout
= get_key_file_integer("global", "pinentry_timeout");
660 void set_pinentry_defaults(struct pinentry_s
*pin
)
666 g_snprintf(buf
, sizeof(buf
), "%s/.pwmd/pinentry.conf", g_get_home_dir());
667 fp
= fopen(buf
, "r");
670 while ((p
= fgets(buf
, sizeof(buf
), fp
)) != NULL
) {
671 gchar name
[32] = {0}, value
[256] = {0};
676 if (p
[strlen(p
)-1] == '\n')
679 if (sscanf(p
, " %31[a-zA-Z] = %255s", name
, value
) != 2)
682 if (g_strcasecmp("TTYNAME", name
) == 0) {
684 g_free(pin
->ttyname
);
686 pin
->ttyname
= g_strdup(value
);
688 else if (g_strcasecmp("TTYTYPE", name
) == 0) {
690 g_free(pin
->ttytype
);
692 pin
->ttytype
= g_strdup(value
);
694 else if (g_strcasecmp("DISPLAY", name
) == 0) {
696 g_free(pin
->display
);
698 pin
->display
= g_strdup(value
);
700 else if (g_strcasecmp("PATH", name
) == 0) {
704 pin
->path
= g_strdup(value
);
706 else if (g_strcasecmp("LC_TYPE", name
) == 0) {
708 g_free(pin
->lcctype
);
710 pin
->lcctype
= g_strdup(value
);
712 else if (g_strcasecmp("LC_MESSAGES", name
) == 0) {
714 g_free(pin
->lcmessages
);
716 pin
->lcmessages
= g_strdup(value
);
723 reset_pin_defaults(pin
);
726 int pinentry_iterate(struct client_s
*cl
, gboolean read_ready
)
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
);
738 unlock_pin_mutex(cl
->pinentry
);
739 MUTEX_UNLOCK(&cl
->pinentry
->status_mutex
);
742 if (cl
->pinentry
->status
== PINENTRY_RUNNING
) {
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
);
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
) {
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();
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
,
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
);
783 if (cl
->pinentry
->tid
) {
784 cl
->pinentry
->status
= PINENTRY_NONE
;
785 pth_cond_notify(&cl
->pinentry
->cond
, FALSE
);
788 shakey
= gcry_malloc(hashlen
);
791 pk
.error
= gpg_error_from_errno(ENOMEM
);
793 gcry_md_hash_buffer(GCRY_MD_SHA256
, shakey
,
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
));
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
));
815 log_write(N_("read(): short byte count"));
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
)
827 if (pk
.error
|| pk
.status
== PINENTRY_RUNNING
) {
829 unlock_file_mutex(cl
);
830 unlock_pin_mutex(cl
->pinentry
);
833 memset(&pk
, 0, sizeof(pk
));
837 MUTEX_UNLOCK(&cl
->pinentry
->status_mutex
);
841 struct pinentry_s
*pinentry_init()
843 struct pinentry_s
*pin
= g_malloc0(sizeof(struct pinentry_s
));
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
);