On 3 May 2017 at 22:35, Stefan Sperling <s...@elego.de> wrote:
> On Wed, May 03, 2017 at 10:05:01PM +0200, Lukas Jirkovsky wrote:
>> New version. Instead of reimplementing the gpg-agent logic, "gpgconf
>> --list-dir agent-socket" is used. If the gpgconf fails, the code falls
>> back to the original solution to stay compatible with old Gnupg
>> versions.
>
> Thanks Lukas, this patch looks good to me.
>
> I have just one minor stylistic nit:
> The local scratch_pool created in your new function is not necessary.
> This code could be simplified further by just using 'pool' throughout.

Hello Stefan,
thank you for comments. Attached is the updated version without scratch_pool.

> In any case, I would not object to having your patch committed as it is.
> The scratch_pool is just a small detail.
>
> It would be good if you could send patches as a unidiff in the future.
> 'svn diff' produces such output by default, and 'diff -u' works, too.

No problem, will do. I was just blindly following the Patch submission
guidelines from the Community Guide. I like the unified diff output
more as well.
Index: subversion/libsvn_subr/gpg_agent.c
===================================================================
--- subversion/libsvn_subr/gpg_agent.c  (revision 1793701)
+++ subversion/libsvn_subr/gpg_agent.c  (working copy)
@@ -64,10 +64,13 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 
+#include <apr_file_io.h>
 #include <apr_pools.h>
+#include <apr_strings.h>
 #include "svn_auth.h"
 #include "svn_config.h"
 #include "svn_error.h"
+#include "svn_io.h"
 #include "svn_pools.h"
 #include "svn_cmdline.h"
 #include "svn_checksum.h"
@@ -225,6 +228,46 @@
   close(sd);
 }
 
+/* Find gpg-agent socket location using gpgconf. Returns the path to socket, or
+ * NULL if the socket path cannot be determined using gpgconf.
+ */
+static const char *
+find_gpgconf_agent_socket(apr_pool_t *pool)
+{
+  apr_proc_t proc;
+  svn_stringbuf_t *line;
+  svn_error_t *err;
+  const char *gpgargv[] = { "gpgconf", "--list-dir", "agent-socket", NULL };
+
+  /* execute "gpgconf --list-dir agent-socket" */
+  err = svn_io_start_cmd3(&proc, NULL, "gpgconf", (const char* const*)gpgargv,
+                          NULL, TRUE, FALSE, NULL, TRUE, NULL, FALSE, NULL,
+                          pool);
+  if (err != SVN_NO_ERROR)
+    {
+      svn_error_clear(err);
+      return NULL;
+    }
+
+  /* read the gpgconf output */
+  err = svn_io_file_readline(proc.out, &line, NULL, NULL, APR_SIZE_MAX,
+                             pool, pool);
+  if (err != SVN_NO_ERROR)
+    {
+      svn_error_clear(err);
+      return NULL;
+    }
+  apr_file_close(proc.out);
+  err = svn_io_wait_for_cmd(&proc, "gpgconf", NULL, NULL, pool);
+  if (err != SVN_NO_ERROR)
+    {
+      svn_error_clear(err);
+      return NULL;
+    }
+
+  return line->data;
+}
+
 /* Locate a running GPG Agent, and return an open file descriptor
  * for communication with the agent in *NEW_SD. If no running agent
  * can be found, set *NEW_SD to -1. */
@@ -242,37 +285,43 @@
 
   *new_sd = -1;
 
-  /* This implements the method of finding the socket as described in
-   * the gpg-agent man page under the --use-standard-socket option.
-   * The manage page says the standard socket is "named 'S.gpg-agent' located
-   * in the home directory."  GPG's home directory is either the directory
-   * specified by $GNUPGHOME or ~/.gnupg. */
-  gpg_agent_info = getenv("GPG_AGENT_INFO");
-  if (gpg_agent_info != NULL)
-    {
-      apr_array_header_t *socket_details;
+  /* Query socket location using gpgconf if possible */
+  socket_name = find_gpgconf_agent_socket(pool);
 
-      /* For reference GPG_AGENT_INFO consists of 3 : separated fields.
-       * The path to the socket, the pid of the gpg-agent process and
-       * finally the version of the protocol the agent talks. */
-      socket_details = svn_cstring_split(gpg_agent_info, ":", TRUE,
-                                         pool);
-      socket_name = APR_ARRAY_IDX(socket_details, 0, const char *);
-    }
-  else if ((gnupghome = getenv("GNUPGHOME")) != NULL)
-    {
-      const char *homedir = svn_dirent_canonicalize(gnupghome, pool);
-      socket_name = svn_dirent_join(homedir, "S.gpg-agent", pool);
-    }
-  else
+  /* fallback to the old method used with Gnupg 1.x */
+  if (socket_name == NULL)
     {
-      const char *homedir = svn_user_get_homedir(pool);
+      /* This implements the method of finding the socket as described in
+       * the gpg-agent man page under the --use-standard-socket option.
+       * The manage page says the standard socket is "named 'S.gpg-agent' 
located
+       * in the home directory."  GPG's home directory is either the directory
+       * specified by $GNUPGHOME or ~/.gnupg. */
+      if ((gpg_agent_info = getenv("GPG_AGENT_INFO")) != NULL)
+        {
+          apr_array_header_t *socket_details;
 
-      if (!homedir)
-        return SVN_NO_ERROR;
+          /* For reference GPG_AGENT_INFO consists of 3 : separated fields.
+           * The path to the socket, the pid of the gpg-agent process and
+           * finally the version of the protocol the agent talks. */
+          socket_details = svn_cstring_split(gpg_agent_info, ":", TRUE,
+                                             pool);
+          socket_name = APR_ARRAY_IDX(socket_details, 0, const char *);
+        }
+      else if ((gnupghome = getenv("GNUPGHOME")) != NULL)
+        {
+          const char *homedir = svn_dirent_canonicalize(gnupghome, pool);
+          socket_name = svn_dirent_join(homedir, "S.gpg-agent", pool);
+        }
+      else
+        {
+          const char *homedir = svn_user_get_homedir(pool);
 
-      socket_name = svn_dirent_join_many(pool, homedir, ".gnupg",
-                                         "S.gpg-agent", SVN_VA_NULL);
+          if (!homedir)
+            return SVN_NO_ERROR;
+
+          socket_name = svn_dirent_join_many(pool, homedir, ".gnupg",
+                                             "S.gpg-agent", SVN_VA_NULL);
+        }
     }
 
   if (socket_name != NULL)

Reply via email to