diff --git a/test/test-utils-glib.c b/test/test-utils-glib.c index 30b9836c..bcd83d11 100644 --- a/test/test-utils-glib.c +++ b/test/test-utils-glib.c @@ -40,6 +40,7 @@ # include # include # include +# include # include #endif @@ -66,6 +67,61 @@ _test_assert_no_error (const DBusError *e, } #ifdef DBUS_UNIX +static gboolean +can_become_user_or_skip (uid_t uid) +{ + gchar *message; + pid_t child_pid; + pid_t pid; + int wstatus; + + /* We can't switch to the uid without affecting the whole process, + * which we don't necessarily want to do, so try it in a child process. */ + child_pid = fork (); + + if (child_pid < 0) + g_error ("fork: %s", g_strerror (errno)); + + if (child_pid == 0) + { + /* Child process: try to become uid, exit 0 on success, exit with + * status = errno on failure */ + + if (setuid (uid) != 0) + { + /* make sure we report failure even if errno is wrong */ + if (errno == 0) + errno = ENODATA; + + _exit (errno); + } + + /* success */ + _exit (0); + } + + /* Parent process: wait for child and report result */ + + pid = waitpid (child_pid, &wstatus, 0); + g_assert_cmpuint (child_pid, ==, pid); + + if (WIFEXITED (wstatus) && WEXITSTATUS (wstatus) == 0) + return TRUE; + + if (WIFEXITED (wstatus)) + message = g_strdup_printf ("unable to become uid %lu: %s", + (unsigned long) uid, + g_strerror (WEXITSTATUS (wstatus))); + else + message = g_strdup_printf ("unable to become uid %lu: unknown wait status %d", + (unsigned long) uid, + wstatus); + + g_test_skip (message); + g_free (message); + return FALSE; +} + static void child_setup (gpointer user_data) { @@ -141,6 +197,9 @@ spawn_dbus_daemon (const gchar *binary, return NULL; } + if (!can_become_user_or_skip (pwd->pw_uid)) + return NULL; + if (user == TEST_USER_ROOT_DROP_TO_MESSAGEBUS) { /* Let the dbus-daemon start as root and drop privileges @@ -163,6 +222,9 @@ spawn_dbus_daemon (const gchar *binary, return NULL; } + if (!can_become_user_or_skip (pwd->pw_uid)) + return NULL; + break; case TEST_USER_ME: