[PATCH] agent: Send pinentry the uid of connecting process where possible.

Daniel Kahn Gillmor dkg at fifthhorseman.net
Sun Feb 5 08:23:30 CET 2017


* agent/agent.h (server_control_s): Add field 'client_uid'.
* agent/call-pinentry.c (start_pinentry): Add uid field to assuan
option "owner" sent to pinentry.
* agent/command-ssh.c (peer_info_s): New static struct.
(get_client_pid): Rename to...
(get_client_info): Here, and extract uid in addition to pid.
(start_command_handler_ssh): Use get_client_info() instead of
get_client_pid().
* agent/command.c (start_command_handler): Use assuan_get_peercred
instead of assuan_get_pid.

--

This requires a concurrent update to pinentry to handle the new uid
field.  Distributing the uid as well as the pid makes it harder for a
different user on the same machine to take advantage of any race
conditions between when a requesting process might ask for something
that needs pinentry, and when pinentry gets around to inspecting the
state of that process.

Signed-off-by: Daniel Kahn Gillmor <dkg at fifthhorseman.net>
---
 agent/agent.h         |  1 +
 agent/call-pinentry.c |  5 +++--
 agent/command-ssh.c   | 29 +++++++++++++++++++++++------
 agent/command.c       | 23 +++++++++++++++++------
 4 files changed, 44 insertions(+), 14 deletions(-)

diff --git a/agent/agent.h b/agent/agent.h
index 217838472..23064a703 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -219,6 +219,7 @@ struct server_control_s
   char *lc_ctype;
   char *lc_messages;
   unsigned long client_pid;
+  int client_uid;
 
   /* The current pinentry mode.  */
   pinentry_mode_t pinentry_mode;
diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c
index 99316653b..9d62b442f 100644
--- a/agent/call-pinentry.c
+++ b/agent/call-pinentry.c
@@ -553,8 +553,9 @@ start_pinentry (ctrl_t ctrl)
         nodename = utsbuf.nodename;
 #endif /*!HAVE_W32_SYSTEM*/
 
-      if ((optstr = xtryasprintf ("OPTION owner=%lu %s",
-                                  ctrl->client_pid, nodename)))
+      if ((optstr = xtryasprintf ("OPTION owner=%lu %d %s",
+                                  ctrl->client_pid, ctrl->client_uid,
+                                  nodename)))
         {
           assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
                            NULL);
diff --git a/agent/command-ssh.c b/agent/command-ssh.c
index 1d4453c84..40fd481ec 100644
--- a/agent/command-ssh.c
+++ b/agent/command-ssh.c
@@ -248,6 +248,11 @@ static gpg_error_t ssh_signature_encoder_eddsa (ssh_key_type_spec_t *spec,
 static gpg_error_t ssh_key_extract_comment (gcry_sexp_t key, char **comment);
 
 
+struct peer_info_s
+{
+  unsigned long pid;
+  int uid;
+};
 
 /* Global variables.  */
 
@@ -3492,10 +3497,12 @@ 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)
+static struct peer_info_s
+get_client_info (int fd)
 {
+  struct peer_info_s out;
   pid_t client_pid = (pid_t)(-1);
+  uid_t client_uid = (uid_t)-1;
 
 #ifdef HAVE_SO_PEERCRED
   {
@@ -3503,7 +3510,10 @@ get_client_pid (int fd)
     socklen_t cl = sizeof cr;
 
     if ( !getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &cr, &cl))
-      client_pid = cr.pid;
+      {
+        client_pid = cr.pid;
+        client_uid = cr.uid;
+      }
   }
 #elif defined (HAVE_GETPEERUCRED)
   {
@@ -3511,7 +3521,8 @@ get_client_pid (int fd)
 
     if (getpeerucred (fd, &ucred) != -1)
       {
-	client_pid= ucred_getpid (ucred);
+	client_pid = ucred_getpid (ucred);
+	client_uid = ucred_geteuid (ucred);
 	ucred_free (ucred);
       }
   }
@@ -3522,10 +3533,13 @@ get_client_pid (int fd)
 
     if (getsockopt (fd, 0, LOCAL_PEEREID, &unp, &unpl) != -1)
       client_pid = unp.unp_pid;
+      client_uid = unp.unp_euid;
   }
 #endif
 
-  return client_pid == (pid_t)(-1)? 0 : (unsigned long)client_pid;
+  out.pid = (client_pid == (pid_t)(-1)? 0 : (unsigned long)client_pid);
+  out.uid = (int)client_uid;
+  return out;
 }
 
 
@@ -3536,12 +3550,15 @@ start_command_handler_ssh (ctrl_t ctrl, gnupg_fd_t sock_client)
   estream_t stream_sock = NULL;
   gpg_error_t err;
   int ret;
+  struct peer_info_s peer_info;
 
   err = agent_copy_startup_env (ctrl);
   if (err)
     goto out;
 
-  ctrl->client_pid = get_client_pid (FD2INT(sock_client));
+  peer_info = get_client_info (FD2INT(sock_client));
+  ctrl->client_pid = peer_info.pid;
+  ctrl->client_uid = peer_info.uid;
 
   /* Create stream from socket.  */
   stream_sock = es_fdopen (FD2INT(sock_client), "r+");
diff --git a/agent/command.c b/agent/command.c
index c8b34e988..1aef6a154 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -3288,7 +3288,7 @@ start_command_handler (ctrl_t ctrl, gnupg_fd_t listen_fd, gnupg_fd_t fd)
 
   for (;;)
     {
-      pid_t client_pid;
+      assuan_peercred_t client_creds;
 
       rc = assuan_accept (ctx);
       if (gpg_err_code (rc) == GPG_ERR_EOF || rc == -1)
@@ -3301,12 +3301,23 @@ start_command_handler (ctrl_t ctrl, gnupg_fd_t listen_fd, gnupg_fd_t fd)
           break;
         }
 
-      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;
+      rc = assuan_get_peercred (ctx, &client_creds);
+      if (rc)
+        {
+          log_info ("Assuan get_peercred failed: %s\n", gpg_strerror (rc));
+          ctrl->client_pid = 0;
+          ctrl->client_uid = -1;
+        }
       else
-        ctrl->client_pid = 0;
+        {
+          ctrl->server_local->connect_from_self =
+            (client_creds->pid == getpid ());
+          if (client_creds->pid != ASSUAN_INVALID_PID)
+            ctrl->client_pid = (unsigned long)client_creds->pid;
+          else
+            ctrl->client_pid = 0;
+          ctrl->client_uid = client_creds->uid;
+        }
 
       rc = assuan_process (ctx);
       if (rc)
-- 
2.11.0




More information about the Gnupg-devel mailing list