Implement NetBSD credentials-passing with LOCAL_PEEREID
authorPatrick Welche <prlw1@cam.ac.uk>
Tue, 29 Jul 2014 13:08:20 +0000 (14:08 +0100)
committerSimon McVittie <simon.mcvittie@collabora.co.uk>
Thu, 6 Nov 2014 14:29:50 +0000 (14:29 +0000)
Bug: https://bugs.freedesktop.org/show_bug.cgi?id=69702
Reviewed-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
Reviewed-by: Alban Crequy <alban.crequy@collabora.co.uk>
Tested-by: Patrick Welche <prlw1@cam.ac.uk>
bus/dispatch.c
configure.ac
dbus/dbus-sysdeps-unix.c
test/dbus-daemon.c

index fa2cc96..8f322f8 100644 (file)
@@ -1312,6 +1312,11 @@ check_get_connection_unix_process_id (BusContext     *context,
 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
           defined(__linux__) || \
           defined(__OpenBSD__)
+          /* In principle NetBSD should also be in that list, but
+           * its implementation of PID-passing doesn't work
+           * over a socketpair() as used in the debug-pipe transport.
+           * We test this functionality in a more realistic situation
+           * in test/dbus-daemon.c. */
           warn_unexpected (connection, message, "not this error");
 
           goto out;
index de34d3e..ae2c01c 100644 (file)
@@ -818,6 +818,11 @@ if test x$dbus_have_struct_cmsgcred = xyes; then
     AC_DEFINE(HAVE_CMSGCRED,1,[Have cmsgcred structure])
 fi
 
+AC_CHECK_MEMBER([struct unpcbid.unp_pid],
+                [AC_DEFINE([HAVE_UNPCBID], 1, [Have unpcbid structure])],
+                [],
+                [[#include <sys/un.h>]])
+
 AC_CHECK_FUNCS(getpeerucred getpeereid)
 
 AC_CHECK_FUNCS(pipe2 accept4)
index b89c695..f4a42d8 100644 (file)
@@ -1797,16 +1797,41 @@ _dbus_read_credentials_socket  (int              client_fd,
 #endif
     int cr_len = sizeof (cr);
 
-    if (getsockopt (client_fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) == 0 &&
-       cr_len == sizeof (cr))
+    if (getsockopt (client_fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) != 0)
       {
-       pid_read = cr.pid;
-       uid_read = cr.uid;
+        _dbus_verbose ("Failed to getsockopt(SO_PEERCRED): %s\n",
+                       _dbus_strerror (errno));
+      }
+    else if (cr_len != sizeof (cr))
+      {
+        _dbus_verbose ("Failed to getsockopt(SO_PEERCRED), returned %d bytes, expected %d\n",
+                       cr_len, (int) sizeof (cr));
+      }
+    else
+      {
+        pid_read = cr.pid;
+        uid_read = cr.uid;
+      }
+#elif defined(HAVE_UNPCBID) && defined(LOCAL_PEEREID)
+    /* Another variant of the above - used on NetBSD
+     */
+    struct unpcbid cr;
+    socklen_t cr_len = sizeof (cr);
+
+    if (getsockopt (client_fd, 0, LOCAL_PEEREID, &cr, &cr_len) != 0)
+      {
+        _dbus_verbose ("Failed to getsockopt(LOCAL_PEEREID): %s\n",
+                       _dbus_strerror (errno));
+      }
+    else if (cr_len != sizeof (cr))
+      {
+        _dbus_verbose ("Failed to getsockopt(LOCAL_PEEREID), returned %d bytes, expected %d\n",
+                       cr_len, (int) sizeof (cr));
       }
     else
       {
-       _dbus_verbose ("Failed to getsockopt() credentials, returned len %d/%d: %s\n",
-                      cr_len, (int) sizeof (cr), _dbus_strerror (errno));
+        pid_read = cr.unp_pid;
+        uid_read = cr.unp_euid;
       }
 #elif defined(HAVE_CMSGCRED)
     /* We only check for HAVE_CMSGCRED, but we're really assuming that the
index 43f3445..3b8e134 100644 (file)
@@ -568,6 +568,60 @@ test_creds (Fixture *f,
 }
 
 static void
+test_processid (Fixture *f,
+    gconstpointer context)
+{
+  const char *unique = dbus_bus_get_unique_name (f->left_conn);
+  DBusMessage *m = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
+      DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "GetConnectionUnixProcessID");
+  DBusPendingCall *pc;
+  DBusError error = DBUS_ERROR_INIT;
+  guint32 pid;
+
+  if (m == NULL)
+    g_error ("OOM");
+
+  if (!dbus_message_append_args (m,
+        DBUS_TYPE_STRING, &unique,
+        DBUS_TYPE_INVALID))
+    g_error ("OOM");
+
+  if (!dbus_connection_send_with_reply (f->left_conn, m, &pc,
+                                        DBUS_TIMEOUT_USE_DEFAULT) ||
+      pc == NULL)
+    g_error ("OOM");
+
+  dbus_message_unref (m);
+  m = NULL;
+
+  if (dbus_pending_call_get_completed (pc))
+    pending_call_store_reply (pc, &m);
+  else if (!dbus_pending_call_set_notify (pc, pending_call_store_reply,
+                                          &m, NULL))
+    g_error ("OOM");
+
+  while (m == NULL)
+    test_main_context_iterate (f->ctx, TRUE);
+
+  g_assert_cmpstr (dbus_message_get_signature (m), ==, "u");
+
+  g_assert_true (dbus_message_get_args (m, &error,
+                                        DBUS_TYPE_UINT32, &pid,
+                                        DBUS_TYPE_INVALID));
+// g_assert_no_error (&error);
+
+  g_message ("GetConnectionUnixProcessID returned %u", pid);
+
+#ifdef G_OS_UNIX
+  g_assert_cmpuint (pid, ==, getpid ());
+#elif defined(G_OS_WIN32)
+  g_assert_cmpuint (pid, ==, GetCurrentProcessId ());
+#else
+  g_assert_not_reached ();
+#endif
+}
+
+static void
 teardown (Fixture *f,
     gconstpointer context G_GNUC_UNUSED)
 {
@@ -632,6 +686,7 @@ main (int argc,
   g_test_add ("/no-reply/timeout", Fixture, &finite_timeout_config,
       setup, test_no_reply, teardown);
   g_test_add ("/creds", Fixture, NULL, setup, test_creds, teardown);
+  g_test_add ("/processid", Fixture, NULL, setup, test_processid, teardown);
 
   return g_test_run ();
 }