agent: Tell the Pinentry the client's pid.

* configure.ac: Check for SO_PEERCRED et al.
* agent/agent.h (server_control_s): Add field 'client_pid'.
* agent/command.c (start_command_handler): Set CLIENT_PID.
* agent/command-ssh.c (get_client_pid): New.
(start_command_handler_ssh): Set CLIENT_PID.
* agent/call-pinentry.c (start_pinentry): Tell Pinentry the client-pid.

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2017-02-03 17:13:08 +01:00
parent 7052a0d77c
commit 309f464a59
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
5 changed files with 110 additions and 1 deletions

View File

@ -218,6 +218,7 @@ struct server_control_s
session_env_t session_env;
char *lc_ctype;
char *lc_messages;
unsigned long client_pid;
/* The current pinentry mode. */
pinentry_mode_t pinentry_mode;

View File

@ -540,6 +540,20 @@ start_pinentry (ctrl_t ctrl)
}
}
/* Tell Pinentry about our client. */
if (ctrl->client_pid)
{
char *optstr;
if ((optstr = xtryasprintf ("OPTION owner=%lu", ctrl->client_pid)))
{
assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
NULL);
/* We ignore errors because this is just a fancy thing and
older pinentries do not support this feature. */
xfree (optstr);
}
}
/* Ask the pinentry for its version and flavor and store that as a
* string in MB. This information is useful for helping users to

View File

@ -3491,6 +3491,44 @@ ssh_request_process (ctrl_t ctrl, estream_t stream_sock)
}
/* Return the peer's pid. Stripped down code from libassuan. */
static unsigned long
get_client_pid (int fd)
{
pid_t client_pid = (pid_t)(-1);
#ifdef HAVE_SO_PEERCRED
{
struct ucred cr;
socklen_t cl = sizeof cr;
if ( !getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &cr, &cl))
client_pid = cr.pid;
}
#elif defined (HAVE_GETPEERUCRED)
{
ucred_t *ucred = NULL;
if (getpeerucred (fd, &ucred) != -1)
{
client_pid= ucred_getpid (ucred);
ucred_free (ucred);
}
}
#elif defined (HAVE_LOCAL_PEEREID)
{
struct unpcbid unp;
socklen_t unpl = sizeof unp;
if (getsockopt (fd, 0, LOCAL_PEEREID, &unp, &unpl) != -1)
client_pid = unp.unp_pid;
}
#endif
return client_pid == (pid_t)(-1)? 0 : (unsigned long)client_pid;
}
/* Start serving client on SOCK_CLIENT. */
void
start_command_handler_ssh (ctrl_t ctrl, gnupg_fd_t sock_client)
@ -3503,6 +3541,8 @@ start_command_handler_ssh (ctrl_t ctrl, gnupg_fd_t sock_client)
if (err)
goto out;
ctrl->client_pid = get_client_pid (FD2INT(sock_client));
/* Create stream from socket. */
stream_sock = es_fdopen (FD2INT(sock_client), "r+");
if (!stream_sock)

View File

@ -3288,6 +3288,8 @@ start_command_handler (ctrl_t ctrl, gnupg_fd_t listen_fd, gnupg_fd_t fd)
for (;;)
{
pid_t client_pid;
rc = assuan_accept (ctx);
if (gpg_err_code (rc) == GPG_ERR_EOF || rc == -1)
{
@ -3299,7 +3301,12 @@ start_command_handler (ctrl_t ctrl, gnupg_fd_t listen_fd, gnupg_fd_t fd)
break;
}
ctrl->server_local->connect_from_self = (assuan_get_pid (ctx)==getpid ());
client_pid = assuan_get_pid (ctx);
ctrl->server_local->connect_from_self = (client_pid == getpid ());
if (client_pid != ASSUAN_INVALID_PID)
ctrl->client_pid = (unsigned long)client_pid;
else
ctrl->client_pid = 0;
rc = assuan_process (ctx);
if (rc)

View File

@ -1375,6 +1375,53 @@ if test $ac_cv_func_mmap != yes -a $mmap_needed = yes; then
AC_MSG_ERROR([[Sorry, the current implemenation requires mmap.]])
fi
#
# Check for the getsockopt SO_PEERCRED
# (This has been copied from libassuan)
#
AC_MSG_CHECKING(for SO_PEERCRED)
AC_CACHE_VAL(gnupg_cv_sys_so_peercred,
[AC_TRY_COMPILE([#include <sys/socket.h>],
[struct ucred cr;
int cl = sizeof cr;
getsockopt (1, SOL_SOCKET, SO_PEERCRED, &cr, &cl);],
gnupg_cv_sys_so_peercred=yes,
gnupg_cv_sys_so_peercred=no)
])
AC_MSG_RESULT($gnupg_cv_sys_so_peercred)
if test $gnupg_cv_sys_so_peercred = yes; then
AC_DEFINE(HAVE_SO_PEERCRED, 1,
[Defined if SO_PEERCRED is supported (Linux specific)])
else
# Check for the getsockopt LOCAL_PEEREID (NetBSD)
AC_MSG_CHECKING(for LOCAL_PEEREID)
AC_CACHE_VAL(gnupg_cv_sys_so_local_peereid,
[AC_TRY_COMPILE([#include <sys/socket.>
#include <sys/un.h>],
[struct unpcbid unp;
int unpl = sizeof unp;
getsockopt (1, SOL_SOCKET, LOCAL_PEEREID, &unp, &unpl);],
gnupg_cv_sys_so_local_peereid=yes,
gnupg_cv_sys_so_local_peereid=no)
])
AC_MSG_RESULT($gnupg_cv_sys_so_local_peereid)
if test $gnupg_cv_sys_so_local_peereid = yes; then
AC_DEFINE(HAVE_LOCAL_PEEREID, 1,
[Defined if LOCAL_PEEREID is supported (NetBSD specific)])
else
# (Open)Solaris
AC_CHECK_FUNCS([getpeerucred], AC_CHECK_HEADERS([ucred.h]))
if test $ac_cv_func_getpeerucred != yes; then
# FreeBSD
AC_CHECK_FUNCS([getpeereid])
fi
fi
fi
#
# W32 specific test
#