From d64258004b94b1ddbffaf7d6f41789f404f1d271 Mon Sep 17 00:00:00 2001 From: Ben Kibbey Date: Fri, 16 Sep 2016 19:12:33 -0400 Subject: [PATCH] Fix gpg-agent restart for cache commands. --- src/agent.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 130 insertions(+), 5 deletions(-) diff --git a/src/agent.c b/src/agent.c index 365749b2..4d894753 100644 --- a/src/agent.c +++ b/src/agent.c @@ -35,6 +35,7 @@ #endif #include "pwmd-error.h" +#include #include "util-misc.h" #include "mem.h" #include "common.h" @@ -120,6 +121,41 @@ assuan_command (struct agent_s *a, char **result, return rc; } +static char * +get_gpg_connect_agent_path (void) +{ + gpgme_engine_info_t engine; + char *s, *p; + + gpgme_get_engine_info (&engine); + while (engine) + { + if (engine->protocol == GPGME_PROTOCOL_GPGCONF) + break; + + engine = engine->next; + } + + if (!engine) + return NULL; + + s = str_dup (engine->file_name); + if (!s) + return NULL; + + p = strrchr (s, '/'); + if (p) + { + *p = 0; + p = str_asprintf ("%s/gpg-connect-agent", s); + xfree (s); + return p; + } + + xfree (s); + return NULL; +} + gpg_error_t agent_connect (struct agent_s *agent) { @@ -128,11 +164,94 @@ agent_connect (struct agent_s *agent) static struct assuan_malloc_hooks mhooks = { xmalloc, xrealloc, xfree }; agent->did_restart = 0; + if (agent->restart) + { + gpgme_ctx_t gctx; + + rc = gpgme_new (&gctx); + if (!rc) + { + char **args = NULL; + + pthread_cleanup_push ((void *)gpgme_release, gctx); + rc = gpgme_set_protocol (gctx, GPGME_PROTOCOL_SPAWN); + if (!rc && strv_printf (&args, "")) + { + if (!rc && strv_printf (&args, "--homedir")) + { + char *gpghome = config_get_string ("global", "gpg_homedir"); + + if (gpghome) + { + if (!strv_printf (&args, "%s", gpghome)) + rc = GPG_ERR_ENOMEM; + } + else + { + if (!strv_printf (&args, "%s/.gnupg", homedir)) + rc = GPG_ERR_ENOMEM; + } + + xfree (gpghome); + } + else if (!rc) + rc = GPG_ERR_ENOMEM; + } + else if (!rc) + rc = GPG_ERR_ENOMEM; + + pthread_cleanup_push ((void *)strv_free, args); + if (!rc) + { + gpgme_data_t idata = NULL; + size_t len; + char *s; + + rc = gpgme_data_new (&idata); + if (!rc) + { + char *gca = get_gpg_connect_agent_path (); + + pthread_cleanup_push (xfree, gca); + if (gca) + rc = gpgme_op_spawn (gctx, gca, (const char **)args, NULL, + idata, NULL, + GPGME_SPAWN_DETACHED|GPGME_SPAWN_ALLOW_SET_FG); + else + rc = GPG_ERR_ENOMEM; + + pthread_cleanup_pop (1); + } + + if (!rc) + { + ssize_t ret = gpgme_data_write (idata, "/BYE\n", 5); + + if (ret != 5) + rc = gpg_error_from_syserror (); + } + + if (idata) + { + s = gpgme_data_release_and_get_mem (idata, &len); + gpgme_free (s); + } + } + + pthread_cleanup_pop (1); + pthread_cleanup_pop (1); + } + + if (rc) + return rc; + } + rc = assuan_new_ext (&ctx, GPG_ERR_SOURCE_DEFAULT, &mhooks, assuan_log_cb, NULL); if (rc) return rc; + pthread_cleanup_push ((void *)assuan_release, ctx); rc = assuan_socket_connect (ctx, agent->socket, ASSUAN_INVALID_PID, 0); if (!rc) { @@ -147,6 +266,7 @@ agent_connect (struct agent_s *agent) assuan_release (ctx); } + pthread_cleanup_pop (0); return rc; } @@ -156,14 +276,15 @@ send_to_agent (struct agent_s *agent, char **result, size_t *len, { gpg_error_t rc = 0; - if (!agent->ctx) + if (agent->ctx) + rc = assuan_command (agent, result, len, cmd); + else { rc = agent_connect (agent); - if (rc) - return rc; + if (!rc) + rc = assuan_command (agent, result, len, cmd); } - rc = assuan_command (agent, result, len, cmd); if (!agent->restart && gpg_err_source (rc) == GPG_ERR_SOURCE_DEFAULT && (gpg_err_code (rc) == GPG_ERR_ASS_CONNECT_FAILED || gpg_err_code (rc) == GPG_ERR_EPIPE)) @@ -193,7 +314,11 @@ agent_command (struct agent_s *agent, char **result, size_t * len, va_start (ap, fmt); if (str_vasprintf (&cmd, fmt, ap) > 0) - rc = send_to_agent (agent, result, len, cmd); + { + pthread_cleanup_push (xfree, cmd); + rc = send_to_agent (agent, result, len, cmd); + pthread_cleanup_pop (0); + } else rc = GPG_ERR_ENOMEM; -- 2.11.4.GIT