Add a simple manual test for authentication/authorization.
authorSimon McVittie <simon.mcvittie@collabora.co.uk>
Fri, 23 Aug 2013 00:57:27 +0000 (02:57 +0200)
committerRalf Habacker <ralf.habacker@freenet.de>
Fri, 23 Aug 2013 00:57:50 +0000 (02:57 +0200)
Bug: http://bugs.freedesktop.org/show_bug.cgi?id=39720
Reviewed-by: Ralf Habacker <ralf.habacker@freenet.de>
test/Makefile.am
test/manual-authz.c [new file with mode: 0644]

index 074017a..4866b32 100644 (file)
@@ -103,6 +103,8 @@ installable_tests = \
        shell-test \
        test-printf \
        $(NULL)
+installable_manual_tests += \
+       $(NULL)
 
 if DBUS_WITH_GLIB
 installable_tests += \
@@ -116,6 +118,9 @@ installable_tests += \
        test-syntax \
        test-syslog \
        $(NULL)
+installable_manual_tests += \
+       manual-authz \
+       $(NULL)
 endif DBUS_WITH_GLIB
 
 installcheck_tests =
@@ -132,6 +137,11 @@ TESTS_ENVIRONMENT = \
        DBUS_TEST_HOMEDIR=@abs_top_builddir@/dbus \
        $(NULL)
 
+manual_authz_SOURCES = manual-authz.c
+manual_authz_LDADD = $(top_builddir)/dbus/libdbus-1.la \
+    $(GLIB_LIBS) \
+    $(DBUS_GLIB_LIBS)
+
 test_corrupt_SOURCES = corrupt.c
 test_corrupt_LDADD = $(top_builddir)/dbus/libdbus-1.la \
     $(GLIB_LIBS) \
@@ -173,9 +183,9 @@ TESTS += $(installable_tests)
 installcheck_tests += $(installable_tests)
 
 if DBUS_ENABLE_INSTALLED_TESTS
-  testexec_PROGRAMS += $(installable_tests)
+  testexec_PROGRAMS += $(installable_tests) $(installable_manual_tests)
 else !DBUS_ENABLE_INSTALLED_TESTS
-  noinst_PROGRAMS += $(installable_tests)
+  noinst_PROGRAMS += $(installable_tests) $(installable_manual_tests)
 endif !DBUS_ENABLE_INSTALLED_TESTS
 
 endif DBUS_ENABLE_MODULAR_TESTS
diff --git a/test/manual-authz.c b/test/manual-authz.c
new file mode 100644 (file)
index 0000000..d228829
--- /dev/null
@@ -0,0 +1,405 @@
+/* Simple sanity-check for authentication and authorization.
+ *
+ * Copyright © 2010-2011 Nokia Corporation
+ * Copyright © 2012 Collabora Ltd.
+ *
+ * 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 <dbus/dbus-glib-lowlevel.h>
+
+#ifdef G_OS_UNIX
+#include <unistd.h>
+#include <sys/types.h>
+#endif
+
+typedef struct {
+    DBusError e;
+
+    DBusServer *normal_server;
+    DBusServer *anon_allowed_server;
+    DBusServer *anon_only_server;
+    DBusServer *anon_mech_only_server;
+    DBusServer *anon_disallowed_server;
+    DBusServer *permissive_server;
+    DBusServer *unhappy_server;
+    DBusServer *same_uid_server;
+    DBusServer *same_uid_or_anon_server;
+} Fixture;
+
+static void oom (void) G_GNUC_NORETURN;
+static void
+oom (void)
+{
+  g_error ("out of memory");
+}
+
+static void
+assert_no_error (const DBusError *e)
+{
+  if (G_UNLIKELY (dbus_error_is_set (e)))
+    g_error ("expected success but got error: %s: %s", e->name, e->message);
+}
+
+static DBusHandlerResult
+server_message_cb (DBusConnection *conn,
+    DBusMessage *message,
+    void *data)
+{
+  if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected"))
+    {
+      dbus_connection_unref (conn);
+
+      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+
+  if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_CALL)
+    {
+      DBusMessage *reply = dbus_message_new_method_return (message);
+      const char *hello = "Hello, world!";
+      unsigned long uid;
+      char *sid;
+
+      if (dbus_connection_get_unix_user (conn, &uid))
+        {
+          g_message ("message from uid %lu", uid);
+        }
+      else if (dbus_connection_get_windows_user (conn, &sid))
+        {
+          if (sid == NULL)
+            oom ();
+
+          g_message ("message from sid \"%s\"", sid);
+          dbus_free (sid);
+        }
+      else if (dbus_connection_get_is_anonymous (conn))
+        {
+          g_message ("message from Anonymous");
+        }
+      else
+        {
+          g_message ("message from ... someone?");
+        }
+
+      if (reply == NULL)
+        oom ();
+
+      if (!dbus_message_append_args (reply,
+            DBUS_TYPE_STRING, &hello,
+            DBUS_TYPE_INVALID))
+        oom ();
+
+      if (!dbus_connection_send (conn, reply, NULL))
+        oom ();
+
+      dbus_message_unref (reply);
+
+      return DBUS_HANDLER_RESULT_HANDLED;
+    }
+
+  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static dbus_bool_t
+permissive_unix_func (DBusConnection *conn,
+    unsigned long uid,
+    void *data)
+{
+  g_message ("accepting Unix user %lu", uid);
+  return TRUE;
+}
+
+static dbus_bool_t
+permissive_win_func (DBusConnection *conn,
+    const char *sid,
+    void *data)
+{
+  g_message ("accepting Windows user \"%s\"", sid);
+  return TRUE;
+}
+
+static dbus_bool_t
+broken_unix_func (DBusConnection *conn,
+    unsigned long uid,
+    void *data)
+{
+  g_error ("libdbus called the Unix user function for an ANONYMOUS-only "
+      "connection");
+  return FALSE;
+}
+
+static dbus_bool_t
+broken_win_func (DBusConnection *conn,
+    const char *sid,
+    void *data)
+{
+  g_error ("libdbus called the Windows user function for an ANONYMOUS-only "
+      "connection");
+  return FALSE;
+}
+
+static dbus_bool_t
+unhappy_unix_func (DBusConnection *conn,
+    unsigned long uid,
+    void *data)
+{
+  g_message ("rejecting Unix user %lu", uid);
+  return FALSE;
+}
+
+static dbus_bool_t
+unhappy_win_func (DBusConnection *conn,
+    const char *sid,
+    void *data)
+{
+  g_message ("rejecting Windows user \"%s\"", sid);
+  return FALSE;
+}
+
+static dbus_bool_t
+same_uid_unix_func (DBusConnection *conn,
+    unsigned long uid,
+    void *data)
+{
+  g_message ("checking whether Unix user %lu owns this process", uid);
+  /* I'd use _dbus_unix_user_is_process_owner(), but it's private... */
+#ifdef G_OS_UNIX
+  return (geteuid () == uid);
+#else
+  return FALSE;
+#endif
+}
+
+static dbus_bool_t
+same_uid_win_func (DBusConnection *conn,
+    const char *sid,
+    void *data)
+{
+  g_message ("checking whether Windows user \"%s\" owns this process", sid);
+  g_message ("Stub implementation consistent with dbus-sysdeps-util-win: "
+      "assume they do");
+  return TRUE;
+}
+
+static void
+new_conn_cb (DBusServer *server,
+    DBusConnection *conn,
+    void *data)
+{
+  Fixture *f = data;
+
+  dbus_connection_ref (conn);
+  dbus_connection_setup_with_g_main (conn, NULL);
+
+  if (!dbus_connection_add_filter (conn, server_message_cb, f, NULL))
+    oom ();
+
+  if (server == f->normal_server)
+    {
+    }
+  else if (server == f->anon_allowed_server)
+    {
+      dbus_connection_set_allow_anonymous (conn, TRUE);
+    }
+  else if (server == f->anon_only_server)
+    {
+      dbus_connection_set_allow_anonymous (conn, TRUE);
+
+      dbus_connection_set_unix_user_function (conn, unhappy_unix_func,
+          f, NULL);
+      dbus_connection_set_windows_user_function (conn, unhappy_win_func,
+          f, NULL);
+    }
+  else if (server == f->anon_mech_only_server)
+    {
+      dbus_connection_set_allow_anonymous (conn, TRUE);
+
+      /* should never get called */
+      dbus_connection_set_unix_user_function (conn, broken_unix_func,
+          f, NULL);
+      dbus_connection_set_windows_user_function (conn, broken_win_func,
+          f, NULL);
+    }
+  else if (server == f->anon_disallowed_server)
+    {
+      dbus_connection_set_allow_anonymous (conn, FALSE);
+
+      /* should never get called */
+      dbus_connection_set_unix_user_function (conn, broken_unix_func,
+          f, NULL);
+      dbus_connection_set_windows_user_function (conn, broken_win_func,
+          f, NULL);
+    }
+  else if (server == f->permissive_server)
+    {
+      dbus_connection_set_unix_user_function (conn, permissive_unix_func,
+          f, NULL);
+      dbus_connection_set_windows_user_function (conn, permissive_win_func,
+          f, NULL);
+    }
+  else if (server == f->unhappy_server)
+    {
+      dbus_connection_set_unix_user_function (conn, unhappy_unix_func,
+          f, NULL);
+      dbus_connection_set_windows_user_function (conn, unhappy_win_func,
+          f, NULL);
+    }
+  else if (server == f->same_uid_server)
+    {
+      dbus_connection_set_unix_user_function (conn, same_uid_unix_func,
+          f, NULL);
+      dbus_connection_set_windows_user_function (conn, same_uid_win_func,
+          f, NULL);
+    }
+  else if (server == f->same_uid_or_anon_server)
+    {
+      dbus_connection_set_allow_anonymous (conn, TRUE);
+
+      dbus_connection_set_unix_user_function (conn, same_uid_unix_func,
+          f, NULL);
+      dbus_connection_set_windows_user_function (conn, same_uid_win_func,
+          f, NULL);
+    }
+  else
+    {
+      g_assert_not_reached ();
+    }
+}
+
+static void
+setup (Fixture *f,
+    const gchar *listen_addr)
+{
+  const char *only_anon[] = { "ANONYMOUS", NULL };
+  char *connect_addr;
+
+  f->normal_server = dbus_server_listen (listen_addr, &f->e);
+  assert_no_error (&f->e);
+  g_assert (f->normal_server != NULL);
+  dbus_server_set_new_connection_function (f->normal_server,
+      new_conn_cb, f, NULL);
+  dbus_server_setup_with_g_main (f->normal_server, NULL);
+  connect_addr = dbus_server_get_address (f->normal_server);
+  g_message ("Normal server:\n%s", connect_addr);
+  dbus_free (connect_addr);
+
+  f->anon_allowed_server = dbus_server_listen (listen_addr, &f->e);
+  assert_no_error (&f->e);
+  g_assert (f->anon_allowed_server != NULL);
+  dbus_server_set_new_connection_function (f->anon_allowed_server,
+      new_conn_cb, f, NULL);
+  dbus_server_setup_with_g_main (f->anon_allowed_server, NULL);
+  connect_addr = dbus_server_get_address (f->anon_allowed_server);
+  g_message ("Anonymous-allowed server:\n%s", connect_addr);
+  dbus_free (connect_addr);
+
+  f->anon_only_server = dbus_server_listen (listen_addr, &f->e);
+  assert_no_error (&f->e);
+  g_assert (f->anon_only_server != NULL);
+  dbus_server_set_new_connection_function (f->anon_only_server,
+      new_conn_cb, f, NULL);
+  dbus_server_setup_with_g_main (f->anon_only_server, NULL);
+  connect_addr = dbus_server_get_address (f->anon_only_server);
+  g_message ("Anonymous-only server:\n%s", connect_addr);
+  dbus_free (connect_addr);
+
+  f->anon_mech_only_server = dbus_server_listen (listen_addr, &f->e);
+  assert_no_error (&f->e);
+  g_assert (f->anon_mech_only_server != NULL);
+  dbus_server_set_auth_mechanisms (f->anon_mech_only_server, only_anon);
+  dbus_server_set_new_connection_function (f->anon_mech_only_server,
+      new_conn_cb, f, NULL);
+  dbus_server_setup_with_g_main (f->anon_mech_only_server, NULL);
+  connect_addr = dbus_server_get_address (f->anon_mech_only_server);
+  g_message ("Anon mech only server:\n%s", connect_addr);
+  dbus_free (connect_addr);
+
+  f->anon_disallowed_server = dbus_server_listen (listen_addr, &f->e);
+  assert_no_error (&f->e);
+  g_assert (f->anon_disallowed_server != NULL);
+  dbus_server_set_auth_mechanisms (f->anon_disallowed_server, only_anon);
+  dbus_server_set_new_connection_function (f->anon_disallowed_server,
+      new_conn_cb, f, NULL);
+  dbus_server_setup_with_g_main (f->anon_disallowed_server, NULL);
+  connect_addr = dbus_server_get_address (f->anon_disallowed_server);
+  g_message ("Anonymous-disallowed server:\n%s", connect_addr);
+  dbus_free (connect_addr);
+
+  f->permissive_server = dbus_server_listen (listen_addr, &f->e);
+  assert_no_error (&f->e);
+  g_assert (f->permissive_server != NULL);
+  dbus_server_set_new_connection_function (f->permissive_server,
+      new_conn_cb, f, NULL);
+  dbus_server_setup_with_g_main (f->permissive_server, NULL);
+  connect_addr = dbus_server_get_address (f->permissive_server);
+  g_message ("Permissive server:\n%s", connect_addr);
+  dbus_free (connect_addr);
+
+  f->unhappy_server = dbus_server_listen (listen_addr, &f->e);
+  assert_no_error (&f->e);
+  g_assert (f->unhappy_server != NULL);
+  dbus_server_set_new_connection_function (f->unhappy_server,
+      new_conn_cb, f, NULL);
+  dbus_server_setup_with_g_main (f->unhappy_server, NULL);
+  connect_addr = dbus_server_get_address (f->unhappy_server);
+  g_message ("Unhappy server:\n%s", connect_addr);
+  dbus_free (connect_addr);
+
+  f->same_uid_server = dbus_server_listen (listen_addr, &f->e);
+  assert_no_error (&f->e);
+  g_assert (f->same_uid_server != NULL);
+  dbus_server_set_new_connection_function (f->same_uid_server,
+      new_conn_cb, f, NULL);
+  dbus_server_setup_with_g_main (f->same_uid_server, NULL);
+  connect_addr = dbus_server_get_address (f->same_uid_server);
+  g_message ("Same-UID server:\n%s", connect_addr);
+  dbus_free (connect_addr);
+
+  f->same_uid_or_anon_server = dbus_server_listen (listen_addr, &f->e);
+  assert_no_error (&f->e);
+  g_assert (f->same_uid_or_anon_server != NULL);
+  dbus_server_set_new_connection_function (f->same_uid_or_anon_server,
+      new_conn_cb, f, NULL);
+  dbus_server_setup_with_g_main (f->same_uid_or_anon_server, NULL);
+  connect_addr = dbus_server_get_address (f->same_uid_or_anon_server);
+  g_message ("Same-UID-or-anon server:\n%s", connect_addr);
+  dbus_free (connect_addr);
+}
+
+int
+main (int argc,
+    char **argv)
+{
+  Fixture f = { DBUS_ERROR_INIT };
+
+  if (argc >= 2)
+    setup (&f, argv[1]);
+  else
+    setup (&f, "tcp:host=127.0.0.1");
+
+  for (;;)
+    g_main_context_iteration (NULL, TRUE);
+}