From 81c930ab9ebf4cd0bf9e7c8ef68d94e469bbd89b Mon Sep 17 00:00:00 2001
From: Ralf Habacker <ralf.habacker@freenet.de>
Date: Fri, 27 Jan 2017 17:52:19 +0100
Subject: [PATCH] Add glib based test case for testing dbus auth configuration.

This patch contains an endless loop fix in spawn_dbus_daemon()
in case the spawned process exits unexpected.

Bug: https://bugs.freedesktop.org/show_bug.cgi?id=99512
---
 cmake/test/CMakeLists.txt                          |   1 +
 test/Makefile.am                                   |  12 ++
 .../debug-allow-anonymous.conf.in                  |  14 ++
 .../valid-config-files/debug-allow-any.conf.in     |  12 ++
 .../debug-allow-external.conf.in                   |  13 ++
 .../valid-config-files/debug-allow-invalid.conf.in |  13 ++
 .../valid-config-files/debug-allow-sha1.conf.in    |  13 ++
 test/test-auth.c                                   | 181 +++++++++++++++++++++
 test/test-utils-glib.c                             |  61 +++++--
 test/test-utils-glib.h                             |   6 +
 10 files changed, 313 insertions(+), 13 deletions(-)
 create mode 100644 test/data/valid-config-files/debug-allow-anonymous.conf.in
 create mode 100644 test/data/valid-config-files/debug-allow-any.conf.in
 create mode 100644 test/data/valid-config-files/debug-allow-external.conf.in
 create mode 100644 test/data/valid-config-files/debug-allow-invalid.conf.in
 create mode 100644 test/data/valid-config-files/debug-allow-sha1.conf.in
 create mode 100644 test/test-auth.c

diff --git a/cmake/test/CMakeLists.txt b/cmake/test/CMakeLists.txt
index 58eed09..4111c18 100644
--- a/cmake/test/CMakeLists.txt
+++ b/cmake/test/CMakeLists.txt
@@ -110,6 +110,7 @@ if(DBUS_WITH_GLIB)
     add_test_executable(test-syntax ${CMAKE_SOURCE_DIR}/../test/syntax.c ${TEST_LIBRARIES})
     add_test_executable(test-syslog ${CMAKE_SOURCE_DIR}/../test/internals/syslog.c ${TEST_LIBRARIES})
     add_helper_executable(manual-authz ${CMAKE_SOURCE_DIR}/../test/manual-authz.c ${TEST_LIBRARIES})
+    add_test_executable(test-auth ${CMAKE_SOURCE_DIR}/../test/test-auth.c ${TEST_LIBRARIES})
 endif()
 
 ### keep these in creation order, i.e. uppermost dirs first 
diff --git a/test/Makefile.am b/test/Makefile.am
index eaf2df8..797fd9d 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -156,6 +156,7 @@ endif
 
 if DBUS_WITH_GLIB
 installable_tests += \
+	test-auth \
 	test-corrupt \
 	test-dbus-daemon \
 	test-dbus-daemon-eavesdrop \
@@ -231,6 +232,12 @@ manual_authz_LDADD = \
     $(GLIB_LIBS) \
     $(NULL)
 
+test_auth_SOURCES = test-auth.c
+test_auth_LDADD = \
+    libdbus-testutils.la \
+    $(GLIB_LIBS) \
+    $(NULL)
+
 test_corrupt_SOURCES = corrupt.c
 test_corrupt_LDADD = \
     libdbus-testutils.la \
@@ -344,6 +351,11 @@ endif DBUS_ENABLE_INSTALLED_TESTS
 in_data = \
 	data/valid-config-files-system/debug-allow-all-fail.conf.in \
 	data/valid-config-files-system/debug-allow-all-pass.conf.in \
+	data/valid-config-files/debug-allow-invalid.conf.in \
+	data/valid-config-files/debug-allow-anonymous.conf.in \
+	data/valid-config-files/debug-allow-external.conf.in \
+	data/valid-config-files/debug-allow-sha1.conf.in \
+	data/valid-config-files/debug-allow-any.conf.in \
 	data/valid-config-files/debug-allow-all-sha1.conf.in \
 	data/valid-config-files/debug-allow-all.conf.in \
 	data/valid-config-files/finite-timeout.conf.in \
diff --git a/test/data/valid-config-files/debug-allow-anonymous.conf.in b/test/data/valid-config-files/debug-allow-anonymous.conf.in
new file mode 100644
index 0000000..e433391
--- /dev/null
+++ b/test/data/valid-config-files/debug-allow-anonymous.conf.in
@@ -0,0 +1,14 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+  <listen>@TEST_LISTEN@</listen>
+  <auth>ANONYMOUS</auth>
+  <allow_anonymous/>
+  <servicedir>@DBUS_TEST_DATA@/valid-service-files</servicedir>
+  <policy context="default">
+    <allow send_interface="*"/>
+    <allow receive_interface="*"/>
+    <allow own="*"/>
+    <allow user="*"/>
+  </policy>
+</busconfig>
diff --git a/test/data/valid-config-files/debug-allow-any.conf.in b/test/data/valid-config-files/debug-allow-any.conf.in
new file mode 100644
index 0000000..b4bab47
--- /dev/null
+++ b/test/data/valid-config-files/debug-allow-any.conf.in
@@ -0,0 +1,12 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+  <listen>@TEST_LISTEN@</listen>
+  <servicedir>@DBUS_TEST_DATA@/valid-service-files</servicedir>
+  <policy context="default">
+    <allow send_interface="*"/>
+    <allow receive_interface="*"/>
+    <allow own="*"/>
+    <allow user="*"/>
+  </policy>
+</busconfig>
diff --git a/test/data/valid-config-files/debug-allow-external.conf.in b/test/data/valid-config-files/debug-allow-external.conf.in
new file mode 100644
index 0000000..6c4e8e5
--- /dev/null
+++ b/test/data/valid-config-files/debug-allow-external.conf.in
@@ -0,0 +1,13 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+  <listen>@TEST_LISTEN@</listen>
+  <auth>EXTERNAL</auth>
+  <servicedir>@DBUS_TEST_DATA@/valid-service-files</servicedir>
+  <policy context="default">
+    <allow send_interface="*"/>
+    <allow receive_interface="*"/>
+    <allow own="*"/>
+    <allow user="*"/>
+  </policy>
+</busconfig>
diff --git a/test/data/valid-config-files/debug-allow-invalid.conf.in b/test/data/valid-config-files/debug-allow-invalid.conf.in
new file mode 100644
index 0000000..1ca544c
--- /dev/null
+++ b/test/data/valid-config-files/debug-allow-invalid.conf.in
@@ -0,0 +1,13 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+  <listen>@TEST_LISTEN@</listen>
+  <auth>INVALID</auth>
+  <servicedir>@DBUS_TEST_DATA@/valid-service-files</servicedir>
+  <policy context="default">
+    <allow send_interface="*"/>
+    <allow receive_interface="*"/>
+    <allow own="*"/>
+    <allow user="*"/>
+  </policy>
+</busconfig>
diff --git a/test/data/valid-config-files/debug-allow-sha1.conf.in b/test/data/valid-config-files/debug-allow-sha1.conf.in
new file mode 100644
index 0000000..1dc57ed
--- /dev/null
+++ b/test/data/valid-config-files/debug-allow-sha1.conf.in
@@ -0,0 +1,13 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+  <listen>@TEST_LISTEN@</listen>
+  <auth>DBUS_COOKIE_SHA1</auth>
+  <servicedir>@DBUS_TEST_DATA@/valid-service-files</servicedir>
+  <policy context="default">
+    <allow send_interface="*"/>
+    <allow receive_interface="*"/>
+    <allow own="*"/>
+    <allow user="*"/>
+  </policy>
+</busconfig>
diff --git a/test/test-auth.c b/test/test-auth.c
new file mode 100644
index 0000000..36094a4
--- /dev/null
+++ b/test/test-auth.c
@@ -0,0 +1,181 @@
+/* test case for dbus daemon auth configuration
+ *
+ * Copyright © 2017 Ralf Habacker <ralf.habacker@freenet.de>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <glib.h>
+
+#include <dbus/dbus.h>
+
+#include "test-utils-glib.h"
+
+typedef struct {
+    gboolean skip;
+    TestMainContext *ctx;
+
+    GPid daemon_pid;
+    gchar *address;
+
+    DBusConnection *client_conn;
+} Fixture;
+
+typedef struct {
+    const char *config_file;
+    enum { SPECIFY_ADDRESS = 0, RELY_ON_DEFAULT } connect_mode;
+} Config;
+
+static void
+setup (Fixture *f,
+    gconstpointer context)
+{
+  const Config *config = context;
+
+  f->ctx = test_main_context_get ();
+  f->skip = FALSE;
+  f->address = NULL;
+
+  if (!_test_get_dbus_daemon (config ? config->config_file : NULL,
+                              TEST_USER_ME,
+                              &f->daemon_pid, &f->address))
+    {
+      g_test_skip ("could not start dbus daemon");
+      f->skip = TRUE;
+    }
+  f->client_conn = 0;
+}
+
+static dbus_bool_t
+_test_connect_to_bus (Fixture *f)
+{
+  DBusError error = DBUS_ERROR_INIT;
+  dbus_bool_t ok;
+
+  f->client_conn = dbus_connection_open_private (f->address, &error);
+  if (dbus_error_is_set (&error))
+    return FALSE;
+
+  if (f->client_conn == NULL)
+    return FALSE;
+
+  ok = dbus_bus_register (f->client_conn, &error);
+  if (dbus_error_is_set (&error))
+    return FALSE;
+
+  if (!ok)
+    return FALSE;
+
+  if (dbus_bus_get_unique_name (f->client_conn) == NULL)
+    return FALSE;
+
+  test_connection_setup (f->ctx, f->client_conn);
+  return TRUE;
+}
+
+static void
+test_invalid (Fixture *f, gconstpointer context)
+{
+  if (f->skip)
+    return;
+  if (f->address != NULL)
+    g_test_fail();
+}
+
+static void
+test_valid (Fixture *f, gconstpointer context)
+{
+  if (f->skip)
+    return;
+  if (f->address == NULL)
+    {
+      g_test_fail();
+      return;
+    }
+  if (!_test_connect_to_bus (f))
+    g_test_fail();
+}
+
+static void
+teardown (Fixture *f,
+    gconstpointer context G_GNUC_UNUSED)
+{
+  if (f->client_conn != NULL)
+    {
+      dbus_connection_close (f->client_conn);
+      dbus_connection_unref (f->client_conn);
+      f->client_conn = NULL;
+    }
+
+  if (f->daemon_pid != 0)
+    {
+      test_kill_pid (f->daemon_pid);
+      g_spawn_close_pid (f->daemon_pid);
+      f->daemon_pid = 0;
+    }
+
+  test_main_context_unref (f->ctx);
+  g_free (f->address);
+}
+
+static Config config_invalid = {
+  "valid-config-files/debug-allow-invalid.conf",
+  SPECIFY_ADDRESS
+};
+
+static Config config_external = {
+  "valid-config-files/debug-allow-external.conf",
+  SPECIFY_ADDRESS
+};
+
+static Config config_sha1 = {
+  "valid-config-files/debug-allow-sha1.conf",
+  SPECIFY_ADDRESS
+};
+
+static Config config_anonymous = {
+  "valid-config-files/debug-allow-anonymous.conf",
+  SPECIFY_ADDRESS
+};
+
+static Config config_any = {
+  "valid-config-files/debug-allow-any.conf",
+  SPECIFY_ADDRESS
+};
+
+int
+main (int argc,
+    char **argv)
+{
+  test_init (&argc, &argv);
+
+  g_test_add ("/auth/invalid", Fixture, &config_invalid, setup, test_invalid, teardown);
+  g_test_add ("/auth/external", Fixture, &config_external, setup, test_valid, teardown);
+  g_test_add ("/auth/sha1", Fixture, &config_sha1, setup, test_valid, teardown);
+  g_test_add ("/auth/anonymous", Fixture, &config_anonymous, setup, test_valid, teardown);
+  g_test_add ("/auth/any", Fixture, &config_any, setup, test_valid, teardown);
+
+  return g_test_run ();
+
+  return 0;
+}
diff --git a/test/test-utils-glib.c b/test/test-utils-glib.c
index 2ba4451..6609942 100644
--- a/test/test-utils-glib.c
+++ b/test/test-utils-glib.c
@@ -105,6 +105,7 @@ spawn_dbus_daemon (const gchar *binary,
   const struct passwd *pwd = NULL;
 #endif
   char *envp[2] = { "DBUS_VERBOSE=1", NULL };
+  gboolean is_running = TRUE;
 
   if (!g_getenv ("DBUS_VERBOSE") || *g_getenv ("DBUS_VERBOSE") == '0')
     envp[0] = NULL;
@@ -200,7 +201,7 @@ spawn_dbus_daemon (const gchar *binary,
   /* polling until the dbus-daemon writes out its address is a bit stupid,
    * but at least it's simple, unlike dbus-launch... in principle we could
    * use select() here, but life's too short */
-  while (1)
+  while (is_running)
     {
       gssize bytes;
       gchar buf[4096];
@@ -222,11 +223,12 @@ spawn_dbus_daemon (const gchar *binary,
         }
 
       g_usleep (G_USEC_PER_SEC / 10);
+      is_running = test_check_pid (*daemon_pid);
     }
 
   g_close (address_fd, NULL);
 
-  return g_string_free (address, FALSE);
+  return is_running ? g_string_free (address, FALSE) : 0;
 }
 
 gchar *
@@ -234,10 +236,23 @@ test_get_dbus_daemon (const gchar *config_file,
                       TestUser     user,
                       GPid        *daemon_pid)
 {
-  gchar *dbus_daemon;
-  gchar *arg;
+  gchar **address = 0;
+  if (_test_get_dbus_daemon (config_file, user, daemon_pid, address))
+    return *address;
+  else
+   return NULL;
+}
+
+dbus_bool_t
+_test_get_dbus_daemon (const gchar *config_file,
+                      TestUser     user,
+                      GPid        *daemon_pid,
+                      gchar       **address)
+{
+  gchar *dbus_daemon = NULL;
+  gchar *arg = NULL;
   const gchar *listen_address = NULL;
-  gchar *address;
+  dbus_bool_t result = FALSE;
 
   /* we often have to override this because on Windows, the default may be
    * autolaunch:, which is globally-scoped and hence unsuitable for
@@ -246,13 +261,12 @@ test_get_dbus_daemon (const gchar *config_file,
 
   if (config_file != NULL)
     {
-
       if (g_getenv ("DBUS_TEST_DATA") == NULL)
         {
           g_test_message ("set DBUS_TEST_DATA to a directory containing %s",
               config_file);
           g_test_skip ("DBUS_TEST_DATA not set");
-          return NULL;
+          goto fail;
         }
 
       arg = g_strdup_printf (
@@ -290,22 +304,27 @@ test_get_dbus_daemon (const gchar *config_file,
         {
           g_test_skip ("cannot use DBUS_TEST_DAEMON_ADDRESS for "
               "unusally-configured dbus-daemon");
-          address = NULL;
+          goto fail;
         }
       else
         {
-          address = g_strdup (g_getenv ("DBUS_TEST_DAEMON_ADDRESS"));
+          *address = g_strdup (g_getenv ("DBUS_TEST_DAEMON_ADDRESS"));
+          result = TRUE;
         }
     }
   else
     {
-      address = spawn_dbus_daemon (dbus_daemon, arg,
+      *address = spawn_dbus_daemon (dbus_daemon, arg,
           listen_address, user, daemon_pid);
+      result = TRUE;
     }
 
-  g_free (dbus_daemon);
-  g_free (arg);
-  return address;
+fail:
+  if (dbus_daemon)
+    g_free (dbus_daemon);
+  if (arg)
+    g_free (arg);
+  return result;
 }
 
 DBusConnection *
@@ -425,6 +444,22 @@ test_kill_pid (GPid pid)
 #endif
 }
 
+gboolean
+test_check_pid (GPid pid)
+{
+#ifdef DBUS_WIN
+  DWORD ret = WaitForSingleObject(pid, 0);
+  return ret == WAIT_TIMEOUT;
+#else
+  int wstatus;
+  if (waitpid (pid, &wstatus, WNOHANG) == -1)
+    return FALSE;
+  if (WIFEXITED (wstatus))
+    return FALSE;
+  return TRUE;
+#endif
+}
+
 static gboolean
 time_out (gpointer data)
 {
diff --git a/test/test-utils-glib.h b/test/test-utils-glib.h
index acacee0..f892fc3 100644
--- a/test/test-utils-glib.h
+++ b/test/test-utils-glib.h
@@ -71,6 +71,11 @@ gchar *test_get_dbus_daemon (const gchar *config_file,
     TestUser user,
     GPid *daemon_pid);
 
+dbus_bool_t _test_get_dbus_daemon (const gchar *config_file,
+    TestUser     user,
+    GPid        *daemon_pid,
+    gchar       **address);
+
 DBusConnection *test_connect_to_bus (TestMainContext *ctx,
     const gchar *address);
 DBusConnection *test_connect_to_bus_as_user (TestMainContext *ctx,
@@ -78,6 +83,7 @@ DBusConnection *test_connect_to_bus_as_user (TestMainContext *ctx,
     TestUser user);
 
 void test_kill_pid (GPid pid);
+gboolean test_check_pid (GPid pid);
 
 void test_init (int *argcp, char ***argvp);
 
-- 
2.6.6