agent: Tell the Pinentry the client's pid.
authorWerner Koch <wk@gnupg.org>
Fri, 3 Feb 2017 16:13:08 +0000 (17:13 +0100)
committerWerner Koch <wk@gnupg.org>
Fri, 3 Feb 2017 16:13:08 +0000 (17:13 +0100)
* 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>
agent/agent.h
agent/call-pinentry.c
agent/command-ssh.c
agent/command.c
configure.ac

index 2db5a5c..2178384 100644 (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;
index 2bebee2..384b23a 100644 (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
index f57bac3..1d4453c 100644 (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)
index a2d4931..c8b34e9 100644 (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)
index 75bed06..ce02d03 100644 (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
 #