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
34 #include "pwmd_error.h"
41 void free_client_list();
42 static gpg_error_t
set_pinentry_strings(struct pinentry_s
*pin
, int which
);
44 static int mem_realloc_cb(void *data
, const void *buffer
, size_t len
)
46 membuf_t
*mem
= (membuf_t
*)data
;
52 if ((p
= xrealloc(mem
->buf
, mem
->len
+ len
)) == NULL
)
56 memcpy((char *)mem
->buf
+ mem
->len
, buffer
, len
);
61 static gpg_error_t
assuan_command(struct pinentry_s
*pin
, gchar
**result
,
70 rc
= assuan_transact(pin
->ctx
, cmd
, mem_realloc_cb
, &data
, NULL
, NULL
,
81 mem_realloc_cb(&data
, "", 1);
82 *result
= (gchar
*)data
.buf
;
89 static gpg_error_t
set_pinentry_options(struct pinentry_s
*pin
)
91 gchar
*display
= getenv("DISPLAY");
92 gint have_display
= 0;
93 gchar
*tty
= NULL
, *ttytype
= NULL
;
97 gchar cmd
[ASSUAN_LINELENGTH
];
99 if (pin
->display
|| display
)
102 tty
= pin
->ttyname
? pin
->ttyname
: ttyname(STDOUT_FILENO
);
105 return GPG_ERR_CANCELED
;
108 if (!have_display
&& !tty
)
109 return GPG_ERR_CANCELED
;
112 gchar
*p
= getenv("TERM");
114 ttytype
= pin
->ttytype
? pin
->ttytype
: p
;
117 return GPG_ERR_CANCELED
;
120 opt
= have_display
? "DISPLAY" : "TTYNAME";
121 val
= have_display
? pin
->display
? pin
->display
: display
: tty
;
122 g_snprintf(cmd
, sizeof(cmd
), "OPTION %s=%s", g_ascii_strdown(opt
, strlen(opt
)), val
);
123 rc
= assuan_command(pin
, &result
, cmd
);
129 g_snprintf(cmd
, sizeof(cmd
), "OPTION ttytype=%s", ttytype
);
130 rc
= assuan_command(pin
, &result
, cmd
);
136 static gpg_error_t
launch_pinentry(struct pinentry_s
*pin
)
139 assuan_context_t ctx
;
140 gint child_list
[] = {-1};
141 const gchar
*argv
[4];
143 argv
[0] = "pinentry";
146 argv
[1] = "--display";
147 argv
[2] = pin
->display
;
153 rc
= assuan_pipe_connect(&ctx
, pin
->path
? pin
->path
: PINENTRY_PATH
,
159 pin
->pid
= assuan_get_pid(ctx
);
161 rc
= set_pinentry_options(pin
);
162 return rc
? rc
: set_pinentry_strings(pin
, 0);
165 static gpg_error_t
pinentry_command(struct pinentry_s
*pin
, gchar
**result
,
171 rc
= launch_pinentry(pin
);
173 return rc
? rc
: assuan_command(pin
, result
, cmd
);
176 static gpg_error_t
set_pinentry_strings(struct pinentry_s
*pin
, int which
)
183 title
= g_strdup(N_("Password mismatch, please try again."));
184 else if (!pin
->title
)
185 title
= pin
->title
= g_strdup(N_("Password Manager Daemon"));
190 pin
->prompt
= g_strdup(N_("Password:"));
192 if (!pin
->desc
&& !which
)
193 pin
->desc
= g_strdup_printf(pin
->which
== PINENTRY_OPEN
?
194 N_("A password is required to open the file \"%s\". Please%%0Aenter the password below.") :
195 N_("A password is required to save to the file \"%s\". Please%%0Aenter the password below."),
199 buf
= g_strdup_printf("SETERROR %s", N_("Please type the password again for confirmation."));
201 buf
= g_strdup_printf("SETERROR %s", pin
->desc
);
203 rc
= pinentry_command(pin
, NULL
, buf
);
209 buf
= g_strdup_printf("SETPROMPT %s", pin
->prompt
);
210 rc
= pinentry_command(pin
, NULL
, buf
);
216 buf
= g_strdup_printf("SETDESC %s", title
);
217 rc
= pinentry_command(pin
, NULL
, buf
);
227 static void pinentry_disconnect(struct pinentry_s
*pin
)
233 assuan_disconnect(pin
->ctx
);
239 static gpg_error_t
do_getpin(struct pinentry_s
*pin
, char **result
)
244 rc
= pinentry_command(pin
, result
, "GETPIN");
247 *result
= xstrdup("");
252 gpg_error_t
pinentry_getpin(struct pinentry_s
*pin
, gchar
**result
)
255 gpg_error_t rc
= set_pinentry_strings(pin
, which
);
256 gchar
*result1
= NULL
;
259 pinentry_disconnect(pin
);
264 rc
= do_getpin(pin
, result
);
269 if (pin
->which
== PINENTRY_SAVE
) {
271 rc
= set_pinentry_strings(pin
, 2);
276 result1
= g_strdup(*result
);
280 if (strcmp(result1
, *result
)) {
283 result1
= *result
= NULL
;
284 rc
= set_pinentry_strings(pin
, 1);
295 pinentry_disconnect(pin
);
299 static int write_result(int fd
, pinentry_key_s
*pk
, char *result
)
305 * libassuan handles GPG_ERR_EOF in assuan_process_done() and
306 * will disconnect the client even if the error isn't related
307 * to it. Use GPG_ERR_CANCELED instead.
309 if (gpg_err_code(pk
->error
) == GPG_ERR_EOF
)
310 pk
->error
= GPG_ERR_CANCELED
;
312 len
= pth_write(fd
, pk
, sizeof(pinentry_key_s
));
315 if (len
!= sizeof(pinentry_key_s
))
316 log_write("%s(%i): write: len != sizeof(pk)", __FUNCTION__
, __LINE__
);
321 if (pk
->status
== PINENTRY_PID
)
322 pk
->what
.pid
= atoi(result
);
324 g_strlcpy(pk
->what
.key
, result
, sizeof(pk
->what
.key
));
327 len
= pth_write(fd
, pk
, sizeof(pinentry_key_s
));
329 if (len
!= sizeof(pinentry_key_s
)) {
330 memset(pk
, 0, sizeof(pinentry_key_s
));
331 log_write("%s(%i): write: len != sizeof(pk)", __FUNCTION__
, __LINE__
);
336 if (pk
->status
!= PINENTRY_PID
)
339 memset(pk
, 0, sizeof(pinentry_key_s
));
343 static void reset(struct pinentry_s
*pin
)
347 pth_waitpid(pin
->pid
, &status
, 0);
350 pin
->pid
= pin
->pin_pid
= 0;
352 pth_event_isolate(pin
->ev
);
353 pth_event_free(pin
->ev
, PTH_FREE_THIS
);
355 pin
->status
= PINENTRY_NONE
;
358 static void *timeout_thread(void *arg
)
360 struct pinentry_s
*pin
= arg
;
361 pth_event_t ev
= pth_event(PTH_EVENT_TIME
, pth_timeout(pin
->timeout
, 0));
364 pth_event_free(ev
, PTH_FREE_THIS
);
365 pth_mutex_acquire(&pin
->status_mutex
, FALSE
, NULL
);
367 /* pth_cancel() was called from pinentry_iterate() (we have a key).
368 * pth_wait() was the cancelation point. */
369 if (pin
->status
== PINENTRY_NONE
) {
371 pth_mutex_release(&pin
->status_mutex
);
375 if (kill(pin
->pin_pid
, 0) == 0)
376 if (kill(pin
->pin_pid
, SIGTERM
) == 0)
377 if (kill(pin
->pin_pid
, 0) == 0)
378 kill(pin
->pin_pid
, SIGKILL
);
381 pin
->status
= PINENTRY_TIMEOUT
;
382 pth_mutex_release(&pin
->status_mutex
);
383 pth_exit(PTH_CANCELED
);
387 gpg_error_t
pinentry_fork(assuan_context_t ctx
)
389 struct client_s
*client
= assuan_get_pointer(ctx
);
390 struct pinentry_s
*pin
= client
->pinentry
;
395 gchar
*result
= NULL
;
398 return gpg_error_from_syserror();
404 rc
= gpg_error_from_syserror();
412 if (pin
->timeout
> 0) {
414 * Send the pid of the pinentry process back to pwmd so it can
415 * handle the pinentry timeout properly.
417 pk
.status
= PINENTRY_PID
;
418 pk
.error
= pinentry_command(pin
, &result
, "GETINFO pid");
420 if (write_result(p
[1], &pk
, result
))
424 pk
.status
= PINENTRY_RUNNING
;
425 pk
.error
= pinentry_getpin(pin
, &result
);
427 if (write_result(p
[1], &pk
, result
))
433 client
->pinentry
->fd
= p
[0];
434 client
->pinentry
->pid
= pid
;
435 client
->pinentry
->status
= PINENTRY_INIT
;
440 * Don't call assuan_process_done() here. That should be done in
441 * open_command_finalize() after the key has been read().
446 gpg_error_t
lock_pin_mutex(struct client_s
*client
)
448 while (pth_mutex_acquire(&pin_mutex
, TRUE
, NULL
) == FALSE
) {
450 gpg_error_t rc
= send_status(client
->ctx
, STATUS_LOCKED
);
459 client
->pinentry
->has_lock
= TRUE
;
463 void unlock_pin_mutex(struct pinentry_s
*pin
)
465 if (pin
->has_lock
== FALSE
)
468 pth_mutex_release(&pin_mutex
);
469 pin
->has_lock
= FALSE
;
472 void cleanup_pinentry(struct pinentry_s
*pin
)
477 unlock_pin_mutex(pin
);
479 if (pin
->ctx
&& pin
->pid
)
480 pinentry_disconnect(pin
);
482 g_free(pin
->ttyname
);
483 g_free(pin
->ttytype
);
488 g_free(pin
->display
);
489 g_free(pin
->filename
);
493 static void set_pinentry_defaults(struct pinentry_s
*pin
)
497 struct passwd
*pw
= getpwuid(getuid());
501 g_snprintf(buf
, sizeof(buf
), "%s/.pwmd/pinentry.conf", pw
->pw_dir
);
502 fp
= fopen(buf
, "r");
505 while ((p
= fgets(buf
, sizeof(buf
), fp
)) != NULL
) {
506 gchar name
[32] = {0}, value
[256] = {0};
511 if (p
[strlen(p
)-1] == '\n')
514 if (sscanf(p
, " %31[a-zA-Z] = %255s", name
, value
) != 2)
517 if (g_strcasecmp("TTYNAME", name
) == 0)
518 pin
->ttyname
= g_strdup(value
);
519 else if (g_strcasecmp("TTYTYPE", name
) == 0)
520 pin
->ttytype
= g_strdup(value
);
521 else if (g_strcasecmp("DISPLAY", name
) == 0)
522 pin
->display
= g_strdup(value
);
523 else if (g_strcasecmp("PATH", name
) == 0)
524 pin
->path
= g_strdup(value
);
530 pin
->timeout
= get_key_file_integer("global", "pinentry_timeout");
533 pth_event_t
pinentry_iterate(struct client_s
*cl
, pth_event_t ev
)
537 pth_mutex_acquire(&cl
->pinentry
->status_mutex
, FALSE
, NULL
);
539 /* Set from pinentry_timeout_thread(). */
540 if (cl
->pinentry
->status
== PINENTRY_TIMEOUT
) {
541 rc
= send_error(cl
->ctx
, GPG_ERR_TIMEOUT
);
543 if (cl
->pinentry
->which
== PINENTRY_OPEN
)
547 unlock_pin_mutex(cl
->pinentry
);
550 if (cl
->pinentry
->status
== PINENTRY_RUNNING
) {
551 pth_event_isolate(cl
->pinentry
->ev
);
553 if (pth_event_occurred(cl
->pinentry
->ev
)) {
554 guchar shakey
[gcrykeysize
];
558 memset(&pk
, 0, sizeof(pk
));
559 len
= pth_read(cl
->pinentry
->fd
, &pk
, sizeof(pk
));
561 if (len
== sizeof(pk
)) {
563 if (cl
->pinentry
->status
== PINENTRY_TIMEOUT
)
564 pk
.error
= GPG_ERR_TIMEOUT
;
566 rc
= send_error(cl
->ctx
, pk
.error
);
568 else if (pk
.status
== PINENTRY_PID
) {
570 * Start the timeout thread for the pinentry process
571 * now that we know the pid of it.
573 pth_attr_t attr
= pth_attr_new();
576 pth_attr_set(attr
, PTH_ATTR_JOINABLE
, 0);
577 pth_attr_set(attr
, PTH_ATTR_CANCEL_STATE
,
578 PTH_CANCEL_ASYNCHRONOUS
);
579 cl
->pinentry
->pin_pid
= pk
.what
.pid
;
580 cl
->pinentry
->tid
= pth_spawn(attr
, timeout_thread
,
584 if (cl
->pinentry
->tid
) {
585 cl
->pinentry
->status
= PINENTRY_NONE
;
586 pth_cancel(cl
->pinentry
->tid
);
589 gcry_md_hash_buffer(GCRY_MD_SHA256
, shakey
, pk
.what
.key
,
590 strlen(pk
.what
.key
) == 0 ? 1 : strlen(pk
.what
.key
));
591 rc
= cl
->pinentry
->cb(cl
->ctx
, shakey
, FALSE
);
592 memset(shakey
, 0, sizeof(shakey
));
595 else if (len
== -1) {
596 if (cl
->pinentry
->status
== PINENTRY_TIMEOUT
)
597 pk
.error
= GPG_ERR_TIMEOUT
;
599 pk
.error
= gpg_err_code_from_syserror();
600 log_write("%s", gpg_strerror(pk
.error
));
603 if (cl
->pinentry
->status
== PINENTRY_TIMEOUT
)
604 pk
.error
= GPG_ERR_TIMEOUT
;
606 pk
.error
= GPG_ERR_EOF
;
607 log_write("%s", gpg_strerror(pk
.error
));
610 log_write(N_("pth_read(): short byte count"));
613 if (cl
->pinentry
->tid
) {
614 pth_cancel(cl
->pinentry
->tid
);
615 cl
->pinentry
->status
= PINENTRY_NONE
;
620 if (cl
->pinentry
->which
== PINENTRY_OPEN
)
623 else if (pk
.status
== PINENTRY_RUNNING
)
626 if (pk
.error
|| pk
.status
== PINENTRY_RUNNING
) {
627 unlock_file_mutex(cl
);
628 unlock_pin_mutex(cl
->pinentry
);
631 memset(&pk
, 0, sizeof(pk
));
634 pth_event_concat(ev
, cl
->pinentry
->ev
, NULL
);
637 pth_mutex_release(&cl
->pinentry
->status_mutex
);
641 struct pinentry_s
*pinentry_init()
643 struct pinentry_s
*pin
= g_malloc0(sizeof(struct pinentry_s
));
648 pth_mutex_init(&pin
->status_mutex
);
649 set_pinentry_defaults(pin
);