From fe3161a856558cfff597d633acd8ba63588975c5 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Mon, 26 Jan 2015 15:47:59 +0000 Subject: [PATCH 4/6] Add infrastructure to run bits of tests under an alternative uid Bug: https://bugs.freedesktop.org/show_bug.cgi?id=88810 --- configure.ac | 12 ++++- test/dbus-daemon-eavesdrop.c | 2 +- test/dbus-daemon.c | 1 + test/test-utils-glib.c | 119 +++++++++++++++++++++++++++++++++++++++---- test/test-utils-glib.h | 8 +++ 5 files changed, 130 insertions(+), 12 deletions(-) diff --git a/configure.ac b/configure.ac index 84f44b4..4285f89 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 for running the DBUS daemon (messagebus)])) +AC_ARG_WITH([test_user], + [AS_HELP_STRING([--with-test-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 79c1e90..686ccb3 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 0268464..0259090 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 fc092e5..465a81c 100644 --- a/test/test-utils-glib.c +++ b/test/test-utils-glib.c @@ -7,9 +7,11 @@ # include # include #else +# include # include # include # include +# include #endif #include @@ -26,9 +28,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 (gchar *binary, gchar *configuration, + TestUser user, GPid *daemon_pid) { GError *error = NULL; @@ -41,13 +75,74 @@ spawn_dbus_daemon (gchar *binary, "--print-address=1", /* stdout */ NULL }; +#ifdef DBUS_UNIX + 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 */ argv, NULL, /* envp */ G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, - NULL, /* child_setup */ - NULL, /* user data */ +#ifdef DBUS_UNIX + child_setup, pwd, +#else + NULL, NULL, +#endif daemon_pid, NULL, /* child's stdin = /dev/null */ &address_fd, @@ -89,6 +184,7 @@ spawn_dbus_daemon (gchar *binary, gchar * test_get_dbus_daemon (const gchar *config_file, + TestUser user, GPid *daemon_pid) { gchar *dbus_daemon; @@ -97,12 +193,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) { @@ -138,11 +228,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 380fe95..20c31c7 100644 --- a/test/test-utils-glib.h +++ b/test/test-utils-glib.h @@ -7,12 +7,20 @@ #include "test-utils.h" +typedef enum { + TEST_USER_ME, + TEST_USER_ROOT, + TEST_USER_MESSAGEBUS, + 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, -- 2.1.4