summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon McVittie <simon.mcvittie@collabora.co.uk>2015-01-26 15:47:59 +0000
committerSimon McVittie <simon.mcvittie@collabora.co.uk>2015-02-03 16:19:05 +0000
commit6a49ced2dd3a1e3b161c677deb72d98674a9069d (patch)
tree989889dd95c9b766d05a3adc32bef759b47811f4
parent1e21cc86bfca68d7b5bd564e4c6b086e2a7d242c (diff)
downloaddbus-6a49ced2dd3a1e3b161c677deb72d98674a9069d.tar.gz
dbus-6a49ced2dd3a1e3b161c677deb72d98674a9069d.tar.bz2
dbus-6a49ced2dd3a1e3b161c677deb72d98674a9069d.zip
Add infrastructure to run bits of tests under an alternative uid
Bug: https://bugs.freedesktop.org/show_bug.cgi?id=88810 Reviewed-by: Philip Withnall
-rw-r--r--configure.ac12
-rw-r--r--test/dbus-daemon-eavesdrop.c2
-rw-r--r--test/dbus-daemon.c1
-rw-r--r--test/test-utils-glib.c119
-rw-r--r--test/test-utils-glib.h31
5 files changed, 153 insertions, 12 deletions
diff --git a/configure.ac b/configure.ac
index b9b3ce3c..6deb8006 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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)
diff --git a/test/dbus-daemon-eavesdrop.c b/test/dbus-daemon-eavesdrop.c
index 79c1e903..686ccb35 100644
--- a/test/dbus-daemon-eavesdrop.c
+++ b/test/dbus-daemon-eavesdrop.c
@@ -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,
diff --git a/test/dbus-daemon.c b/test/dbus-daemon.c
index 02684646..02590904 100644
--- a/test/dbus-daemon.c
+++ b/test/dbus-daemon.c
@@ -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)
diff --git a/test/test-utils-glib.c b/test/test-utils-glib.c
index ce312f54..24f0ee46 100644
--- a/test/test-utils-glib.c
+++ b/test/test-utils-glib.c
@@ -33,9 +33,11 @@
# 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);
diff --git a/test/test-utils-glib.h b/test/test-utils-glib.h
index b233384f..c672fe50 100644
--- a/test/test-utils-glib.h
+++ b/test/test-utils-glib.h
@@ -33,12 +33,43 @@
#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,