[RFC PATCH 1/2] Get GPG Agent's socket directly from the agent.
Damien Goutte-Gattat
dgouttegattat at incenp.org
Mon Jan 16 13:26:59 CET 2017
* src/agent.c (agent_connect): Call gpg-connect-agent to get
the socket for a running agent.
* src/get-path.c (get_gpg_connect_agent_path): New function.
* src/support.h (get_gpg_connect_agent_path): New prototype.
* configure.ac: New option --with-gpg-connect-agent-path.
--
This patch replaces all the logic needed to find the socket for
a running GnuPG Agent by a single call to gpg-connect-agent.
This will ensure we will always be able to find the agent,
without having to duplicate the logic already implement in
GnuPG. Gpg-connect-agent will also take care of starting the
agent if it's not already running.
Signed-off-by: Damien Goutte-Gattat <dgouttegattat at incenp.org>
---
configure.ac | 37 +++++++++++++
src/agent.c | 172 ++++++++++++++-------------------------------------------
src/get-path.c | 17 ++++++
src/support.h | 1 +
4 files changed, 95 insertions(+), 132 deletions(-)
diff --git a/configure.ac b/configure.ac
index 1e4137d..8567a3a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -232,12 +232,14 @@ AM_CONDITIONAL(HAVE_LD_VERSION_SCRIPT, test "$have_ld_version_script" = "yes")
GPGSM_DEFAULT=no
GPG_AGENT_DEFAULT=no
+GPG_CONNECT_AGENT_DEFAULT=no
have_w32_system=no
case "${host}" in
*-mingw32*)
# special stuff for Windoze NT
GPGSM_DEFAULT='c:\\gnupg\\gpgsm.exe'
GPG_AGENT_DEFAULT='c:\\gnupg\\gpg-agent.exe'
+ GPG_CONNECT_AGENT_DEFAULT='c:\\gnupg\\gpg-connect-agent.exe'
have_w32_system=yes
;;
*)
@@ -406,6 +408,41 @@ else
fi
AM_CONDITIONAL(HAVE_GPG_AGENT, test "$GPG_AGENT" != "no")
+# GPG_CONNECT_AGENT
+NO_OVERRIDE=no
+AC_ARG_WITH(gpg-connect-agent,
+ AC_HELP_STRING([--with-gpg-connect-agent=PATH],
+ [use gpg-connect-agent binary at PATH]),
+ GPG_CONNECT_AGENT=$withval, NO_OVERRIDE=yes)
+if test "$NO_OVERRIDE" = "yes" || test "$GPG_CONNECT_AGENT" = "yes"; then
+ GPG_CONNECT_AGENT=
+ NO_OVERRIDE=yes
+ if test "$cross_compiling" != "yes"; then
+ AC_PATH_PROG(GPG_CONNECT_AGENT, gpg-connect-agent)
+ fi
+ if test -z "$GPG_CONNECT_AGENT"; then
+ GPG_CONNECT_AGENT="$GPG_CONNECT_AGENT_DEFAULT"
+ fi
+fi
+if test "$GPG_CONNECT_AGENT" = no; then
+ if test "$NO_OVERRIDE" = "yes"; then
+ if test "$cross_compiling" != "yes"; then
+ AC_MSG_WARN([
+***
+*** Could not find gpg-connect-agent, use --with-gpg-connect-agent=PATH to enable it
+***])
+ else
+ AC_MSG_WARN([
+***
+*** Can not determine path to gpg-connect-agent when cross-compiling, use --with-gpg-connect-agent=PATH
+***])
+ fi
+ fi
+else
+ AC_DEFINE_UNQUOTED(GPG_CONNECT_AGENT_PATH, "$GPG_CONNECT_AGENT",
+ [Path to the GPG_CONNECT_AGENT binary.])
+fi
+
# Checks for header files.
AC_HEADER_STDC
diff --git a/src/agent.c b/src/agent.c
index 75d4933..6ee106c 100644
--- a/src/agent.c
+++ b/src/agent.c
@@ -233,151 +233,59 @@ spawn_process_detached (const char *pgmname, const char *argv[])
static gpg_error_t
agent_connect (assuan_context_t *ctx_r)
{
- /* If we ever failed to connect via a socket we will force the use
- of the pipe based server for the lifetime of the process. */
- static int force_pipe_server = 0;
-
gpg_error_t err = 0;
- char *infostr;
- char *ptr;
assuan_context_t ctx = NULL;
+ char buffer[255];
+ FILE *p;
- err = assuan_new (&ctx);
- if (err)
- return err;
-
- restart:
-
- infostr = force_pipe_server ? NULL : getenv ("GPG_AGENT_INFO");
- if (!infostr || !*infostr)
- {
- char *sockname;
-
- /* First check whether we can connect at the standard
- socket. */
- sockname = make_filename (default_homedir (), "S.gpg-agent", NULL);
- if (! sockname)
- return gpg_error_from_errno (errno);
-
- err = assuan_socket_connect (ctx, sockname, 0, 0);
- if (err)
- {
- const char *agent_program;
-
- /* With no success start a new server. */
- DEBUG (DBG_INFO, "no running GPG agent at %s, starting one\n",
- sockname);
-
- agent_program = get_gpg_agent_path ();
-
+ /* Use gpg-connect-agent to obtain the socket name
+ * directly from the agent itself. */
+ snprintf (buffer, sizeof buffer, "%s 'GETINFO socket_name' /bye",
+ get_gpg_connect_agent_path ());
#ifdef HAVE_W32_SYSTEM
- {
- /* Under Windows we start the server in daemon mode. This
- is because the default is to use the standard socket
- and thus there is no need for the GPG_AGENT_INFO
- envvar. This is possible as we don't have a real unix
- domain socket but use a plain file and thus there is no
- need to care about non-local file systems. */
- const char *argv[3];
-
- argv[0] = "--daemon";
- argv[1] = "--use-standard-socket";
- argv[2] = NULL;
-
- err = spawn_process_detached (agent_program, argv);
- if (err)
- DEBUG (DBG_CRIT, "failed to start agent `%s': %s\n",
- agent_program, gpg_strerror (err));
- else
- {
- /* Give the agent some time to prepare itself. */
- Sleep (3 * 1000);
- /* Now try again to connect the agent. */
- err = assuan_socket_connect (ctx_r, sockname, 0, 0);
- }
- }
-#else /*!HAVE_W32_SYSTEM*/
- {
- const char *pgmname;
- const char *argv[3];
- int no_close_list[3];
- int i;
-
- if ( !(pgmname = strrchr (agent_program, '/')))
- pgmname = agent_program;
- else
- pgmname++;
-
- argv[0] = pgmname;
- argv[1] = "--server";
- argv[2] = NULL;
-
- i=0;
- no_close_list[i++] = assuan_fd_from_posix_fd (fileno (stderr));
- no_close_list[i] = -1;
-
- /* Connect to the agent and perform initial handshaking. */
- err = assuan_pipe_connect (ctx, agent_program, argv,
- no_close_list, NULL, NULL, 0);
- }
-#endif /*!HAVE_W32_SYSTEM*/
- }
- free (sockname);
- }
- else
+ p = _popen (buffer, "r");
+#else
+ p = popen (buffer, "r");
+#endif
+ if (p)
{
- int pid;
- int protocol_version;
+ int ret;
- infostr = strdup (infostr);
- if (!infostr)
- return gpg_error_from_errno (errno);
-
- if (!(ptr = strchr (infostr, PATHSEP_C)) || ptr == infostr)
- {
- DEBUG (DBG_CRIT, "malformed GPG_AGENT_INFO environment variable");
- free (infostr);
- force_pipe_server = 1;
- goto restart;
- }
-
- *(ptr++) = 0;
- pid = atoi (ptr);
- while (*ptr && *ptr != PATHSEP_C)
- ptr++;
- protocol_version = *ptr ? atoi (ptr + 1) : 0;
- if (protocol_version != 1)
- {
- DEBUG (DBG_CRIT, "GPG agent protocol version '%d' not supported",
- protocol_version);
- free (infostr);
- force_pipe_server = 1;
- goto restart;
- }
+ ret = fscanf (p, "D %254s\nOK\n", buffer);
+ if (ret == EOF) /* I/O error? */
+ err = gpg_error_from_errno (errno);
+ else if (ret != 1) /* Unexpected reply */
+ err = gpg_error (GPG_ERR_NO_AGENT);
- err = assuan_socket_connect (ctx, infostr, pid, 0);
- free (infostr);
- if (err)
- {
- DEBUG (DBG_CRIT, "cannot connect to GPG agent: %s", gpg_strerror (err));
- force_pipe_server = 1;
- goto restart;
- }
+ pclose (p);
}
+ else
+ err = gpg_error_from_errno (errno);
- if (err)
+ /* Then connect to the socket we got. */
+ if (!err)
{
- assuan_release (ctx);
- DEBUG (DBG_CRIT, "cannot connect to GPG agent: %s", gpg_strerror (err));
- return gpg_error (GPG_ERR_NO_AGENT);
+ err = assuan_new (&ctx);
+ if (!err)
+ {
+ err = assuan_socket_connect (ctx, buffer, 0, 0);
+ if (!err)
+ {
+ *ctx_r = ctx;
+ if (_scute_debug_flags & DBG_ASSUAN)
+ assuan_set_log_stream (*ctx_r, _scute_debug_stream);
+ }
+ else
+ assuan_release (ctx);
+ }
}
- if (_scute_debug_flags & DBG_ASSUAN)
- assuan_set_log_stream (*ctx_r, _scute_debug_stream);
-
- *ctx_r = ctx;
+ /* We do not try any harder. If gpg-connect-agent somehow failed
+ * to give us a suitable socket, we probably cannot do better. */
+ if (err)
+ DEBUG (DBG_CRIT, "cannot connect to GPG agent: %s", gpg_strerror (err));
- return 0;
+ return err;
}
diff --git a/src/get-path.c b/src/get-path.c
index 0abd863..cb0a136 100644
--- a/src/get-path.c
+++ b/src/get-path.c
@@ -335,6 +335,23 @@ get_gpg_agent_path (void)
}
+const char *
+get_gpg_connect_agent_path (void)
+{
+ static const char *pgmname;
+
+#ifdef HAVE_W32_SYSTEM
+ if (!pgmname)
+ pgmname = find_program_in_inst_dir ("gpg-connect-agent.exe");
+ if (!pgmname)
+ pgmname = find_program_at_standard_place ("GNU\\GnuPG\\gpg-connect-agent.exe");
+#endif
+ if (!pgmname)
+ pgmname = GPG_CONNECT_AGENT_PATH;
+ return pgmname;
+}
+
+
/* Home directory. */
diff --git a/src/support.h b/src/support.h
index 3356224..739d124 100644
--- a/src/support.h
+++ b/src/support.h
@@ -85,6 +85,7 @@ stpcpy (char *a, const char *b)
const char *get_gpgsm_path (void);
const char *get_gpg_agent_path (void);
+const char *get_gpg_connect_agent_path (void);
/* Set up the default home directory. The usual --homedir option
should be parsed later. */
--
2.9.0
More information about the Gnupg-devel
mailing list