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.
[[[
Find gpg-agent socket using gpgconf if possible.
This allows detection of socket with Gnupg >= 2.1.13
which changed the default socket path to /run/user/UID/gnupg
* subversion/libsvn_subr/gpg_agent.c
(find_gpgconf_agent_socket): new function to find
gpg-agent socket using gpgconf
(find_running_gpg_agent): use find_gpgconf_agent_socket
to detect socket when possible.
]]]
Index: libsvn_subr/gpg_agent.c
===================================================================
*** libsvn_subr/gpg_agent.c (revision 1793701)
--- libsvn_subr/gpg_agent.c (working copy)
***************
*** 64,73 ****
--- 64,76 ----
#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"
*************** bye_gpg_agent(int sd)
*** 225,230 ****
--- 228,280 ----
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_pool_t *scratch_pool;
+ apr_proc_t proc;
+ svn_stringbuf_t *line;
+ svn_error_t *err;
+ const char *gpgargv[] = { "gpgconf", "--list-dir", "agent-socket", NULL };
+
+ scratch_pool = svn_pool_create(pool);
+
+ /* 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,
+ scratch_pool);
+ if (err != SVN_NO_ERROR)
+ {
+ svn_pool_destroy(scratch_pool);
+ svn_error_clear(err);
+ return NULL;
+ }
+
+ /* read the gpgconf output */
+ err = svn_io_file_readline(proc.out, &line, NULL, NULL, APR_SIZE_MAX, pool,
+ scratch_pool);
+ if (err != SVN_NO_ERROR)
+ {
+ svn_pool_destroy(scratch_pool);
+ svn_error_clear(err);
+ return NULL;
+ }
+ apr_file_close(proc.out);
+ err = svn_io_wait_for_cmd(&proc, "gpgconf", NULL, NULL, scratch_pool);
+ if (err != SVN_NO_ERROR)
+ {
+ svn_pool_destroy(scratch_pool);
+ svn_error_clear(err);
+ return NULL;
+ }
+
+ svn_pool_destroy(scratch_pool);
+ 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. */
*************** find_running_gpg_agent(int *new_sd, apr_
*** 242,278 ****
*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;
! /* 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);
! 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)
--- 292,334 ----
*new_sd = -1;
! /* Query socket location using gpgconf if possible */
! socket_name = find_gpgconf_agent_socket(pool);
! /* fallback to the old method used with Gnupg 1.x */
! if (socket_name == NULL)
{
! /* 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;
! /* 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);
! 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)