2003-03-01 Joe Shaw <joe@ximian.com>
authorJoe Shaw <joeshaw@novell.com>
Sat, 1 Mar 2003 20:50:18 +0000 (20:50 +0000)
committerJoe Shaw <joeshaw@novell.com>
Sat, 1 Mar 2003 20:50:18 +0000 (20:50 +0000)
* configure.in: Check for "struct cmsgcred" and try to access its
members for BSD-like unices.

* dbus/dbus-sysdeps.c (read_credentials_byte): Fold this back into
_dbus_read_credentials_unix_socket().
(_dbus_read_credentials_unix_socket): Use recvmsg() instead of
read() for reading the credential byte off the unix socket.  Use
struct cmsgcred on systems that support it.

ChangeLog
configure.in
dbus/dbus-sysdeps.c

index f533891..e816027 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2003-03-01  Joe Shaw  <joe@ximian.com>
+
+       * configure.in: Check for "struct cmsgcred" and try to access its
+       members for BSD-like unices.
+
+       * dbus/dbus-sysdeps.c (read_credentials_byte): Fold this back into
+       _dbus_read_credentials_unix_socket().
+       (_dbus_read_credentials_unix_socket): Use recvmsg() instead of
+       read() for reading the credential byte off the unix socket.  Use
+       struct cmsgcred on systems that support it.
+
 2003-02-27  Alexander Larsson  <alexl@redhat.com>
 
        * glib/Makefile.am: 
index 9b969ba..86db3cf 100644 (file)
@@ -200,6 +200,21 @@ if test x$dbus_have_gnuc_varargs = xyes; then
     AC_DEFINE(HAVE_GNUC_VARARGS,1,[Have GNU-style varargs macros])
 fi
 
+dnl Check for various credentials.
+AC_MSG_CHECKING(for struct cmsgcred)
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/socket.h>
+],[
+struct cmsgcred cred;
+
+cred.cmcred_pid = 0;
+],dbus_have_struct_cmsgcred=yes,dbus_have_struct_cmsgcred=no)
+AC_MSG_RESULT($dbus_have_struct_cmsgcred)
+
+if test x$dbus_have_struct_cmsgcred = xyes; then
+    AC_DEFINE(HAVE_CMSGCRED,1,[Have cmsgcred structure])
+fi
 
 DBUS_CLIENT_CFLAGS=
 DBUS_CLIENT_LIBS=
index 4d610a4..2310b00 100644 (file)
@@ -579,53 +579,6 @@ _dbus_listen_tcp_socket (const char     *host,
   return listen_fd;
 }
 
-/* try to read a single byte and return #TRUE if we read it
- * and it's equal to nul.
- */
-static dbus_bool_t
-read_credentials_byte (int             client_fd,
-                       DBusResultCode *result)
-{
-  char buf[1];
-  int bytes_read;
-
- again:
-  bytes_read = read (client_fd, buf, 1);
-  if (bytes_read < 0)
-    {
-      if (errno == EINTR)
-        goto again;
-      else
-        {
-          dbus_set_result (result, _dbus_result_from_errno (errno));      
-          _dbus_verbose ("Failed to read credentials byte: %s\n",
-                         _dbus_strerror (errno));
-          return FALSE;
-        }
-    }
-  else if (bytes_read == 0)
-    {
-      dbus_set_result (result, DBUS_RESULT_IO_ERROR);
-      _dbus_verbose ("EOF reading credentials byte\n");
-      return FALSE;
-    }
-  else
-    {
-      _dbus_assert (bytes_read == 1);
-
-      if (buf[0] != '\0')
-        {
-          dbus_set_result (result, DBUS_RESULT_FAILED);
-          _dbus_verbose ("Credentials byte was not nul\n");
-          return FALSE;
-        }
-
-      _dbus_verbose ("read credentials byte\n");
-      
-      return TRUE;
-    }
-}
-
 static dbus_bool_t
 write_credentials_byte (int             server_fd,
                         DBusResultCode *result)
@@ -684,40 +637,110 @@ _dbus_read_credentials_unix_socket  (int              client_fd,
                                      DBusCredentials *credentials,
                                      DBusResultCode  *result)
 {
+  struct msghdr msg;
+  struct iovec iov;
+  char buf;
+
+#ifdef HAVE_CMSGCRED 
+  char cmsgmem[CMSG_SPACE (sizeof (struct cmsgcred))];
+  struct cmsghdr *cmsg = (struct cmsghdr *) cmsgmem;
+#endif
+
   credentials->pid = -1;
   credentials->uid = -1;
   credentials->gid = -1;
-  
-  if (read_credentials_byte (client_fd, result))
+
+#if defined(LOCAL_CREDS) && defined(HAVE_CMSGCRED)
+  /* Set the socket to receive credentials on the next message */
+  {
+    int on = 1;
+    if (setsockopt (client_fd, 0, LOCAL_CREDS, &on, sizeof (on)) < 0)
+      {
+       _dbus_verbose ("Unable to set LOCAL_CREDS socket option\n");
+       return FALSE;
+      }
+  }
+#endif
+
+  iov.iov_base = &buf;
+  iov.iov_len = 1;
+
+  memset (&msg, 0, sizeof (msg));
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+
+#ifdef HAVE_CMSGCRED
+  memset (cmsgmem, 0, sizeof (cmsgmem));
+  msg.msg_control = cmsgmem;
+  msg.msg_controllen = sizeof (cmsgmem);
+#endif
+
+ again:
+  if (recvmsg (client_fd, &msg, 0) < 0)
     {
+      if (errno == EINTR)
+       goto again;
+
+      dbus_set_result (result, _dbus_result_from_errno (errno));
+      _dbus_verbose ("Failed to read credentials byte: %s\n",
+                    _dbus_strerror (errno));
+      return FALSE;
+    }
+
+  if (buf != '\0')
+    {
+      dbus_set_result (result, DBUS_RESULT_FAILED);
+      _dbus_verbose ("Credentials byte was not nul\n");
+      return FALSE;
+    }
+
+#ifdef HAVE_CMSGCRED
+  if (cmsg->cmsg_len < sizeof (cmsgmem) || cmsg->cmsg_type != SCM_CREDS)
+    {
+      dbus_set_result (result, DBUS_RESULT_FAILED);
+      _dbus_verbose ("Message from recvmsg() was not SCM_CREDS\n");
+      return FALSE;
+    }
+#endif
+
+  _dbus_verbose ("read credentials byte\n");
+
+  {
 #ifdef SO_PEERCRED
-      struct ucred cr;   
-      int cr_len = sizeof (cr);
+    struct ucred cr;   
+    int cr_len = sizeof (cr);
    
-      if (getsockopt (client_fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) == 0 &&
-          cr_len == sizeof (cr))
-        {
-          credentials->pid = cr.pid;
-          credentials->uid = cr.uid;
-          credentials->gid = cr.gid;
-          _dbus_verbose ("Got credentials pid %d uid %d gid %d\n",
-                         credentials->pid,
-                         credentials->uid,
-                         credentials->gid);
-        }
-      else
-        {
-          _dbus_verbose ("Failed to getsockopt() credentials, returned len %d/%d: %s\n",
-                         cr_len, (int) sizeof (cr), _dbus_strerror (errno));
-        }
-#else /* !SO_PEERCRED */
-      _dbus_verbose ("Socket credentials not supported on this OS\n");
+    if (getsockopt (client_fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) == 0 &&
+       cr_len == sizeof (cr))
+      {
+       credentials->pid = cr.pid;
+       credentials->uid = cr.uid;
+       credentials->gid = cr.gid;
+      }
+    else
+      {
+       _dbus_verbose ("Failed to getsockopt() credentials, returned len %d/%d: %s\n",
+                      cr_len, (int) sizeof (cr), _dbus_strerror (errno));
+      }
+#elif defined(HAVE_CMSGCRED)
+    struct cmsgcred *cred;
+
+    cred = (struct cmsgcred *) CMSG_DATA (cmsg);
+
+    credentials->pid = cred->cmcred_pid;
+    credentials->uid = cred->cmcred_euid;
+    credentials->gid = cred->cmcred_groups[0];
+#else /* !SO_PEERCRED && !HAVE_CMSGCRED */
+    _dbus_verbose ("Socket credentials not supported on this OS\n");
 #endif
+  }
 
-      return TRUE;
-    }
-  else
-    return FALSE;
+  _dbus_verbose ("Credentials: pid %d  uid %d  gid %d\n",
+                credentials->pid,
+                credentials->uid,
+                credentials->gid);
+    
+  return TRUE;
 }
 
 /**