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)