From f260164eba7a6240e826dc81441ed405cc403d35 Mon Sep 17 00:00:00 2001 From: Ben Kibbey Date: Sun, 9 Dec 2007 14:09:24 -0500 Subject: [PATCH] Launching pinentry now works. --- src/common.h | 18 ++++- src/pinentry.c | 212 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- src/pwmd.c | 22 +++--- 3 files changed, 226 insertions(+), 26 deletions(-) diff --git a/src/common.h b/src/common.h index 8d9acd4e..88c0d288 100644 --- a/src/common.h +++ b/src/common.h @@ -51,14 +51,26 @@ typedef struct { guchar key[ASSUAN_LINELENGTH]; gpg_error_t error; } pinentry_key_s; + +struct pinentry_s { + assuan_context_t ctx; + pid_t pid; + gint fd; + pinentry_status_t status; + gchar *title; + gchar *desc; + gchar *prompt; + gchar *ttyname; + gchar *ttytype; + gchar *display; + gchar *path; +}; #endif struct client_s { assuan_context_t ctx; #ifdef WITH_PINENTRY - pid_t pinentry_pid; - gint pinentry_fd; - pinentry_status_t pinentry_status; + struct pinentry_s pinentry; #endif gint fd; gpointer doc; /* xmlDocPtr */ diff --git a/src/pinentry.c b/src/pinentry.c index ad643e2b..6f97d16a 100644 --- a/src/pinentry.c +++ b/src/pinentry.c @@ -16,8 +16,10 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include #include +#include #define _ASSUAN_ONLY_GPG_ERRORS 1 #include @@ -26,22 +28,206 @@ #include #endif +#include "mem.h" #include "common.h" #include "pinentry.h" +#include "pwmd_error.h" -static gpg_error_t getpin(struct client_s *client, char **result, int which) +typedef struct { + size_t len; + void *buf; +} membuf_t; + +static gpg_error_t set_pinentry_strings(struct pinentry_s *pin, int which); + +static int mem_realloc_cb(void *data, const void *buffer, size_t len) { -#if 0 - gpg_error_t error = set_pinentry_strings(client, pctx, which); + membuf_t *mem = (membuf_t *)data; + void *p; + + if (!buffer) + return 0; + + if ((p = xrealloc(mem->buf, mem->len + len)) == NULL) + return 1; + + mem->buf = p; + memcpy((char *)mem->buf + mem->len, buffer, len); + mem->len += len; + return 0; +} + +static gpg_error_t assuan_command(struct pinentry_s *pin, char **result, + const char *cmd) +{ + membuf_t data; + gpg_error_t rc; + + data.len = 0; + data.buf = NULL; + + rc = assuan_transact(pin->ctx, cmd, mem_realloc_cb, &data, NULL, NULL, + NULL, NULL); + + if (rc) { + if (data.buf) { + xfree(data.buf); + data.buf = NULL; + } + } + else { + if (data.buf) { + mem_realloc_cb(&data, "", 1); + *result = (gchar *)data.buf; + } + } + + return gpg_err_code(rc); +} + +static gpg_error_t launch_pinentry(struct pinentry_s *pin) +{ + int rc; + assuan_context_t ctx; + int child_list[] = {-1}; + char *display = getenv("DISPLAY"); + const char *argv[6]; + int have_display = 0; + char *tty = NULL; + + //update_pinentry_settings(pin); + + if (pin->display || display) + have_display = 1; + else { + tty = pin->ttyname ? pin->ttyname : ttyname(STDOUT_FILENO); + + if (!tty) + return gpg_error_from_errno(errno); + } + + if (!display && !tty) + return GPG_ERR_ENOTTY; + + argv[0] = "pinentry"; + argv[1] = have_display ? "--display" : "--ttyname"; + argv[2] = have_display ? pin->display ? pin->display : display : tty; + argv[3] = NULL; + + if (!have_display) { + argv[3] = "--ttytype"; + argv[4] = pin->ttytype ? pin->ttytype : getenv("TERM"); + argv[5] = NULL; + } + + rc = assuan_pipe_connect(&ctx, pin->path ? pin->path : PINENTRY_PATH, + argv, child_list); + + if (rc) + return rc; + + //pin->pid = assuan_get_pid(ctx); + pin->ctx = ctx; + return set_pinentry_strings(pin, 0); +} + +static gpg_error_t pinentry_command(struct pinentry_s *pin, gchar **result, + const gchar *cmd) +{ + gpg_error_t error = 0; + + if (!pin->ctx) + error = launch_pinentry(pin); + + return error ? error : assuan_command(pin, result, cmd); +} + +static gpg_error_t set_pinentry_strings(struct pinentry_s *pin, int which) +{ + char *buf; + char tmp[ASSUAN_LINELENGTH]; + gpg_error_t error; + + if (!pin->title) + pin->title = xstrdup(N_("Password Manager Daemon")); + + if (!pin->prompt) + pin->prompt = xstrdup(N_("Password:")); + + if (!pin->desc && !which) + pin->desc = xstrdup(N_("Enter a password.")); + + if (which == 1) { + snprintf(tmp, sizeof(tmp), "SETERROR %s", N_("Invalid password, please try again.")); + buf = xstrdup(tmp); + } + else if (which == 2) { + snprintf(tmp, sizeof(tmp), "SETERROR %s", N_("Please type the password again for confirmation.")); + buf = xstrdup(tmp); + } + else { + buf = (char *)xmalloc(strlen("SETERROR ") + strlen(pin->desc) + 1); + sprintf(buf, "SETERROR %s", pin->desc); + } + + error = pinentry_command(pin, NULL, buf); + xfree(buf); + + if (error) + return error; + + buf = (char *)xmalloc(strlen("SETPROMPT ") + strlen(pin->prompt) + 1); + sprintf(buf, "SETPROMPT %s", pin->prompt); + error = pinentry_command(pin, NULL, buf); + xfree(buf); + + if (error) + return error; + + buf = (char *)xmalloc(strlen("SETDESC ") + strlen(pin->title) + 1); + sprintf(buf, "SETDESC %s", pin->title); + error = pinentry_command(pin, NULL, buf); + xfree(buf); + return error; +} + +static void pinentry_disconnect(struct pinentry_s *pin) +{ + if (pin->ctx) + assuan_disconnect(pin->ctx); + + pin->ctx = NULL; + pin->pid = 0; +} + +static gpg_error_t do_getpin(struct pinentry_s *pin, char **result) +{ + gpg_error_t error; + + *result = NULL; + error = pinentry_command(pin, result, "GETPIN"); + + // FIXME + if (error == GPG_ERR_ASS_CANCELED) + return GPG_ERR_ASS_CANCELED; + + if (!*result) + return EPWMD_KEY; + + return 0; +} + +static gpg_error_t getpin(struct pinentry_s *pin, gchar **result, int which) +{ + gpg_error_t error = set_pinentry_strings(pin, which); if (error) { - pinentry_disconnect(pwm); + pinentry_disconnect(pin); return error; } - error = do_getpin(pwm, result); - pinentry_disconnect(pwm); -#endif + error = do_getpin(pin, result); + pinentry_disconnect(pin); return 0; } @@ -53,6 +239,7 @@ gpg_error_t pinentry_fork(assuan_context_t ctx) pid_t pid; pinentry_key_s pk; gsize len; + gchar *result; if (pipe(p) == -1) { error = gpg_error_from_syserror(); @@ -69,7 +256,7 @@ gpg_error_t pinentry_fork(assuan_context_t ctx) return send_error(ctx, error); case 0: close(p[0]); - pk.error = 0; //getpin() + pk.error = getpin(&client->pinentry, &result, 0); #if 0 if (pk.error) { @@ -85,7 +272,8 @@ gpg_error_t pinentry_fork(assuan_context_t ctx) #endif pk.error = 0; - strncpy(pk.key, "test", sizeof(pk.key)); + strncpy(pk.key, result, sizeof(pk.key)); + xfree(result); len = write(p[1], &pk, sizeof(pk)); if (len != sizeof(pk)) @@ -94,9 +282,9 @@ gpg_error_t pinentry_fork(assuan_context_t ctx) // FIXME cleanup? _exit(0); default: - client->pinentry_fd = p[0]; - client->pinentry_pid = pid; - client->pinentry_status = PINENTRY_INIT; + client->pinentry.fd = p[0]; + client->pinentry.pid = pid; + client->pinentry.status = PINENTRY_INIT; break; } diff --git a/src/pwmd.c b/src/pwmd.c index 7f31e12c..47964dd5 100644 --- a/src/pwmd.c +++ b/src/pwmd.c @@ -386,10 +386,10 @@ static void *client_thread(void *data) } else { #ifdef WITH_PINENTRY - if (cl->pinentry_pid && cl->pinentry_status == PINENTRY_INIT) { - pinentry_ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->pinentry_fd); + if (cl->pinentry.pid && cl->pinentry.status == PINENTRY_INIT) { + pinentry_ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->pinentry.fd); pth_event_concat(ev, pinentry_ev, NULL); - cl->pinentry_status = PINENTRY_RUNNING; + cl->pinentry.status = PINENTRY_RUNNING; } #endif @@ -406,13 +406,13 @@ static void *client_thread(void *data) } #ifdef WITH_PINENTRY - if (cl->pinentry_status == PINENTRY_RUNNING) { + if (cl->pinentry.status == PINENTRY_RUNNING) { pth_event_isolate(pinentry_ev); if (pth_event_occurred(pinentry_ev)) { guchar shakey[gcrykeysize]; pinentry_key_s pk; - gsize len = pth_read(cl->pinentry_fd, &pk, sizeof(pk)); + gsize len = pth_read(cl->pinentry.fd, &pk, sizeof(pk)); pth_event_free(pinentry_ev, PTH_FREE_THIS); pinentry_ev = NULL; @@ -431,16 +431,16 @@ static void *client_thread(void *data) gpg_err_make(GPG_ERR_SOURCE_USER_1, rc)); } - cl->pinentry_fd = -1; - cl->pinentry_pid = 0; - cl->pinentry_status = PINENTRY_INIT; + cl->pinentry.fd = -1; + cl->pinentry.pid = 0; + cl->pinentry.status = PINENTRY_INIT; } else if (len == -1) { if (errno != EAGAIN) { log_write("%s", strerror(errno)); - cl->pinentry_fd = -1; - cl->pinentry_pid = 0; - cl->pinentry_status = PINENTRY_INIT; + cl->pinentry.fd = -1; + cl->pinentry.pid = 0; + cl->pinentry.status = PINENTRY_INIT; } } else if (len == 0) { -- 2.11.4.GIT