uid-permissions.c 7.17 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
/* Integration tests for the dbus-daemon's uid-based hardening
 *
 * Author: Simon McVittie <simon.mcvittie@collabora.co.uk>
 * Copyright © 2010-2011 Nokia Corporation
 * Copyright © 2015 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 "test-utils-glib.h"

32 33
#include <gio/gio.h>

34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
typedef struct {
    gboolean skip;

    TestMainContext *ctx;

    DBusError e;
    GError *ge;

    GPid daemon_pid;

    DBusConnection *conn;
} Fixture;

typedef struct {
    const char *config_file;
    TestUser user;
    gboolean expect_success;
} Config;

static void
setup (Fixture *f,
    gconstpointer context)
{
  const Config *config = context;
  gchar *address;

  f->ctx = test_main_context_get ();
  f->ge = NULL;
  dbus_error_init (&f->e);

  address = test_get_dbus_daemon (config ? config->config_file : NULL,
65
                                  TEST_USER_MESSAGEBUS, NULL,
66 67 68 69 70 71 72 73
                                  &f->daemon_pid);

  if (address == NULL)
    {
      f->skip = TRUE;
      return;
    }

74 75
  f->conn = test_try_connect_to_bus_as_user (f->ctx, address,
      config ? config->user : TEST_USER_ME, &f->ge);
76

77 78 79 80 81 82 83
  if (f->conn == NULL &&
      g_error_matches (f->ge, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
    {
      g_test_skip (f->ge->message);
      g_clear_error (&f->ge);
      f->skip = TRUE;
    }
84

85
  g_assert_no_error (f->ge);
86 87 88 89 90 91 92 93
  g_free (address);
}

static void
test_uae (Fixture *f,
    gconstpointer context)
{
  const Config *config = context;
94 95
  DBusMessage *m = NULL;
  DBusMessage *reply = NULL;
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
  DBusMessageIter args_iter;
  DBusMessageIter arr_iter;

  if (f->skip)
    return;

  m = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
      DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "UpdateActivationEnvironment");

  if (m == NULL)
    g_error ("OOM");

  dbus_message_iter_init_append (m, &args_iter);

  /* Append an empty a{ss} (string => string dictionary). */
  if (!dbus_message_iter_open_container (&args_iter, DBUS_TYPE_ARRAY,
        "{ss}", &arr_iter) ||
      !dbus_message_iter_close_container (&args_iter, &arr_iter))
    g_error ("OOM");

116 117
  reply = test_main_context_call_and_wait (f->ctx, f->conn, m,
      DBUS_TIMEOUT_USE_DEFAULT);
118 119 120 121

  if (config->expect_success)
    {
      /* it succeeds */
122
      g_assert_cmpint (dbus_message_get_type (reply), ==,
123 124 125 126 127
          DBUS_MESSAGE_TYPE_METHOD_RETURN);
    }
  else
    {
      /* it fails, yielding an error message with one string argument */
128 129
      g_assert_cmpint (dbus_message_get_type (reply), ==, DBUS_MESSAGE_TYPE_ERROR);
      g_assert_cmpstr (dbus_message_get_error_name (reply), ==,
130
          DBUS_ERROR_ACCESS_DENIED);
131
      g_assert_cmpstr (dbus_message_get_signature (reply), ==, "s");
132 133
    }

134 135
  dbus_clear_message (&reply);
  dbus_clear_message (&m);
136 137
}

138 139 140 141 142
static void
test_monitor (Fixture *f,
    gconstpointer context)
{
  const Config *config = context;
143 144
  DBusMessage *m = NULL;
  DBusMessage *reply = NULL;
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
  DBusMessageIter args_iter;
  DBusMessageIter arr_iter;
  dbus_uint32_t no_flags = 0;

  if (f->skip)
    return;

  m = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
      DBUS_PATH_DBUS, DBUS_INTERFACE_MONITORING, "BecomeMonitor");

  if (m == NULL)
    g_error ("OOM");

  dbus_message_iter_init_append (m, &args_iter);

  /* Append an empty as (string array). */
  if (!dbus_message_iter_open_container (&args_iter, DBUS_TYPE_ARRAY,
        "s", &arr_iter) ||
      !dbus_message_iter_close_container (&args_iter, &arr_iter) ||
      !dbus_message_iter_append_basic (&args_iter,
        DBUS_TYPE_UINT32, &no_flags))
    g_error ("OOM");

168 169
  reply = test_main_context_call_and_wait (f->ctx, f->conn, m,
      DBUS_TIMEOUT_USE_DEFAULT);
170 171 172 173

  if (config->expect_success)
    {
      /* it succeeds */
174
      g_assert_cmpint (dbus_message_get_type (reply), ==,
175 176 177 178 179
          DBUS_MESSAGE_TYPE_METHOD_RETURN);
    }
  else
    {
      /* it fails, yielding an error message with one string argument */
180 181
      g_assert_cmpint (dbus_message_get_type (reply), ==, DBUS_MESSAGE_TYPE_ERROR);
      g_assert_cmpstr (dbus_message_get_error_name (reply), ==,
182
          DBUS_ERROR_ACCESS_DENIED);
183
      g_assert_cmpstr (dbus_message_get_signature (reply), ==, "s");
184 185
    }

186 187
  dbus_clear_message (&reply);
  dbus_clear_message (&m);
188 189
}

190 191 192 193 194
/*
 * Assert that AddServer() can be called by the owner of the bus
 * (TEST_USER_MESSAGEBUS) or by root, but cannot be called by other
 * users for now.
 */
195 196 197 198 199 200 201 202 203
static void
teardown (Fixture *f,
    gconstpointer context G_GNUC_UNUSED)
{
  dbus_error_free (&f->e);
  g_clear_error (&f->ge);

  if (f->conn != NULL)
    {
204
      test_connection_shutdown (f->ctx, f->conn);
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
      dbus_connection_close (f->conn);
      dbus_connection_unref (f->conn);
      f->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);
}

220
static Config root_ok_config = {
221 222
    "valid-config-files/multi-user.conf",
    TEST_USER_ROOT,
223
    TRUE
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
};

static Config messagebus_ok_config = {
    "valid-config-files/multi-user.conf",
    TEST_USER_MESSAGEBUS,
    TRUE
};

static Config other_fail_config = {
    "valid-config-files/multi-user.conf",
    TEST_USER_OTHER,
    FALSE
};

int
main (int argc,
    char **argv)
{
242 243
  int ret;

244
  test_init (&argc, &argv);
245

246 247 248 249 250 251
  /* UpdateActivationEnvironment used to be allowed by dbus-daemon for root
   * and messagebus but not for other users (although system.conf forbids it
   * for everyone, and it's useless). It is now hard-coded to fail on a
   * system bus for everyone, so don't assert that root and messagebus
   * may call it; continue to assert that it is denied for unprivileged
   * users though. */
252 253 254
  g_test_add ("/uid-permissions/uae/other", Fixture, &other_fail_config,
      setup, test_uae, teardown);

255 256 257 258 259 260 261 262
  /* BecomeMonitor has the behaviour that UAE used to have. */
  g_test_add ("/uid-permissions/monitor/root", Fixture, &root_ok_config,
      setup, test_monitor, teardown);
  g_test_add ("/uid-permissions/monitor/messagebus", Fixture, &messagebus_ok_config,
      setup, test_monitor, teardown);
  g_test_add ("/uid-permissions/monitor/other", Fixture, &other_fail_config,
      setup, test_monitor, teardown);

263 264 265
  ret = g_test_run ();
  dbus_shutdown ();
  return ret;
266
}