]> git.ipfire.org Git - thirdparty/dbus.git/commitdiff
Add infrastructure to run bits of tests under an alternative uid
authorSimon McVittie <simon.mcvittie@collabora.co.uk>
Mon, 26 Jan 2015 15:47:59 +0000 (15:47 +0000)
committerSimon McVittie <simon.mcvittie@collabora.co.uk>
Tue, 3 Feb 2015 16:19:05 +0000 (16:19 +0000)
Bug: https://bugs.freedesktop.org/show_bug.cgi?id=88810
Reviewed-by: Philip Withnall
configure.ac
test/dbus-daemon-eavesdrop.c
test/dbus-daemon.c
test/test-utils-glib.c
test/test-utils-glib.h

index b9b3ce3c6fce2cedad5a364e6efd87ea53d02b40..6deb80066198f4e3728fcc2ec747e5d88381e22e 100644 (file)
@@ -168,6 +168,9 @@ AC_ARG_WITH(console-auth-dir, AS_HELP_STRING([--with-console-auth-dir=[dirname]]
 AC_ARG_WITH(console-owner-file, AS_HELP_STRING([--with-console-owner-file=[filename]],[file whose owner determines current console owner]))
 AC_ARG_WITH(launchd-agent-dir, AS_HELP_STRING([--with-launchd-agent-dir=[dirname]],[directory to put the launchd agent (default: /Library/LaunchAgents)]))
 AC_ARG_WITH(dbus_user, AS_HELP_STRING([--with-dbus-user=<user>],[User for running the DBUS daemon (messagebus)]))
+AC_ARG_WITH([test_user],
+  [AS_HELP_STRING([--with-test-user=<user>],
+    [Unprivileged user for regression tests, other than root and the dbus_user (default: nobody)])])
 AC_ARG_WITH(dbus_daemondir, AS_HELP_STRING([--with-dbus-daemondir=[dirname]],[Directory for installing the DBUS daemon]))
 
 AC_ARG_ENABLE([embedded-tests],
@@ -591,7 +594,7 @@ AC_DEFINE_UNQUOTED([DBUS_USE_SYNC], [$have_sync], [Use the gcc __sync extension]
 AC_SEARCH_LIBS(socket,[socket network])
 AC_CHECK_FUNC(gethostbyname,,[AC_CHECK_LIB(nsl,gethostbyname)])
 
-AC_CHECK_FUNCS([vsnprintf vasprintf nanosleep usleep setenv clearenv unsetenv socketpair getgrouplist fpathconf setrlimit poll setlocale localeconv strtoll strtoull issetugid getresuid getrlimit])
+AC_CHECK_FUNCS([vsnprintf vasprintf nanosleep usleep setenv clearenv unsetenv socketpair getgrouplist fpathconf setrlimit poll setlocale localeconv strtoll strtoull issetugid getresuid setresuid getrlimit])
 
 AC_CHECK_HEADERS([syslog.h])
 if test "x$ac_cv_header_syslog_h" = "xyes"; then
@@ -1575,6 +1578,13 @@ fi
 AC_SUBST(DBUS_USER)
 AC_DEFINE_UNQUOTED(DBUS_USER,"$DBUS_USER", [User for running the system BUS daemon])
 
+#### User for regression tests
+AS_IF([test -z "$with_test_user"], [with_test_user=nobody])
+DBUS_TEST_USER="$with_test_user"
+AC_SUBST([DBUS_TEST_USER])
+AC_DEFINE_UNQUOTED([DBUS_TEST_USER], ["$DBUS_TEST_USER"],
+  [Unprivileged user used in some regression tests])
+
 #### Prefix to install into
 DBUS_PREFIX=$EXPANDED_PREFIX
 AC_SUBST(DBUS_PREFIX)
index 79c1e9036e3f0cc26fc03e7d0329bbdec5f4dc93..686ccb35fbec72d65c738661872e0fa5085be249 100644 (file)
@@ -283,7 +283,7 @@ setup (Fixture *f,
   f->ge = NULL;
   dbus_error_init (&f->e);
 
-  address = test_get_dbus_daemon (NULL, &f->daemon_pid);
+  address = test_get_dbus_daemon (NULL, TEST_USER_ME, &f->daemon_pid);
 
   f->sender = test_connect_to_bus (f->ctx, address);
   dbus_bus_request_name (f->sender, SENDER_NAME, DBUS_NAME_FLAG_DO_NOT_QUEUE,
index 02684646d420e58c23984ff6950bbe04bdc7a221..025909046d9922fa7567a397e90ef540d5e5d58a 100644 (file)
@@ -124,6 +124,7 @@ setup (Fixture *f,
   dbus_error_init (&f->e);
 
   address = test_get_dbus_daemon (config ? config->config_file : NULL,
+                                  TEST_USER_ME,
                                   &f->daemon_pid);
 
   if (address == NULL)
index ce312f54b511c13ed6478c6fb06f53a6782034b3..24f0ee4680bcf7e1dbf7240bc2c500c8acbf115d 100644 (file)
 # include <io.h>
 # include <windows.h>
 #else
+# include <errno.h>
 # include <signal.h>
 # include <unistd.h>
 # include <sys/types.h>
+# include <pwd.h>
 #endif
 
 #include <glib.h>
@@ -53,9 +55,41 @@ _test_assert_no_error (const DBusError *e,
         file, line, e->name, e->message);
 }
 
+#ifdef DBUS_UNIX
+static void
+child_setup (gpointer user_data)
+{
+  const struct passwd *pwd = user_data;
+  uid_t uid = geteuid ();
+
+  if (pwd == NULL || (pwd->pw_uid == uid && getuid () == uid))
+    return;
+
+  if (uid != 0)
+    g_error ("not currently euid 0: %lu", (unsigned long) uid);
+
+  if (setuid (pwd->pw_uid) != 0)
+    g_error ("could not setuid (%lu): %s",
+        (unsigned long) pwd->pw_uid, g_strerror (errno));
+
+  uid = getuid ();
+
+  if (uid != pwd->pw_uid)
+    g_error ("after successful setuid (%lu) my uid is %ld",
+        (unsigned long) pwd->pw_uid, (unsigned long) uid);
+
+  uid = geteuid ();
+
+  if (uid != pwd->pw_uid)
+    g_error ("after successful setuid (%lu) my euid is %ld",
+        (unsigned long) pwd->pw_uid, (unsigned long) uid);
+}
+#endif
+
 static gchar *
 spawn_dbus_daemon (const gchar *binary,
     const gchar *configuration,
+    TestUser user,
     GPid *daemon_pid)
 {
   GError *error = NULL;
@@ -68,13 +102,74 @@ spawn_dbus_daemon (const gchar *binary,
       "--print-address=1", /* stdout */
       NULL
   };
+#ifdef DBUS_UNIX
+  const struct passwd *pwd = NULL;
+#endif
+
+  if (user == TEST_USER_ME)
+    {
+#ifdef DBUS_UNIX
+      if (getuid () == 0)
+        {
+          g_message ("SKIP: this test is not designed to run as root");
+          return NULL;
+        }
+#endif
+    }
+  else
+    {
+#ifdef DBUS_UNIX
+      if (getuid () != 0)
+        {
+          g_message ("SKIP: cannot use alternative uid when not uid 0");
+          return NULL;
+        }
+
+      switch (user)
+        {
+          case TEST_USER_ROOT:
+            break;
+
+          case TEST_USER_MESSAGEBUS:
+            pwd = getpwnam (DBUS_USER);
+
+            if (pwd == NULL)
+              {
+                g_message ("SKIP: user '%s' does not exist", DBUS_USER);
+                return NULL;
+              }
+
+            break;
+
+          case TEST_USER_OTHER:
+            pwd = getpwnam (DBUS_TEST_USER);
+
+            if (pwd == NULL)
+              {
+                g_message ("SKIP: user '%s' does not exist", DBUS_TEST_USER);
+                return NULL;
+              }
+
+            break;
+
+          default:
+            g_assert_not_reached ();
+        }
+#else
+      g_message ("SKIP: cannot use alternative uid on Windows");
+      return NULL;
+#endif
+    }
 
   g_spawn_async_with_pipes (NULL, /* working directory */
       (gchar **) argv, /* g_s_a_w_p() is not const-correct :-( */
       NULL, /* envp */
       G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
-      NULL, /* child_setup */
-      NULL, /* user data */
+#ifdef DBUS_UNIX
+      child_setup, (gpointer) pwd,
+#else
+      NULL, NULL,
+#endif
       daemon_pid,
       NULL, /* child's stdin = /dev/null */
       &address_fd,
@@ -118,6 +213,7 @@ spawn_dbus_daemon (const gchar *binary,
 
 gchar *
 test_get_dbus_daemon (const gchar *config_file,
+                      TestUser     user,
                       GPid        *daemon_pid)
 {
   gchar *dbus_daemon;
@@ -126,12 +222,6 @@ test_get_dbus_daemon (const gchar *config_file,
 
   if (config_file != NULL)
     {
-      if (g_getenv ("DBUS_TEST_DAEMON_ADDRESS") != NULL)
-        {
-          g_message ("SKIP: cannot use DBUS_TEST_DAEMON_ADDRESS for "
-              "unusally-configured dbus-daemon");
-          return NULL;
-        }
 
       if (g_getenv ("DBUS_TEST_DATA") == NULL)
         {
@@ -167,11 +257,20 @@ test_get_dbus_daemon (const gchar *config_file,
 
   if (g_getenv ("DBUS_TEST_DAEMON_ADDRESS") != NULL)
     {
-      address = g_strdup (g_getenv ("DBUS_TEST_DAEMON_ADDRESS"));
+      if (config_file != NULL || user != TEST_USER_ME)
+        {
+          g_message ("SKIP: cannot use DBUS_TEST_DAEMON_ADDRESS for "
+              "unusally-configured dbus-daemon");
+          address = NULL;
+        }
+      else
+        {
+          address = g_strdup (g_getenv ("DBUS_TEST_DAEMON_ADDRESS"));
+        }
     }
   else
     {
-      address = spawn_dbus_daemon (dbus_daemon, arg, daemon_pid);
+      address = spawn_dbus_daemon (dbus_daemon, arg, user, daemon_pid);
     }
 
   g_free (dbus_daemon);
index b233384f8bd180f053544d00e32fb64c31dc0ce4..c672fe509bf7c8e37f884f2c76e56bee16c4796f 100644 (file)
 
 #include "test-utils.h"
 
+/*
+ * Multi-user support for regression tests run with root privileges in
+ * a continuous integration system.
+ *
+ * A developer would normally run the tests as their own uid. Tests run
+ * as TEST_USER_ME are run, and the others are skipped.
+ *
+ * In a CI system that has access to root privileges, most tests should still
+ * be run as an arbitrary non-root user, as above.
+ *
+ * Certain tests can usefully be run again, as root. When this is done,
+ * tests using TEST_USER_ME will be skipped, and tests using TEST_USER_ROOT,
+ * TEST_USER_MESSAGEBUS and/or TEST_USER_OTHER can exercise situations
+ * that only arise when there's more than one uid.
+ */
+typedef enum {
+    /* Whatever non-root user happens to be running the regression test;
+     * such tests also work on Windows */
+    TEST_USER_ME,
+    /* Must be uid 0 on Unix; the test is skipped on Windows */
+    TEST_USER_ROOT,
+    /* The user who would normally run the system bus. This is the DBUS_USER
+     * from configure.ac, usually 'messagebus' but perhaps 'dbus' or
+     * '_dbus'. */
+    TEST_USER_MESSAGEBUS,
+    /* An unprivileged user who is neither root nor DBUS_USER.
+     * This is DBUS_TEST_USER from configure.ac, usually 'nobody'. */
+    TEST_USER_OTHER
+} TestUser;
+
 #define test_assert_no_error(e) _test_assert_no_error (e, __FILE__, __LINE__)
 void _test_assert_no_error (const DBusError *e,
     const char *file,
     int line);
 
 gchar *test_get_dbus_daemon (const gchar *config_file,
+    TestUser user,
     GPid *daemon_pid);
 
 DBusConnection *test_connect_to_bus (TestMainContext *ctx,