diff --git a/agent/agent.h b/agent/agent.h index 2db5a5c74..217838472 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -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; diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c index 2bebee205..384b23a64 100644 --- a/agent/call-pinentry.c +++ b/agent/call-pinentry.c @@ -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 diff --git a/agent/command-ssh.c b/agent/command-ssh.c index f57bac397..1d4453c84 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -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) diff --git a/agent/command.c b/agent/command.c index a2d493167..c8b34e988 100644 --- a/agent/command.c +++ b/agent/command.c @@ -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) diff --git a/configure.ac b/configure.ac index 75bed06c4..ce02d037a 100644 --- a/configure.ac +++ b/configure.ac @@ -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 ], + [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 + #include ], + [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 #