diff --git a/bus/CMakeLists.txt b/bus/CMakeLists.txt index febfaeb0..e464f605 100644 --- a/bus/CMakeLists.txt +++ b/bus/CMakeLists.txt @@ -51,8 +51,6 @@ set(BUS_SOURCES # config-parser-trivial.c connection.c connection.h - containers.c - containers.h desktop-file.c desktop-file.h dir-watch.h diff --git a/bus/bus.c b/bus/bus.c index 62d58f8e..eaa8f2ae 100644 --- a/bus/bus.c +++ b/bus/bus.c @@ -31,7 +31,6 @@ #include "activation.h" #include "connection.h" -#include "containers.h" #include "dispatch.h" #include "services.h" #include "utils.h" @@ -73,7 +72,6 @@ struct BusContext BusMatchmaker *matchmaker; BusLimits limits; DBusRLimit *initial_fd_limit; - BusContainers *containers; unsigned int fork : 1; unsigned int syslog : 1; unsigned int keep_umask : 1; @@ -921,14 +919,6 @@ bus_context_new (const DBusString *config_file, goto failed; } - context->containers = bus_containers_new (); - - if (context->containers == NULL) - { - BUS_SET_OOM (error); - goto failed; - } - /* check user before we fork */ if (context->user != NULL) { @@ -1227,9 +1217,6 @@ bus_context_shutdown (BusContext *context) link = _dbus_list_get_next_link (&context->servers, link); } - - if (context->containers != NULL) - bus_containers_stop_listening (context->containers); } BusContext * @@ -1300,7 +1287,6 @@ bus_context_unref (BusContext *context) context->matchmaker = NULL; } - bus_clear_containers (&context->containers); dbus_free (context->config_file); dbus_free (context->log_prefix); dbus_free (context->type); @@ -1405,12 +1391,6 @@ bus_context_allow_windows_user (BusContext *context, windows_sid); } -BusContainers * -bus_context_get_containers (BusContext *context) -{ - return context->containers; -} - BusClientPolicy* bus_context_create_client_policy (BusContext *context, DBusConnection *connection, diff --git a/bus/bus.h b/bus/bus.h index 88451ebb..b970be65 100644 --- a/bus/bus.h +++ b/bus/bus.h @@ -113,7 +113,6 @@ dbus_bool_t bus_context_allow_unix_user (BusContext unsigned long uid); dbus_bool_t bus_context_allow_windows_user (BusContext *context, const char *windows_sid); -BusContainers *bus_context_get_containers (BusContext *context); BusClientPolicy* bus_context_create_client_policy (BusContext *context, DBusConnection *connection, diff --git a/bus/connection.c b/bus/connection.c index f0177c6f..e7917778 100644 --- a/bus/connection.c +++ b/bus/connection.c @@ -26,7 +26,6 @@ #include #include "connection.h" -#include "containers.h" #include "dispatch.h" #include "policy.h" #include "services.h" @@ -311,9 +310,6 @@ bus_connection_disconnected (DBusConnection *connection) d->link_in_monitors = NULL; } - bus_containers_remove_connection (bus_context_get_containers (d->connections->context), - connection); - if (d->link_in_connection_list != NULL) { if (d->name != NULL) @@ -593,9 +589,6 @@ cache_peer_loginfo_string (BusConnectionData *d, const char *windows_sid = NULL; const char *security_label = NULL; dbus_bool_t prev_added; - const char *container = NULL; - const char *container_type = NULL; - const char *container_name = NULL; DBusCredentials *credentials; if (!_dbus_string_init (&loginfo_buf)) @@ -676,30 +669,6 @@ cache_peer_loginfo_string (BusConnectionData *d, prev_added = TRUE; } - /* This does have to come from the connection, not the credentials */ - if (bus_containers_connection_is_contained (connection, &container, - &container_type, - &container_name)) - { - dbus_bool_t did_append; - - if (prev_added) - { - if (!_dbus_string_append_byte (&loginfo_buf, ' ')) - goto oom; - } - - did_append = _dbus_string_append_printf (&loginfo_buf, - "container=%s %s=\"%s\")", - container, - container_type, - container_name); - if (!did_append) - goto oom; - else - prev_added = TRUE; - } - if (!_dbus_string_steal_data (&loginfo_buf, &(d->cached_loginfo_string))) goto oom; @@ -2472,26 +2441,6 @@ bus_transaction_send (BusTransaction *transaction, d = BUS_CONNECTION_DATA (destination); _dbus_assert (d != NULL); - /* You might think that this is too late to be setting header fields, - * because the message is locked before sending - but remember that - * the message isn't actually queued to be sent (and hence locked) - * until we know we have enough memory for the entire transaction, - * and that doesn't happen until we know all the recipients. - * So this is about the last possible time we could edit the header. */ - if ((d->want_headers & BUS_EXTRA_HEADERS_CONTAINER_INSTANCE) && - dbus_message_get_container_instance (message) == NULL) - { - const char *path; - - if (sender == NULL || - !bus_containers_connection_is_contained (sender, &path, - NULL, NULL)) - path = "/"; - - if (!dbus_message_set_container_instance (message, path)) - return FALSE; - } - to_send = dbus_new (MessageToSend, 1); if (to_send == NULL) { diff --git a/bus/containers.c b/bus/containers.c deleted file mode 100644 index 816f3e1b..00000000 --- a/bus/containers.c +++ /dev/null @@ -1,1480 +0,0 @@ -/* containers.c - restricted bus servers for containers - * - * Copyright © 2017 Collabora Ltd. - * - * SPDX-License-Identifier: AFL-2.1 OR GPL-2.0-or-later - * - * Licensed under the Academic Free License version 2.1 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#include -#include "containers.h" - -#include "dbus/dbus-internals.h" - -#ifdef DBUS_ENABLE_CONTAINERS - -#error This feature is not ready for production use - -#ifndef DBUS_UNIX -# error DBUS_ENABLE_CONTAINERS requires DBUS_UNIX -#endif - -#include - -#include "dbus/dbus-hash.h" -#include "dbus/dbus-message-internal.h" -#include "dbus/dbus-sysdeps-unix.h" - -#include "connection.h" -#include "dispatch.h" -#include "driver.h" -#include "utils.h" - -/* - * A container instance groups together a per-app-container server with - * all the connections for which it is responsible. - */ -typedef struct -{ - int refcount; - char *path; - char *type; - char *name; - DBusVariant *metadata; - BusContext *context; - BusContainers *containers; - DBusServer *server; - DBusConnection *creator; - /* List of owned DBusConnection, removed when the DBusConnection is - * removed from the bus */ - DBusList *connections; - unsigned long uid; - unsigned announced:1; -} BusContainerInstance; - -/* Data attached to a DBusConnection that has created container instances. */ -typedef struct -{ - /* List of instances created by this connection; unowned. - * The BusContainerInstance removes itself from here on destruction. */ - DBusList *instances; -} BusContainerCreatorData; - -/* Data slot on DBusConnection, holding BusContainerCreatorData */ -static dbus_int32_t container_creator_data_slot = -1; - -/* - * Singleton data structure encapsulating the container-related parts of - * a BusContext. - */ -struct BusContainers -{ - int refcount; - /* path borrowed from BusContainerInstance => unowned BusContainerInstance - * The BusContainerInstance removes itself from here on destruction. */ - DBusHashTable *instances_by_path; - /* uid => (void *) (uintptr_t) number of containers */ - DBusHashTable *n_containers_by_user; - DBusString address_template; - dbus_uint64_t next_container_id; -}; - -/* Data slot on DBusConnection, holding BusContainerInstance */ -static dbus_int32_t contained_data_slot = -1; - -BusContainers * -bus_containers_new (void) -{ - /* We allocate the hash table lazily, expecting that the common case will - * be a connection where this feature is never used */ - BusContainers *self = NULL; - DBusString invalid = _DBUS_STRING_INIT_INVALID; - - /* One reference per BusContainers, unless we ran out of memory the first - * time we tried to allocate it, in which case it will be -1 when we - * free the BusContainers */ - if (!dbus_connection_allocate_data_slot (&contained_data_slot)) - goto oom; - - /* Ditto */ - if (!dbus_connection_allocate_data_slot (&container_creator_data_slot)) - goto oom; - - self = dbus_new0 (BusContainers, 1); - - if (self == NULL) - goto oom; - - self->refcount = 1; - self->instances_by_path = NULL; - self->next_container_id = DBUS_UINT64_CONSTANT (0); - self->address_template = invalid; - - /* Make it mutable */ - if (!_dbus_string_init (&self->address_template)) - goto oom; - - if (_dbus_getuid () == 0) - { - DBusString dir; - - /* System bus (we haven't dropped privileges at this point), or - * root's session bus. Use random socket paths resembling - * /run/dbus/containers/dbus-abcdef, which is next to /run/dbus/pid - * (if not using the Red Hat init scripts, which use a different - * pid file for historical reasons). - * - * We rely on the tmpfiles.d snippet or an OS-specific init script to - * have created this directory with the appropriate owner; if it hasn't, - * creating container sockets will just fail. */ - _dbus_string_init_const (&dir, DBUS_RUNSTATEDIR "/dbus/containers"); - - /* We specifically use paths, because an abstract socket that you can't - * bind-mount is not particularly useful. */ - if (!_dbus_string_append (&self->address_template, "unix:dir=") || - !_dbus_address_append_escaped (&self->address_template, &dir)) - goto oom; - } - else - { - /* Otherwise defer creating the directory for sockets until we need it, - * so that we can have better error behaviour */ - } - - return self; - -oom: - if (self != NULL) - { - /* This will free the data slot too */ - bus_containers_unref (self); - } - else - { - if (contained_data_slot != -1) - dbus_connection_free_data_slot (&contained_data_slot); - - if (container_creator_data_slot != -1) - dbus_connection_free_data_slot (&container_creator_data_slot); - } - - return NULL; -} - -BusContainers * -bus_containers_ref (BusContainers *self) -{ - _dbus_assert (self->refcount > 0); - _dbus_assert (self->refcount < _DBUS_INT_MAX); - - self->refcount++; - return self; -} - -void -bus_containers_unref (BusContainers *self) -{ - _dbus_assert (self != NULL); - _dbus_assert (self->refcount > 0); - - if (--self->refcount == 0) - { - _dbus_clear_hash_table (&self->instances_by_path); - _dbus_clear_hash_table (&self->n_containers_by_user); - _dbus_string_free (&self->address_template); - dbus_free (self); - - if (contained_data_slot != -1) - dbus_connection_free_data_slot (&contained_data_slot); - - if (container_creator_data_slot != -1) - dbus_connection_free_data_slot (&container_creator_data_slot); - } -} - -static BusContainerInstance * -bus_container_instance_ref (BusContainerInstance *self) -{ - _dbus_assert (self->refcount > 0); - _dbus_assert (self->refcount < _DBUS_INT_MAX); - - self->refcount++; - return self; -} - -static dbus_bool_t -bus_container_instance_emit_removed (BusContainerInstance *self) -{ - BusTransaction *transaction = NULL; - DBusMessage *message = NULL; - DBusError error = DBUS_ERROR_INIT; - - transaction = bus_transaction_new (self->context); - - if (transaction == NULL) - goto oom; - - message = dbus_message_new_signal (DBUS_PATH_DBUS, - DBUS_INTERFACE_CONTAINERS1, - "InstanceRemoved"); - - if (message == NULL || - !dbus_message_set_sender (message, DBUS_SERVICE_DBUS) || - !dbus_message_append_args (message, - DBUS_TYPE_OBJECT_PATH, &self->path, - DBUS_TYPE_INVALID) || - !bus_transaction_capture (transaction, NULL, NULL, message)) - goto oom; - - if (!bus_dispatch_matches (transaction, NULL, NULL, message, &error)) - { - if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) - goto oom; - - /* This can't actually happen, because all of the error cases in - * bus_dispatch_matches() are only if there is an addressed recipient - * (a unicast message), which there is not in this case. But if it - * somehow does happen, we don't want to stay in the OOM-retry loop, - * because waiting for more memory will not help; so continue to - * execute the transaction anyway. */ - _dbus_warn ("Failed to send InstanceRemoved for a reason " - "other than OOM: %s: %s", error.name, error.message); - dbus_error_free (&error); - } - - bus_transaction_execute_and_free (transaction); - dbus_message_unref (message); - _DBUS_ASSERT_ERROR_IS_CLEAR (&error); - return TRUE; - -oom: - dbus_error_free (&error); - dbus_clear_message (&message); - - if (transaction != NULL) - bus_transaction_cancel_and_free (transaction); - - return FALSE; -} - -static void -bus_container_instance_unref (BusContainerInstance *self) -{ - _dbus_assert (self->refcount > 0); - - if (--self->refcount == 0) - { - BusContainerCreatorData *creator_data; - - /* If we announced the container instance in a reply from - * AddServer() (which is also the time at which it becomes - * available for the querying methods), then we have to emit - * InstanceRemoved for it. - * - * Similar to bus/connection.c dropping well-known name ownership, - * this isn't really a situation where we can "fail", because - * this last-unref is likely to be happening as a result of a - * connection disconnecting; so we use a retry loop on OOM. */ - for (; self->announced; _dbus_wait_for_memory ()) - { - if (bus_container_instance_emit_removed (self)) - self->announced = FALSE; - } - - /* As long as the server is listening, the BusContainerInstance can't - * be freed, because the DBusServer holds a reference to the - * BusContainerInstance */ - _dbus_assert (self->server == NULL); - - /* Similarly, as long as there are connections, the BusContainerInstance - * can't be freed, because each connection holds a reference to the - * BusContainerInstance */ - _dbus_assert (self->connections == NULL); - - creator_data = dbus_connection_get_data (self->creator, - container_creator_data_slot); - _dbus_assert (creator_data != NULL); - _dbus_list_remove (&creator_data->instances, self); - - /* It's OK to do this even if we were never added to instances_by_path, - * because the paths are globally unique. */ - if (self->path != NULL && self->containers->instances_by_path != NULL && - _dbus_hash_table_remove_string (self->containers->instances_by_path, - self->path)) - { - DBusHashIter entry; - uintptr_t n = 0; - - if (!_dbus_hash_iter_lookup (self->containers->n_containers_by_user, - (void *) (uintptr_t) self->uid, - FALSE, &entry)) - _dbus_assert_not_reached ("Container should not be placed in " - "instances_by_path until its " - "n_containers_by_user entry has " - "been allocated"); - - n = (uintptr_t) _dbus_hash_iter_get_value (&entry); - _dbus_assert (n > 0); - n -= 1; - _dbus_hash_iter_set_value (&entry, (void *) n); - } - - _dbus_clear_variant (&self->metadata); - bus_context_unref (self->context); - bus_containers_unref (self->containers); - dbus_connection_unref (self->creator); - dbus_free (self->path); - dbus_free (self->type); - dbus_free (self->name); - dbus_free (self); - } -} - -static inline void -bus_clear_container_instance (BusContainerInstance **instance_p) -{ - _dbus_clear_pointer_impl (BusContainerInstance, instance_p, - bus_container_instance_unref); -} - -static void -bus_container_instance_stop_listening (BusContainerInstance *self) -{ - /* In case the DBusServer holds the last reference to self */ - bus_container_instance_ref (self); - - if (self->server != NULL) - { - dbus_server_set_new_connection_function (self->server, NULL, NULL, NULL); - dbus_server_disconnect (self->server); - dbus_clear_server (&self->server); - } - - bus_container_instance_unref (self); -} - -static BusContainerInstance * -bus_container_instance_new (BusContext *context, - BusContainers *containers, - DBusConnection *creator, - DBusError *error) -{ - BusContainerInstance *self = NULL; - DBusString path = _DBUS_STRING_INIT_INVALID; - - _dbus_assert (context != NULL); - _dbus_assert (containers != NULL); - _dbus_assert (creator != NULL); - _DBUS_ASSERT_ERROR_IS_CLEAR (error); - - if (!_dbus_string_init (&path)) - { - BUS_SET_OOM (error); - goto fail; - } - - self = dbus_new0 (BusContainerInstance, 1); - - if (self == NULL) - { - BUS_SET_OOM (error); - goto fail; - } - - self->refcount = 1; - self->type = NULL; - self->name = NULL; - self->metadata = NULL; - self->context = bus_context_ref (context); - self->containers = bus_containers_ref (containers); - self->server = NULL; - self->creator = dbus_connection_ref (creator); - - if (containers->next_container_id >= - DBUS_UINT64_CONSTANT (0xFFFFFFFFFFFFFFFF)) - { - /* We can't increment it any further without wrapping around */ - dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, - "Too many containers created during the lifetime of " - "this bus"); - goto fail; - } - - if (!_dbus_string_append_printf (&path, - "/org/freedesktop/DBus/Containers1/c%" DBUS_INT64_MODIFIER "u", - containers->next_container_id++)) - { - BUS_SET_OOM (error); - goto fail; - } - - if (!_dbus_string_steal_data (&path, &self->path)) - goto fail; - - _dbus_string_free (&path); - return self; - -fail: - _dbus_string_free (&path); - - if (self != NULL) - bus_container_instance_unref (self); - - return NULL; -} - -static void -bus_container_creator_data_free (BusContainerCreatorData *self) -{ - /* Each instance holds a ref to the creator, so there should be - * nothing here */ - _dbus_assert (self->instances == NULL); - - dbus_free (self); -} - -/* We only accept EXTERNAL authentication, because Unix platforms that are - * sufficiently capable to have app-containers ought to have it. */ -static const char * const auth_mechanisms[] = -{ - "EXTERNAL", - NULL -}; - -/* Statically assert that we can store a uid in a void *, losslessly. - * - * In practice this is always true on Unix. For now we don't support this - * feature on systems where it isn't. */ -_DBUS_STATIC_ASSERT (sizeof (uid_t) <= sizeof (uintptr_t)); -/* True by definition. */ -_DBUS_STATIC_ASSERT (sizeof (void *) == sizeof (uintptr_t)); - -static dbus_bool_t -allow_same_uid_only (DBusConnection *connection, - unsigned long uid, - void *data) -{ - return (uid == (uintptr_t) data); -} - -static void -bus_container_instance_lost_connection (BusContainerInstance *instance, - DBusConnection *connection) -{ - bus_container_instance_ref (instance); - dbus_connection_ref (connection); - - /* This is O(n), but we don't expect to have many connections per - * container instance. */ - if (_dbus_list_remove (&instance->connections, connection)) - dbus_connection_unref (connection); - - /* We don't set connection's contained_data_slot to NULL, to make sure - * that once we have marked a connection as belonging to a container, - * there is no going back: even if we somehow keep a reference to it - * around, it will never be treated as uncontained. The connection's - * reference to the instance will be cleaned up on last-unref, and - * the list removal above ensures that the instance does not hold a - * circular ref to the connection, so the last-unref will happen. */ - - dbus_connection_unref (connection); - bus_container_instance_unref (instance); -} - -static void -new_connection_cb (DBusServer *server, - DBusConnection *new_connection, - void *data) -{ - BusContainerInstance *instance = data; - int limit = bus_context_get_max_connections_per_container (instance->context); - - /* This is O(n), but we assume n is small in practice. */ - if (_dbus_list_get_length (&instance->connections) >= limit) - { - /* We can't send this error to the new connection, so just log it */ - bus_context_log (instance->context, DBUS_SYSTEM_LOG_WARNING, - "Closing connection to container server " - "%s (%s \"%s\") because it would exceed resource limit " - "(max_connections_per_container=%d)", - instance->path, instance->type, instance->name, limit); - return; - } - - if (!dbus_connection_set_data (new_connection, contained_data_slot, - bus_container_instance_ref (instance), - (DBusFreeFunction) bus_container_instance_unref)) - { - bus_container_instance_unref (instance); - bus_container_instance_lost_connection (instance, new_connection); - return; - } - - if (_dbus_list_append (&instance->connections, new_connection)) - { - dbus_connection_ref (new_connection); - } - else - { - bus_container_instance_lost_connection (instance, new_connection); - return; - } - - /* If this fails it logs a warning, so we don't need to do that. - * We don't know how to undo this, so do it last (apart from things that - * cannot fail) */ - if (!bus_context_add_incoming_connection (instance->context, new_connection)) - { - bus_container_instance_lost_connection (instance, new_connection); - return; - } - - /* We'd like to check the uid here, but we can't yet. Instead clear the - * BusContext's unix_user_function, which results in us getting the - * default behaviour: only the user that owns the bus can connect. - * - * TODO: For the system bus we might want a way to opt-in to allowing - * other uids, in which case we would refrain from overwriting the - * BusContext's unix_user_function; but that isn't part of the - * lowest-common-denominator implementation. */ - dbus_connection_set_unix_user_function (new_connection, - allow_same_uid_only, - /* The static assertion above - * allow_same_uid_only ensures that - * this cast does not lose - * information */ - (void *) (uintptr_t) instance->uid, - NULL); -} - -static const char * -bus_containers_ensure_address_template (BusContainers *self, - DBusError *error) -{ - DBusString dir = _DBUS_STRING_INIT_INVALID; - const char *ret = NULL; - const char *runtime_dir; - - /* Early-return if we already did this */ - if (_dbus_string_get_length (&self->address_template) > 0) - return _dbus_string_get_const_data (&self->address_template); - - runtime_dir = _dbus_getenv ("XDG_RUNTIME_DIR"); - - if (runtime_dir != NULL) - { - if (!_dbus_string_init (&dir)) - { - BUS_SET_OOM (error); - goto out; - } - - /* We listen on a random socket path resembling - * /run/user/1000/dbus-1/containers/dbus-abcdef, chosen to share - * the dbus-1 directory with the dbus-1/services used for transient - * session services. */ - if (!_dbus_string_append (&dir, runtime_dir) || - !_dbus_string_append (&dir, "/dbus-1")) - { - BUS_SET_OOM (error); - goto out; - } - - if (!_dbus_ensure_directory (&dir, error)) - goto out; - - if (!_dbus_string_append (&dir, "/containers")) - { - BUS_SET_OOM (error); - goto out; - } - - if (!_dbus_ensure_directory (&dir, error)) - goto out; - } - else - { - /* No XDG_RUNTIME_DIR, so don't do anything special or clever: just - * use a random socket like /tmp/dbus-abcdef. */ - const char *tmpdir; - - tmpdir = _dbus_get_tmpdir (); - _dbus_string_init_const (&dir, tmpdir); - } - - /* We specifically use paths, even on Linux (unix:dir= not unix:tmpdir=), - * because an abstract socket that you can't bind-mount is not useful - * when you want something you can bind-mount into a container. */ - if (!_dbus_string_append (&self->address_template, "unix:dir=") || - !_dbus_address_append_escaped (&self->address_template, &dir)) - { - _dbus_string_set_length (&self->address_template, 0); - BUS_SET_OOM (error); - goto out; - } - - ret = _dbus_string_get_const_data (&self->address_template); - -out: - _dbus_string_free (&dir); - return ret; -} - -static dbus_bool_t -bus_container_instance_listen (BusContainerInstance *self, - DBusError *error) -{ - BusContainers *containers = bus_context_get_containers (self->context); - const char *address; - - address = bus_containers_ensure_address_template (containers, error); - - if (address == NULL) - return FALSE; - - self->server = dbus_server_listen (address, error); - - if (self->server == NULL) - return FALSE; - - if (!bus_context_setup_server (self->context, self->server, error)) - return FALSE; - - if (!dbus_server_set_auth_mechanisms (self->server, - (const char **) auth_mechanisms)) - { - BUS_SET_OOM (error); - return FALSE; - } - - /* Cannot fail because the memory it uses was already allocated */ - dbus_server_set_new_connection_function (self->server, new_connection_cb, - bus_container_instance_ref (self), - (DBusFreeFunction) bus_container_instance_unref); - return TRUE; -} - -dbus_bool_t -bus_containers_handle_add_server (DBusConnection *connection, - BusTransaction *transaction, - DBusMessage *message, - DBusError *error) -{ - BusContainerCreatorData *creator_data; - DBusMessageIter iter; - DBusMessageIter dict_iter; - DBusMessageIter writer; - DBusMessageIter array_writer; - const char *type; - const char *name; - const char *path; - BusContainerInstance *instance = NULL; - BusContext *context; - BusContainers *containers; - char *address = NULL; - DBusAddressEntry **entries = NULL; - int n_entries; - DBusMessage *reply = NULL; - int metadata_size; - int limit; - DBusHashIter n_containers_by_user_entry; - uintptr_t this_user_containers = 0; - - context = bus_transaction_get_context (transaction); - containers = bus_context_get_containers (context); - - creator_data = dbus_connection_get_data (connection, - container_creator_data_slot); - - if (creator_data == NULL) - { - creator_data = dbus_new0 (BusContainerCreatorData, 1); - - if (creator_data == NULL) - goto oom; - - creator_data->instances = NULL; - - if (!dbus_connection_set_data (connection, container_creator_data_slot, - creator_data, - (DBusFreeFunction) bus_container_creator_data_free)) - { - bus_container_creator_data_free (creator_data); - goto oom; - } - } - - instance = bus_container_instance_new (context, containers, connection, - error); - - if (instance == NULL) - goto fail; - - if (!dbus_connection_get_unix_user (connection, &instance->uid)) - { - dbus_set_error (error, DBUS_ERROR_FAILED, - "Unable to determine user ID of caller"); - goto fail; - } - - /* We already checked this in bus_driver_handle_message() */ - _dbus_assert (dbus_message_has_signature (message, "ssa{sv}a{sv}")); - - /* Argument 0: Container type */ - if (!dbus_message_iter_init (message, &iter)) - _dbus_assert_not_reached ("Message type was already checked"); - - _dbus_assert (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_STRING); - dbus_message_iter_get_basic (&iter, &type); - instance->type = _dbus_strdup (type); - - if (instance->type == NULL) - goto oom; - - if (!dbus_validate_interface (type, NULL)) - { - dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, - "The container type identifier must have the " - "syntax of an interface name"); - goto fail; - } - - /* Argument 1: Name as defined by container manager */ - if (!dbus_message_iter_next (&iter)) - _dbus_assert_not_reached ("Message type was already checked"); - - _dbus_assert (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_STRING); - dbus_message_iter_get_basic (&iter, &name); - instance->name = _dbus_strdup (name); - - if (instance->name == NULL) - goto oom; - - /* Argument 2: Metadata as defined by container manager */ - if (!dbus_message_iter_next (&iter)) - _dbus_assert_not_reached ("Message type was already checked"); - - _dbus_assert (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_ARRAY); - instance->metadata = _dbus_variant_read (&iter); - _dbus_assert (strcmp (_dbus_variant_get_signature (instance->metadata), - "a{sv}") == 0); - - /* For simplicity we don't count the size of the BusContainerInstance - * itself, the object path, lengths, the non-payload parts of the DBusString, - * NUL terminators and so on. That overhead is O(1) and relatively small. - * This cannot overflow because all parts came from a message, and messages - * are constrained to be orders of magnitude smaller than the maximum - * int value. */ - metadata_size = _dbus_variant_get_length (instance->metadata) + - (int) strlen (type) + - (int) strlen (name); - limit = bus_context_get_max_container_metadata_bytes (context); - - if (metadata_size > limit) - { - DBusError local_error = DBUS_ERROR_INIT; - - dbus_set_error (&local_error, DBUS_ERROR_LIMITS_EXCEEDED, - "Connection \"%s\" (%s) is not allowed to set " - "%d bytes of container metadata " - "(max_container_metadata_bytes=%d)", - bus_connection_get_name (connection), - bus_connection_get_loginfo (connection), - metadata_size, limit); - bus_context_log_literal (context, DBUS_SYSTEM_LOG_WARNING, - local_error.message); - dbus_move_error (&local_error, error); - goto fail; - } - - /* Argument 3: Named parameters */ - if (!dbus_message_iter_next (&iter)) - _dbus_assert_not_reached ("Message type was already checked"); - - _dbus_assert (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_ARRAY); - dbus_message_iter_recurse (&iter, &dict_iter); - - while (dbus_message_iter_get_arg_type (&dict_iter) != DBUS_TYPE_INVALID) - { - DBusMessageIter pair_iter; - const char *param_name; - - _dbus_assert (dbus_message_iter_get_arg_type (&dict_iter) == - DBUS_TYPE_DICT_ENTRY); - - dbus_message_iter_recurse (&dict_iter, &pair_iter); - _dbus_assert (dbus_message_iter_get_arg_type (&pair_iter) == - DBUS_TYPE_STRING); - dbus_message_iter_get_basic (&pair_iter, ¶m_name); - - /* If we supported any named parameters, we'd copy them into the data - * structure here; but we don't, so fail instead. */ - dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, - "Named parameter %s is not understood", param_name); - goto fail; - } - - /* End of arguments */ - _dbus_assert (!dbus_message_iter_has_next (&iter)); - - if (containers->instances_by_path == NULL) - { - containers->instances_by_path = _dbus_hash_table_new (DBUS_HASH_STRING, - NULL, NULL); - - if (containers->instances_by_path == NULL) - goto oom; - } - - if (containers->n_containers_by_user == NULL) - { - containers->n_containers_by_user = _dbus_hash_table_new (DBUS_HASH_UINTPTR, - NULL, NULL); - - if (containers->n_containers_by_user == NULL) - goto oom; - } - - limit = bus_context_get_max_containers (context); - - if (_dbus_hash_table_get_n_entries (containers->instances_by_path) >= limit) - { - DBusError local_error = DBUS_ERROR_INIT; - - dbus_set_error (&local_error, DBUS_ERROR_LIMITS_EXCEEDED, - "Connection \"%s\" (%s) is not allowed to create more " - "container servers (max_containers=%d)", - bus_connection_get_name (connection), - bus_connection_get_loginfo (connection), - limit); - bus_context_log_literal (context, DBUS_SYSTEM_LOG_WARNING, - local_error.message); - dbus_move_error (&local_error, error); - goto fail; - } - - if (!_dbus_hash_iter_lookup (containers->n_containers_by_user, - /* We statically assert that a uid fits in a - * uintptr_t, so this can't lose information */ - (void *) (uintptr_t) instance->uid, TRUE, - &n_containers_by_user_entry)) - goto oom; - - this_user_containers = (uintptr_t) _dbus_hash_iter_get_value (&n_containers_by_user_entry); - limit = bus_context_get_max_containers_per_user (context); - - /* We need to be careful with types here because this_user_containers is - * unsigned. */ - if (limit <= 0 || this_user_containers >= (unsigned) limit) - { - DBusError local_error = DBUS_ERROR_INIT; - - dbus_set_error (&local_error, DBUS_ERROR_LIMITS_EXCEEDED, - "Connection \"%s\" (%s) is not allowed to create more " - "container servers for uid %lu " - "(max_containers_per_user=%d)", - bus_connection_get_name (connection), - bus_connection_get_loginfo (connection), - instance->uid, limit); - bus_context_log_literal (context, DBUS_SYSTEM_LOG_WARNING, - local_error.message); - dbus_move_error (&local_error, error); - goto fail; - } - - if (!_dbus_hash_table_insert_string (containers->instances_by_path, - instance->path, instance)) - goto oom; - - /* This cannot fail (we already allocated the memory) so we can do it after - * we already succeeded in adding it to instances_by_path. The matching - * decrement is done whenever we remove it from instances_by_path. */ - this_user_containers += 1; - _dbus_hash_iter_set_value (&n_containers_by_user_entry, - (void *) this_user_containers); - - if (!_dbus_list_append (&creator_data->instances, instance)) - goto oom; - - /* This part is separated out because we eventually want to be able to - * accept a fd-passed server socket in the named parameters, instead of - * creating our own server, and defer listening on it until later */ - if (!bus_container_instance_listen (instance, error)) - goto fail; - - address = dbus_server_get_address (instance->server); - - if (!dbus_parse_address (address, &entries, &n_entries, error)) - _dbus_assert_not_reached ("listening on unix:dir= should yield a valid address"); - - _dbus_assert (n_entries == 1); - _dbus_assert (strcmp (dbus_address_entry_get_method (entries[0]), "unix") == 0); - - path = dbus_address_entry_get_value (entries[0], "path"); - _dbus_assert (path != NULL); - - reply = dbus_message_new_method_return (message); - - if (!dbus_message_append_args (reply, - DBUS_TYPE_OBJECT_PATH, &instance->path, - DBUS_TYPE_INVALID)) - goto oom; - - dbus_message_iter_init_append (reply, &writer); - - if (!dbus_message_iter_open_container (&writer, DBUS_TYPE_ARRAY, - DBUS_TYPE_BYTE_AS_STRING, - &array_writer)) - goto oom; - - if (!dbus_message_iter_append_fixed_array (&array_writer, DBUS_TYPE_BYTE, - &path, strlen (path) + 1)) - { - dbus_message_iter_abandon_container (&writer, &array_writer); - goto oom; - } - - if (!dbus_message_iter_close_container (&writer, &array_writer)) - goto oom; - - if (!dbus_message_append_args (reply, - DBUS_TYPE_STRING, &address, - DBUS_TYPE_INVALID)) - goto oom; - - _dbus_assert (dbus_message_has_signature (reply, "oays")); - - if (! bus_transaction_send_from_driver (transaction, connection, reply)) - goto oom; - - instance->announced = TRUE; - dbus_message_unref (reply); - bus_container_instance_unref (instance); - dbus_address_entries_free (entries); - dbus_free (address); - return TRUE; - -oom: - BUS_SET_OOM (error); - /* fall through */ -fail: - if (instance != NULL) - bus_container_instance_stop_listening (instance); - - dbus_clear_message (&reply); - dbus_clear_address_entries (&entries); - bus_clear_container_instance (&instance); - dbus_free (address); - return FALSE; -} - -dbus_bool_t -bus_containers_supported_arguments_getter (BusContext *context, - DBusMessageIter *var_iter) -{ - DBusMessageIter arr_iter; - - /* There are none so far */ - return dbus_message_iter_open_container (var_iter, DBUS_TYPE_ARRAY, - DBUS_TYPE_STRING_AS_STRING, - &arr_iter) && - dbus_message_iter_close_container (var_iter, &arr_iter); -} - -dbus_bool_t -bus_containers_handle_stop_instance (DBusConnection *connection, - BusTransaction *transaction, - DBusMessage *message, - DBusError *error) -{ - BusContext *context; - BusContainers *containers; - BusContainerInstance *instance = NULL; - DBusList *iter; - const char *path; - unsigned long uid; - - if (!dbus_message_get_args (message, error, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) - goto failed; - - context = bus_transaction_get_context (transaction); - containers = bus_context_get_containers (context); - - if (containers->instances_by_path != NULL) - { - instance = _dbus_hash_table_lookup_string (containers->instances_by_path, - path); - } - - if (instance == NULL) - { - dbus_set_error (error, DBUS_ERROR_NOT_CONTAINER, - "There is no container with path '%s'", path); - goto failed; - } - - if (!dbus_connection_get_unix_user (connection, &uid)) - { - dbus_set_error (error, DBUS_ERROR_FAILED, - "Unable to determine user ID of caller"); - goto failed; - } - - if (uid != instance->uid) - { - dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, - "User %lu cannot stop a container server started by " - "user %lu", uid, instance->uid); - goto failed; - } - - bus_container_instance_ref (instance); - bus_container_instance_stop_listening (instance); - - for (iter = _dbus_list_get_first_link (&instance->connections); - iter != NULL; - iter = _dbus_list_get_next_link (&instance->connections, iter)) - dbus_connection_close (iter->data); - - bus_container_instance_unref (instance); - - if (!bus_driver_send_ack_reply (connection, transaction, message, error)) - goto failed; - - return TRUE; - -failed: - _DBUS_ASSERT_ERROR_IS_SET (error); - return FALSE; -} - -dbus_bool_t -bus_containers_handle_stop_listening (DBusConnection *connection, - BusTransaction *transaction, - DBusMessage *message, - DBusError *error) -{ - BusContext *context; - BusContainers *containers; - BusContainerInstance *instance = NULL; - const char *path; - unsigned long uid; - - if (!dbus_message_get_args (message, error, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) - goto failed; - - context = bus_transaction_get_context (transaction); - containers = bus_context_get_containers (context); - - if (containers->instances_by_path != NULL) - { - instance = _dbus_hash_table_lookup_string (containers->instances_by_path, - path); - } - - if (instance == NULL) - { - dbus_set_error (error, DBUS_ERROR_NOT_CONTAINER, - "There is no container with path '%s'", path); - goto failed; - } - - if (!dbus_connection_get_unix_user (connection, &uid)) - { - dbus_set_error (error, DBUS_ERROR_FAILED, - "Unable to determine user ID of caller"); - goto failed; - } - - if (uid != instance->uid) - { - dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, - "User %lu cannot stop a container server started by " - "user %lu", uid, instance->uid); - goto failed; - } - - bus_container_instance_ref (instance); - bus_container_instance_stop_listening (instance); - bus_container_instance_unref (instance); - - if (!bus_driver_send_ack_reply (connection, transaction, message, error)) - goto failed; - - return TRUE; - -failed: - _DBUS_ASSERT_ERROR_IS_SET (error); - return FALSE; -} - -/* - * This accepts a NULL connection so that it can be used when checking - * whether to allow sending or receiving a message, which might involve - * the dbus-daemon itself as a message sender or recipient. - */ -static BusContainerInstance * -connection_get_instance (DBusConnection *connection) -{ - if (connection == NULL) - return NULL; - - if (contained_data_slot == -1) - return NULL; - - return dbus_connection_get_data (connection, contained_data_slot); -} - -dbus_bool_t -bus_containers_handle_get_connection_instance (DBusConnection *caller, - BusTransaction *transaction, - DBusMessage *message, - DBusError *error) -{ - BusContainerInstance *instance; - BusDriverFound found; - DBusConnection *subject; - DBusMessage *reply = NULL; - DBusMessageIter writer; - DBusMessageIter arr_writer; - const char *bus_name; - - _DBUS_ASSERT_ERROR_IS_CLEAR (error); - - found = bus_driver_get_conn_helper (caller, message, "container instance", - &bus_name, &subject, error); - - switch (found) - { - case BUS_DRIVER_FOUND_SELF: - dbus_set_error (error, DBUS_ERROR_NOT_CONTAINER, - "The message bus is not in a container"); - goto failed; - - case BUS_DRIVER_FOUND_PEER: - break; - - case BUS_DRIVER_FOUND_ERROR: - /* fall through */ - default: - goto failed; - } - - instance = connection_get_instance (subject); - - if (instance == NULL) - { - dbus_set_error (error, DBUS_ERROR_NOT_CONTAINER, - "Connection '%s' is not in a container", bus_name); - goto failed; - } - - reply = dbus_message_new_method_return (message); - - if (reply == NULL) - goto oom; - - if (!dbus_message_append_args (reply, - DBUS_TYPE_OBJECT_PATH, &instance->path, - DBUS_TYPE_INVALID)) - goto oom; - - dbus_message_iter_init_append (reply, &writer); - - if (!dbus_message_iter_open_container (&writer, DBUS_TYPE_ARRAY, "{sv}", - &arr_writer)) - goto oom; - - if (!bus_driver_fill_connection_credentials (NULL, instance->creator, - caller, - &arr_writer)) - { - dbus_message_iter_abandon_container (&writer, &arr_writer); - goto oom; - } - - if (!dbus_message_iter_close_container (&writer, &arr_writer)) - goto oom; - - if (!dbus_message_append_args (reply, - DBUS_TYPE_STRING, &instance->type, - DBUS_TYPE_STRING, &instance->name, - DBUS_TYPE_INVALID)) - goto oom; - - dbus_message_iter_init_append (reply, &writer); - - if (!_dbus_variant_write (instance->metadata, &writer)) - goto oom; - - if (!bus_transaction_send_from_driver (transaction, caller, reply)) - goto oom; - - dbus_message_unref (reply); - return TRUE; - -oom: - BUS_SET_OOM (error); - /* fall through */ -failed: - _DBUS_ASSERT_ERROR_IS_SET (error); - - dbus_clear_message (&reply); - return FALSE; -} - -dbus_bool_t -bus_containers_handle_get_instance_info (DBusConnection *connection, - BusTransaction *transaction, - DBusMessage *message, - DBusError *error) -{ - BusContext *context; - BusContainers *containers; - BusContainerInstance *instance = NULL; - DBusMessage *reply = NULL; - DBusMessageIter writer; - DBusMessageIter arr_writer; - const char *path; - - if (!dbus_message_get_args (message, error, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) - goto failed; - - context = bus_transaction_get_context (transaction); - containers = bus_context_get_containers (context); - - if (containers->instances_by_path != NULL) - { - instance = _dbus_hash_table_lookup_string (containers->instances_by_path, - path); - } - - if (instance == NULL) - { - dbus_set_error (error, DBUS_ERROR_NOT_CONTAINER, - "There is no container with path '%s'", path); - goto failed; - } - - reply = dbus_message_new_method_return (message); - - if (reply == NULL) - goto oom; - - dbus_message_iter_init_append (reply, &writer); - - if (!dbus_message_iter_open_container (&writer, DBUS_TYPE_ARRAY, "{sv}", - &arr_writer)) - goto oom; - - if (!bus_driver_fill_connection_credentials (NULL, instance->creator, - connection, - &arr_writer)) - { - dbus_message_iter_abandon_container (&writer, &arr_writer); - goto oom; - } - - if (!dbus_message_iter_close_container (&writer, &arr_writer)) - goto oom; - - if (!dbus_message_append_args (reply, - DBUS_TYPE_STRING, &instance->type, - DBUS_TYPE_STRING, &instance->name, - DBUS_TYPE_INVALID)) - goto oom; - - dbus_message_iter_init_append (reply, &writer); - - if (!_dbus_variant_write (instance->metadata, &writer)) - goto oom; - - if (!bus_transaction_send_from_driver (transaction, connection, reply)) - goto oom; - - dbus_message_unref (reply); - return TRUE; - -oom: - BUS_SET_OOM (error); - /* fall through */ -failed: - _DBUS_ASSERT_ERROR_IS_SET (error); - - dbus_clear_message (&reply); - return FALSE; -} - -dbus_bool_t -bus_containers_handle_request_header (DBusConnection *caller, - BusTransaction *transaction, - DBusMessage *message, - DBusError *error) -{ - DBusMessage *reply = NULL; - dbus_bool_t ret = FALSE; - - reply = dbus_message_new_method_return (message); - - /* We prepare the transaction before carrying out its side-effects, - * because otherwise it isn't transactional */ - if (reply == NULL || - !bus_transaction_send_from_driver (transaction, caller, reply)) - { - BUS_SET_OOM (error); - goto out; - } - - bus_connection_request_headers (caller, - BUS_EXTRA_HEADERS_CONTAINER_INSTANCE); - ret = TRUE; - -out: - dbus_clear_message (&reply); - return ret; -} - -void -bus_containers_stop_listening (BusContainers *self) -{ - if (self->instances_by_path != NULL) - { - DBusHashIter iter; - - _dbus_hash_iter_init (self->instances_by_path, &iter); - - while (_dbus_hash_iter_next (&iter)) - { - BusContainerInstance *instance = _dbus_hash_iter_get_value (&iter); - - bus_container_instance_stop_listening (instance); - } - } -} - -#else - -BusContainers * -bus_containers_new (void) -{ - /* Return an arbitrary non-NULL pointer just to indicate that we didn't - * fail. There is no valid operation to do with it on this platform, - * other than unreffing it, which does nothing. */ - return (BusContainers *) 1; -} - -BusContainers * -bus_containers_ref (BusContainers *self) -{ - _dbus_assert (self == (BusContainers *) 1); - return self; -} - -void -bus_containers_unref (BusContainers *self) -{ - _dbus_assert (self == (BusContainers *) 1); -} - -void -bus_containers_stop_listening (BusContainers *self) -{ - _dbus_assert (self == (BusContainers *) 1); -} - -#endif /* DBUS_ENABLE_CONTAINERS */ - -void -bus_containers_remove_connection (BusContainers *self, - DBusConnection *connection) -{ -#ifdef DBUS_ENABLE_CONTAINERS - BusContainerCreatorData *creator_data; - BusContainerInstance *instance; - - dbus_connection_ref (connection); - creator_data = dbus_connection_get_data (connection, - container_creator_data_slot); - - if (creator_data != NULL) - { - DBusList *iter; - DBusList *next; - - for (iter = _dbus_list_get_first_link (&creator_data->instances); - iter != NULL; - iter = next) - { - instance = iter->data; - - /* Remember where we got to before we do something that might free - * iter and instance */ - next = _dbus_list_get_next_link (&creator_data->instances, iter); - - _dbus_assert (instance->creator == connection); - - /* This will invalidate iter and instance if there are no open - * connections to this instance */ - bus_container_instance_stop_listening (instance); - } - } - - instance = connection_get_instance (connection); - - if (instance != NULL) - bus_container_instance_lost_connection (instance, connection); - - dbus_connection_unref (connection); -#endif /* DBUS_ENABLE_CONTAINERS */ -} - -dbus_bool_t -bus_containers_connection_is_contained (DBusConnection *connection, - const char **path, - const char **type, - const char **name) -{ -#ifdef DBUS_ENABLE_CONTAINERS - BusContainerInstance *instance; - - instance = connection_get_instance (connection); - - if (instance != NULL) - { - if (path != NULL) - *path = instance->path; - - if (type != NULL) - *type = instance->type; - - if (name != NULL) - *name = instance->name; - - return TRUE; - } -#endif /* DBUS_ENABLE_CONTAINERS */ - - return FALSE; -} diff --git a/bus/containers.h b/bus/containers.h deleted file mode 100644 index 842a43f4..00000000 --- a/bus/containers.h +++ /dev/null @@ -1,77 +0,0 @@ -/* containers.h - restricted bus servers for containers - * - * Copyright © 2017 Collabora Ltd. - * - * SPDX-License-Identifier: AFL-2.1 OR GPL-2.0-or-later - * - * Licensed under the Academic Free License version 2.1 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#ifndef BUS_CONTAINERS_H -#define BUS_CONTAINERS_H - -#include "bus.h" - -#include - -BusContainers *bus_containers_new (void); -BusContainers *bus_containers_ref (BusContainers *self); -void bus_containers_unref (BusContainers *self); -void bus_containers_stop_listening (BusContainers *self); - -dbus_bool_t bus_containers_handle_add_server (DBusConnection *connection, - BusTransaction *transaction, - DBusMessage *message, - DBusError *error); -dbus_bool_t bus_containers_handle_stop_instance (DBusConnection *connection, - BusTransaction *transaction, - DBusMessage *message, - DBusError *error); -dbus_bool_t bus_containers_handle_stop_listening (DBusConnection *connection, - BusTransaction *transaction, - DBusMessage *message, - DBusError *error); -dbus_bool_t bus_containers_handle_get_instance_info (DBusConnection *connection, - BusTransaction *transaction, - DBusMessage *message, - DBusError *error); -dbus_bool_t bus_containers_handle_get_connection_instance (DBusConnection *connection, - BusTransaction *transaction, - DBusMessage *message, - DBusError *error); -dbus_bool_t bus_containers_handle_request_header (DBusConnection *connection, - BusTransaction *transaction, - DBusMessage *message, - DBusError *error); -dbus_bool_t bus_containers_supported_arguments_getter (BusContext *context, - DBusMessageIter *var_iter); - -void bus_containers_remove_connection (BusContainers *self, - DBusConnection *connection); -dbus_bool_t bus_containers_connection_is_contained (DBusConnection *connection, - const char **path, - const char **type, - const char **name); - -static inline void -bus_clear_containers (BusContainers **containers_p) -{ - _dbus_clear_pointer_impl (BusContainers, containers_p, bus_containers_unref); -} - -#endif /* multiple-inclusion guard */ diff --git a/bus/driver.c b/bus/driver.c index ebd98015..fa4213c1 100644 --- a/bus/driver.c +++ b/bus/driver.c @@ -28,7 +28,6 @@ #include "activation.h" #include "apparmor.h" #include "connection.h" -#include "containers.h" #include "driver.h" #include "dispatch.h" #include "services.h" @@ -118,19 +117,6 @@ bus_driver_check_caller_is_not_container (DBusConnection *connection, DBusMessage *message, DBusError *error) { - if (bus_containers_connection_is_contained (connection, NULL, NULL, NULL)) - { - const char *method = dbus_message_get_member (message); - - bus_context_log_and_set_error (bus_transaction_get_context (transaction), - DBUS_SYSTEM_LOG_SECURITY, error, DBUS_ERROR_ACCESS_DENIED, - "rejected attempt to call %s by connection %s (%s) in " - "container", method, - nonnull (bus_connection_get_name (connection), "(inactive)"), - bus_connection_get_loginfo (connection)); - return FALSE; - } - return TRUE; } @@ -1970,9 +1956,6 @@ bus_driver_fill_connection_credentials (DBusCredentials *credentials, dbus_pid_t pid = DBUS_PID_UNSET; const char *windows_sid = NULL; const char *linux_security_label = NULL; -#ifdef DBUS_ENABLE_CONTAINERS - const char *path; -#endif #ifdef HAVE_UNIX_FD_PASSING int pid_fd = -1; /* owned by credentials */ #endif @@ -2033,18 +2016,6 @@ bus_driver_fill_connection_credentials (DBusCredentials *credentials, return FALSE; } -#ifdef DBUS_ENABLE_CONTAINERS - /* This has to come from the connection, not the credentials */ - if (peer_conn != NULL && - bus_containers_connection_is_contained (peer_conn, &path, NULL, NULL)) - { - if (!_dbus_asv_add_object_path (asv_iter, - DBUS_INTERFACE_CONTAINERS1 ".Instance", - path)) - return FALSE; - } -#endif - #ifdef HAVE_UNIX_FD_PASSING if (caller_conn != NULL && pid_fd >= 0 && dbus_connection_can_send_type (caller_conn, DBUS_TYPE_UNIX_FD) && @@ -2500,7 +2471,8 @@ typedef enum * containers are never privileged. */ METHOD_FLAG_PRIVILEGED = (1 << 1), - /* If set, callers must not be associated with a container instance. */ + /* If set, callers must not be associated with a container instance. + * (No-op, the Containers1 interface is not present in this branch.) */ METHOD_FLAG_NO_CONTAINERS = (1 << 2), METHOD_FLAG_NONE = 0 @@ -2649,29 +2621,6 @@ static const MessageHandler introspectable_message_handlers[] = { { NULL, NULL, NULL, NULL } }; -#ifdef DBUS_ENABLE_CONTAINERS -static const MessageHandler containers_message_handlers[] = { - { "AddServer", "ssa{sv}a{sv}", "oays", bus_containers_handle_add_server, - METHOD_FLAG_NO_CONTAINERS }, - { "StopInstance", "o", "", bus_containers_handle_stop_instance, - METHOD_FLAG_NO_CONTAINERS }, - { "StopListening", "o", "", bus_containers_handle_stop_listening, - METHOD_FLAG_NO_CONTAINERS }, - { "GetConnectionInstance", "s", "oa{sv}ssa{sv}", - bus_containers_handle_get_connection_instance, - METHOD_FLAG_NONE }, - { "GetInstanceInfo", "o", "a{sv}ssa{sv}", bus_containers_handle_get_instance_info, - METHOD_FLAG_NONE }, - { "RequestHeader", "", "", bus_containers_handle_request_header, - METHOD_FLAG_NONE }, - { NULL, NULL, NULL, NULL } -}; -static const PropertyHandler containers_property_handlers[] = { - { "SupportedArguments", "as", bus_containers_supported_arguments_getter }, - { NULL, NULL, NULL } -}; -#endif - static const MessageHandler monitoring_message_handlers[] = { { "BecomeMonitor", "asu", "", bus_driver_handle_become_monitor, METHOD_FLAG_PRIVILEGED }, @@ -2777,13 +2726,6 @@ static InterfaceHandler interface_handlers[] = { #ifdef DBUS_ENABLE_STATS { BUS_INTERFACE_STATS, stats_message_handlers, NULL, INTERFACE_FLAG_NONE }, -#endif -#ifdef DBUS_ENABLE_CONTAINERS - { DBUS_INTERFACE_CONTAINERS1, containers_message_handlers, - " \n" - " \n" - " \n", - INTERFACE_FLAG_NONE, containers_property_handlers }, #endif { DBUS_INTERFACE_PEER, peer_message_handlers, NULL, /* Not in the Interfaces property because it's a pseudo-interface @@ -3087,16 +3029,6 @@ bus_driver_handle_message (DBusConnection *connection, return FALSE; } } - else if (mh->flags & METHOD_FLAG_NO_CONTAINERS) - { - if (!bus_driver_check_caller_is_not_container (connection, - transaction, - message, error)) - { - _DBUS_ASSERT_ERROR_IS_SET (error); - return FALSE; - } - } if (!(is_canonical_path || (mh->flags & METHOD_FLAG_ANY_PATH))) { diff --git a/bus/meson.build b/bus/meson.build index 058e3b25..176894d6 100644 --- a/bus/meson.build +++ b/bus/meson.build @@ -96,7 +96,6 @@ libdbus_daemon_internal_sources = [ 'config-parser-common.c', 'config-parser.c', 'connection.c', - 'containers.c', 'desktop-file.c', 'dispatch.c', 'driver.c', diff --git a/bus/tmpfiles.d/dbus-containers.conf.in b/bus/tmpfiles.d/dbus-containers.conf.in deleted file mode 100644 index 4bf1b02b..00000000 --- a/bus/tmpfiles.d/dbus-containers.conf.in +++ /dev/null @@ -1,5 +0,0 @@ -# Fields: type; path; mode; uid; gid; age; argument (symlink target) - -# Create ${runstatedir}/dbus/containers owned by the system bus user. -# org.freedesktop.DBus.Containers1 uses this to create sockets. -d @EXPANDED_RUNSTATEDIR@/dbus/containers 0755 @DBUS_USER@ - - - diff --git a/bus/tmpfiles.d/meson.build b/bus/tmpfiles.d/meson.build index 91dd13f3..f866879c 100644 --- a/bus/tmpfiles.d/meson.build +++ b/bus/tmpfiles.d/meson.build @@ -25,12 +25,3 @@ configure_file( configuration: data_config, install_dir: get_option('prefix') / 'lib' / 'tmpfiles.d', ) - -if get_option('containers') - configure_file( - input: 'dbus-containers.conf.in', - output: 'dbus-containers.conf', - configuration: data_config, - install_dir: get_option('prefix') / 'lib' / 'tmpfiles.d', - ) -endif diff --git a/meson.build b/meson.build index 77d7bb1d..a2b0f9e9 100644 --- a/meson.build +++ b/meson.build @@ -1104,7 +1104,6 @@ config.set_quoted('DBUS_SESSION_BUS_CONNECT_ADDRESS', session_bus_connect_addres config.set('DBUS_ENABLE_STATS', get_option('stats')) -config.set('DBUS_ENABLE_CONTAINERS', get_option('containers')) enable_user_session = get_option('user_session') @@ -1353,7 +1352,6 @@ summary_dict += { 'Building assertions': asserts, 'Building checks': checks, 'Building bus stats API': get_option('stats'), - 'Building container API': get_option('containers'), 'Building SELinux support': config.get('HAVE_SELINUX'), 'Building AppArmor support': apparmor.found(), 'Building inotify support': use_inotify, diff --git a/meson_options.txt b/meson_options.txt index 83c1c921..e63f4bd6 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -40,13 +40,6 @@ option( description: 'Check for usage errors at public API' ) -option( - 'containers', - type: 'boolean', - value: false, - description: 'Enable restricted servers for app containers' -) - option( 'dbus_daemondir', type: 'string', diff --git a/test/containers.c b/test/containers.c deleted file mode 100644 index 79636460..00000000 --- a/test/containers.c +++ /dev/null @@ -1,1807 +0,0 @@ -/* Integration tests for restricted sockets for containers - * - * Copyright © 2017-2018 Collabora Ltd. - * SPDX-License-Identifier: MIT - * - * 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 - -#include - -#include - -#include -#include -#include - -#if defined(DBUS_ENABLE_CONTAINERS) && defined(HAVE_GIO_UNIX) - -#define HAVE_CONTAINERS_TEST - -#include -#include - -#include "dbus/dbus-sysdeps-unix.h" - -#endif - -#include "test-utils-glib.h" - -#define DBUS_INTERFACE_CONTAINERS1 "org.freedesktop.DBus.Containers1" - -typedef struct { - TestMainContext *ctx; - gboolean skip; - gchar *bus_address; - GPid daemon_pid; - GError *error; - - GDBusProxy *proxy; - - gchar *instance_path; - gchar *socket_path; - gchar *socket_dbus_address; - GDBusConnection *unconfined_conn; - gchar *unconfined_unique_name; - GDBusConnection *confined_conn; - - GDBusConnection *observer_conn; - GDBusProxy *observer_proxy; - GHashTable *containers_removed; - guint removed_sub; - DBusConnection *libdbus_observer; - DBusMessage *latest_shout; -} Fixture; - -typedef struct -{ - const gchar *config_file; - enum - { - STOP_SERVER_EXPLICITLY, - STOP_SERVER_DISCONNECT_FIRST, - STOP_SERVER_NEVER_CONNECTED, - STOP_SERVER_FORCE, - STOP_SERVER_WITH_MANAGER - } - stop_server; -} Config; - -static const Config default_config = -{ - NULL, - 0 /* not used, the stop-server test always uses non-default config */ -}; - -#ifdef DBUS_ENABLE_CONTAINERS -/* A GDBusNameVanishedCallback that sets a boolean flag. */ -static void -name_gone_set_boolean_cb (GDBusConnection *conn, - const gchar *name, - gpointer user_data) -{ - gboolean *gone_p = user_data; - - g_assert_nonnull (gone_p); - g_assert_false (*gone_p); - *gone_p = TRUE; -} -#endif - -#ifdef HAVE_CONTAINERS_TEST -static void -iterate_both_main_loops (TestMainContext *ctx) -{ - /* TODO: Gluing these two main loops together so they can block would - * be better than sleeping, but do we have enough API to do that without - * reinventing dbus-glib? */ - g_usleep (G_USEC_PER_SEC / 100); - test_main_context_iterate (ctx, FALSE); - g_main_context_iteration (NULL, FALSE); -} -#endif - -static DBusHandlerResult -observe_shouting_cb (DBusConnection *observer, - DBusMessage *message, - void *user_data) -{ - Fixture *f = user_data; - - if (dbus_message_is_signal (message, "com.example.Shouting", "Shouted")) - { - dbus_clear_message (&f->latest_shout); - f->latest_shout = dbus_message_ref (message); - } - - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - -static void -instance_removed_cb (GDBusConnection *observer, - const gchar *sender, - const gchar *path, - const gchar *iface, - const gchar *member, - GVariant *parameters, - gpointer user_data) -{ - Fixture *f = user_data; - const gchar *container; - - g_assert_cmpstr (sender, ==, DBUS_SERVICE_DBUS); - g_assert_cmpstr (path, ==, DBUS_PATH_DBUS); - g_assert_cmpstr (iface, ==, DBUS_INTERFACE_CONTAINERS1); - g_assert_cmpstr (member, ==, "InstanceRemoved"); - g_assert_cmpstr (g_variant_get_type_string (parameters), ==, "(o)"); - g_variant_get (parameters, "(&o)", &container); - g_assert (!g_hash_table_contains (f->containers_removed, container)); - g_hash_table_add (f->containers_removed, g_strdup (container)); -} - -static void -fixture_disconnect_unconfined (Fixture *f) -{ - if (f->unconfined_conn != NULL) - { - GError *error = NULL; - - g_dbus_connection_close_sync (f->unconfined_conn, NULL, &error); - - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED)) - g_clear_error (&error); - else - g_assert_no_error (error); - } - - g_clear_object (&f->unconfined_conn); -} - -static void -fixture_disconnect_observer (Fixture *f) -{ - if (f->observer_conn != NULL) - { - GError *error = NULL; - - g_dbus_connection_signal_unsubscribe (f->observer_conn, - f->removed_sub); - - g_dbus_connection_close_sync (f->observer_conn, NULL, &error); - - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED)) - g_clear_error (&error); - else - g_assert_no_error (error); - } - - g_clear_object (&f->observer_conn); -} - -static void -setup (Fixture *f, - gconstpointer context) -{ - const Config *config = context; - - if (config == NULL) - config = &default_config; - - f->ctx = test_main_context_get (); - - f->bus_address = test_get_dbus_daemon (config->config_file, TEST_USER_ME, - NULL, &f->daemon_pid); - - if (f->bus_address == NULL) - { - f->skip = TRUE; - return; - } - - f->unconfined_conn = g_dbus_connection_new_for_address_sync (f->bus_address, - (G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION | - G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT), - NULL, NULL, &f->error); - g_assert_no_error (f->error); - f->unconfined_unique_name = g_strdup ( - g_dbus_connection_get_unique_name (f->unconfined_conn)); - g_test_message ("Unconfined connection: \"%s\"", - f->unconfined_unique_name); - - f->observer_conn = g_dbus_connection_new_for_address_sync (f->bus_address, - (G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION | - G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT), - NULL, NULL, &f->error); - g_assert_no_error (f->error); - f->containers_removed = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, NULL); - f->removed_sub = g_dbus_connection_signal_subscribe (f->observer_conn, - DBUS_SERVICE_DBUS, - DBUS_INTERFACE_CONTAINERS1, - "InstanceRemoved", - DBUS_PATH_DBUS, NULL, - G_DBUS_SIGNAL_FLAGS_NONE, - instance_removed_cb, - f, NULL); - - /* We have to use libdbus for new header fields, because GDBus doesn't - * yet have API for that. */ - f->libdbus_observer = test_connect_to_bus (f->ctx, f->bus_address); - dbus_bus_add_match (f->libdbus_observer, - "interface='com.example.Shouting'", NULL); - - if (!dbus_connection_add_filter (f->libdbus_observer, observe_shouting_cb, f, - NULL)) - g_error ("OOM"); -} - -/* - * Assert that Get(SupportedArguments) contains what we expect it to. - */ -static void -test_get_supported_arguments (Fixture *f, - gconstpointer context) -{ - GVariant *v; -#ifdef DBUS_ENABLE_CONTAINERS - const gchar **args; - gsize len; -#endif - - if (f->skip) - return; - - f->proxy = g_dbus_proxy_new_sync (f->unconfined_conn, G_DBUS_PROXY_FLAGS_NONE, - NULL, DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, DBUS_INTERFACE_CONTAINERS1, - NULL, &f->error); - - /* This one is DBUS_ENABLE_CONTAINERS rather than HAVE_CONTAINERS_TEST - * because we can still test whether the interface appears or not, even - * if we were not able to detect gio-unix-2.0 */ -#ifdef DBUS_ENABLE_CONTAINERS - g_assert_no_error (f->error); - - v = g_dbus_proxy_get_cached_property (f->proxy, "SupportedArguments"); - g_assert_cmpstr (g_variant_get_type_string (v), ==, "as"); - args = g_variant_get_strv (v, &len); - - /* No arguments are defined yet */ - g_assert_cmpuint (len, ==, 0); - - g_free (args); - g_variant_unref (v); -#else /* !DBUS_ENABLE_CONTAINERS */ - g_assert_no_error (f->error); - v = g_dbus_proxy_get_cached_property (f->proxy, "SupportedArguments"); - g_assert_null (v); -#endif /* !DBUS_ENABLE_CONTAINERS */ -} - -#ifdef HAVE_CONTAINERS_TEST -/* - * Try to make an AddServer call that usually succeeds, but may fail and - * be skipped if we are running as root and this version of dbus has not - * been fully installed. Return TRUE if we can continue. - * - * parameters is sunk if it is a floating reference. - */ -static gboolean -add_container_server (Fixture *f, - GVariant *parameters) -{ - GVariant *tuple; - GStatBuf stat_buf; - - f->proxy = g_dbus_proxy_new_sync (f->unconfined_conn, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, - NULL, DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, DBUS_INTERFACE_CONTAINERS1, - NULL, &f->error); - g_assert_no_error (f->error); - - g_test_message ("Calling AddServer..."); - tuple = g_dbus_proxy_call_sync (f->proxy, "AddServer", parameters, - G_DBUS_CALL_FLAGS_NONE, -1, NULL, &f->error); - - /* For root, the sockets go in /run/dbus/containers, which we rely on - * system infrastructure to create; so it's OK for AddServer to fail - * when uninstalled, although not OK if it fails as an installed-test. */ - if (f->error != NULL && - _dbus_getuid () == 0 && - _dbus_getenv ("DBUS_TEST_UNINSTALLED") != NULL) - { - g_test_message ("AddServer: %s", f->error->message); - g_assert_error (f->error, G_DBUS_ERROR, G_DBUS_ERROR_FILE_NOT_FOUND); - g_test_skip ("AddServer failed, probably because this dbus " - "version is not fully installed"); - return FALSE; - } - - g_assert_no_error (f->error); - g_assert_nonnull (tuple); - - g_assert_cmpstr (g_variant_get_type_string (tuple), ==, "(oays)"); - g_variant_get (tuple, "(o^ays)", &f->instance_path, &f->socket_path, - &f->socket_dbus_address); - g_assert_true (g_str_has_prefix (f->socket_dbus_address, "unix:")); - g_assert_null (strchr (f->socket_dbus_address, ';')); - g_assert_null (strchr (f->socket_dbus_address + strlen ("unix:"), ':')); - g_clear_pointer (&tuple, g_variant_unref); - - g_assert_nonnull (f->instance_path); - g_assert_true (g_variant_is_object_path (f->instance_path)); - g_assert_nonnull (f->socket_path); - g_assert_true (g_path_is_absolute (f->socket_path)); - g_assert_nonnull (f->socket_dbus_address); - g_assert_cmpstr (g_stat (f->socket_path, &stat_buf) == 0 ? NULL : - g_strerror (errno), ==, NULL); - g_assert_cmpuint ((stat_buf.st_mode & S_IFMT), ==, S_IFSOCK); - return TRUE; -} -#endif - -/* - * Assert that a simple AddServer() call succeeds and has the behaviour - * we expect (we can connect a confined connection to it, the confined - * connection can talk to the dbus-daemon and to an unconfined connection, - * and the socket gets cleaned up when the dbus-daemon terminates). - * - * This also tests simple cases for metadata. - */ -static void -test_basic (Fixture *f, - gconstpointer context) -{ -#ifdef HAVE_CONTAINERS_TEST - GVariant *asv; - GVariant *creator; - GVariant *parameters; - GVariantDict dict; - const gchar *confined_unique_name; - const gchar *path_from_query; - const gchar *name; - const gchar *name_owner; - const gchar *type; - guint32 uid; - GStatBuf stat_buf; - GVariant *tuple; - DBusMessage *libdbus_message = NULL; - DBusMessage *libdbus_reply = NULL; - DBusError libdbus_error = DBUS_ERROR_INIT; - - if (f->skip) - return; - - parameters = g_variant_new ("(ssa{sv}a{sv})", - "com.example.NotFlatpak", - "sample-app", - NULL, /* no metadata */ - NULL); /* no named arguments */ - if (!add_container_server (f, g_steal_pointer (¶meters))) - return; - - g_test_message ("Connecting to %s...", f->socket_dbus_address); - f->confined_conn = g_dbus_connection_new_for_address_sync ( - f->socket_dbus_address, - (G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION | - G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT), - NULL, NULL, &f->error); - g_assert_no_error (f->error); - - g_test_message ("Making a method call from confined app..."); - tuple = g_dbus_connection_call_sync (f->confined_conn, DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, - "GetNameOwner", - g_variant_new ("(s)", DBUS_SERVICE_DBUS), - G_VARIANT_TYPE ("(s)"), - G_DBUS_CALL_FLAGS_NONE, -1, NULL, - &f->error); - g_assert_no_error (f->error); - g_assert_nonnull (tuple); - g_assert_cmpstr (g_variant_get_type_string (tuple), ==, "(s)"); - g_variant_get (tuple, "(&s)", &name_owner); - g_assert_cmpstr (name_owner, ==, DBUS_SERVICE_DBUS); - g_clear_pointer (&tuple, g_variant_unref); - - g_test_message ("Making a method call from confined app to unconfined..."); - tuple = g_dbus_connection_call_sync (f->confined_conn, - f->unconfined_unique_name, - "/", DBUS_INTERFACE_PEER, - "Ping", - NULL, G_VARIANT_TYPE_UNIT, - G_DBUS_CALL_FLAGS_NONE, -1, NULL, - &f->error); - g_assert_no_error (f->error); - g_assert_nonnull (tuple); - g_assert_cmpstr (g_variant_get_type_string (tuple), ==, "()"); - g_clear_pointer (&tuple, g_variant_unref); - - g_test_message ("Receiving signals without requesting extra headers"); - g_dbus_connection_emit_signal (f->confined_conn, NULL, "/", - "com.example.Shouting", "Shouted", - NULL, NULL); - - while (f->latest_shout == NULL) - iterate_both_main_loops (f->ctx); - - g_assert_cmpstr (dbus_message_get_container_instance (f->latest_shout), ==, - NULL); - dbus_clear_message (&f->latest_shout); - - g_dbus_connection_emit_signal (f->unconfined_conn, NULL, "/", - "com.example.Shouting", "Shouted", - NULL, NULL); - - while (f->latest_shout == NULL) - iterate_both_main_loops (f->ctx); - - g_assert_cmpstr (dbus_message_get_container_instance (f->latest_shout), ==, - NULL); - dbus_clear_message (&f->latest_shout); - - g_test_message ("Receiving signals after requesting extra headers"); - - libdbus_message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_CONTAINERS1, - "RequestHeader"); - libdbus_reply = test_main_context_call_and_wait (f->ctx, - f->libdbus_observer, - libdbus_message, - DBUS_TIMEOUT_USE_DEFAULT); - - if (dbus_set_error_from_message (&libdbus_error, libdbus_reply)) - g_error ("%s", libdbus_error.message); - - dbus_clear_message (&libdbus_message); - dbus_clear_message (&libdbus_reply); - - g_dbus_connection_emit_signal (f->confined_conn, NULL, "/", - "com.example.Shouting", "Shouted", - NULL, NULL); - - while (f->latest_shout == NULL) - iterate_both_main_loops (f->ctx); - - g_assert_cmpstr (dbus_message_get_container_instance (f->latest_shout), ==, - f->instance_path); - dbus_clear_message (&f->latest_shout); - - g_dbus_connection_emit_signal (f->unconfined_conn, NULL, "/", - "com.example.Shouting", "Shouted", - NULL, NULL); - - while (f->latest_shout == NULL) - iterate_both_main_loops (f->ctx); - - g_assert_cmpstr (dbus_message_get_container_instance (f->latest_shout), ==, - "/"); - dbus_clear_message (&f->latest_shout); - - g_test_message ("Checking that confined app is not considered privileged..."); - tuple = g_dbus_connection_call_sync (f->confined_conn, DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, - "UpdateActivationEnvironment", - g_variant_new ("(a{ss})", NULL), - G_VARIANT_TYPE_UNIT, - G_DBUS_CALL_FLAGS_NONE, -1, NULL, - &f->error); - g_assert_error (f->error, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED); - g_test_message ("Access denied as expected: %s", f->error->message); - g_clear_error (&f->error); - g_assert_null (tuple); - - g_test_message ("Inspecting connection container info"); - confined_unique_name = g_dbus_connection_get_unique_name (f->confined_conn); - tuple = g_dbus_proxy_call_sync (f->proxy, "GetConnectionInstance", - g_variant_new ("(s)", confined_unique_name), - G_DBUS_CALL_FLAGS_NONE, -1, NULL, &f->error); - g_assert_no_error (f->error); - g_assert_nonnull (tuple); - g_assert_cmpstr (g_variant_get_type_string (tuple), ==, "(oa{sv}ssa{sv})"); - g_variant_get (tuple, "(&o@a{sv}&s&s@a{sv})", - &path_from_query, &creator, &type, &name, &asv); - g_assert_cmpstr (path_from_query, ==, f->instance_path); - g_variant_dict_init (&dict, creator); - g_assert_true (g_variant_dict_lookup (&dict, "UnixUserID", "u", &uid)); - g_assert_cmpuint (uid, ==, _dbus_getuid ()); - g_variant_dict_clear (&dict); - g_assert_cmpstr (type, ==, "com.example.NotFlatpak"); - g_assert_cmpstr (name, ==, "sample-app"); - /* Trivial case: the metadata a{sv} is empty */ - g_assert_cmpuint (g_variant_n_children (asv), ==, 0); - g_clear_pointer (&asv, g_variant_unref); - g_clear_pointer (&creator, g_variant_unref); - g_clear_pointer (&tuple, g_variant_unref); - - g_test_message ("Inspecting container instance info"); - tuple = g_dbus_proxy_call_sync (f->proxy, "GetInstanceInfo", - g_variant_new ("(o)", f->instance_path), - G_DBUS_CALL_FLAGS_NONE, -1, NULL, &f->error); - g_assert_no_error (f->error); - g_assert_nonnull (tuple); - g_assert_cmpstr (g_variant_get_type_string (tuple), ==, "(a{sv}ssa{sv})"); - g_variant_get (tuple, "(@a{sv}&s&s@a{sv})", &creator, &type, &name, &asv); - g_variant_dict_init (&dict, creator); - g_assert_true (g_variant_dict_lookup (&dict, "UnixUserID", "u", &uid)); - g_assert_cmpuint (uid, ==, _dbus_getuid ()); - g_variant_dict_clear (&dict); - g_assert_cmpstr (type, ==, "com.example.NotFlatpak"); - g_assert_cmpstr (name, ==, "sample-app"); - /* Trivial case: the metadata a{sv} is empty */ - g_assert_cmpuint (g_variant_n_children (asv), ==, 0); - g_clear_pointer (&asv, g_variant_unref); - g_clear_pointer (&creator, g_variant_unref); - g_clear_pointer (&tuple, g_variant_unref); - - /* Check that the socket is cleaned up when the dbus-daemon is terminated */ - test_kill_pid (f->daemon_pid); - g_spawn_close_pid (f->daemon_pid); - f->daemon_pid = 0; - - while (g_stat (f->socket_path, &stat_buf) == 0) - g_usleep (G_USEC_PER_SEC / 20); - - g_assert_cmpint (errno, ==, ENOENT); - -#else /* !HAVE_CONTAINERS_TEST */ - g_test_skip ("Containers or gio-unix-2.0 not supported"); -#endif /* !HAVE_CONTAINERS_TEST */ -} - -/* - * If we are running as root, assert that when one uid (root) creates a - * container server, another uid (TEST_USER_OTHER) cannot connect to it - */ -static void -test_wrong_uid (Fixture *f, - gconstpointer context) -{ -#ifdef HAVE_CONTAINERS_TEST - GVariant *parameters; - - if (f->skip) - return; - - parameters = g_variant_new ("(ssa{sv}a{sv})", - "com.example.NotFlatpak", - "sample-app", - NULL, /* no metadata */ - NULL); /* no named arguments */ - if (!add_container_server (f, g_steal_pointer (¶meters))) - return; - - g_test_message ("Connecting to %s...", f->socket_dbus_address); - f->confined_conn = test_try_connect_gdbus_as_user (f->socket_dbus_address, - TEST_USER_OTHER, - &f->error); - - /* That might be skipped if we can't become TEST_USER_OTHER */ - if (f->error != NULL && - g_error_matches (f->error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED)) - { - g_test_skip (f->error->message); - return; - } - - /* The connection was unceremoniously closed */ - g_assert_error (f->error, G_IO_ERROR, G_IO_ERROR_CLOSED); - -#else /* !HAVE_CONTAINERS_TEST */ - g_test_skip ("Containers or gio-unix-2.0 not supported"); -#endif /* !HAVE_CONTAINERS_TEST */ -} - -/* - * Test for non-trivial metadata: assert that the metadata a{sv} is - * carried through correctly, and that the app name is allowed to be empty. - */ -static void -test_metadata (Fixture *f, - gconstpointer context) -{ -#ifdef HAVE_CONTAINERS_TEST - GVariant *asv; - GVariant *creator; - GVariant *tuple; - GVariant *parameters; - GVariantDict dict; - const gchar *confined_unique_name; - const gchar *path_from_query; - const gchar *name; - const gchar *type; - guint32 uid; - guint u; - gboolean b; - const gchar *s; - - if (f->skip) - return; - - g_variant_dict_init (&dict, NULL); - g_variant_dict_insert (&dict, "Species", "s", "Martes martes"); - g_variant_dict_insert (&dict, "IsCrepuscular", "b", TRUE); - g_variant_dict_insert (&dict, "NChildren", "u", 2); - - parameters = g_variant_new ("(ss@a{sv}a{sv})", - "org.example.Springwatch", - /* Verify that empty app names are OK */ - "", - g_variant_dict_end (&dict), - NULL); /* no named arguments */ - if (!add_container_server (f, g_steal_pointer (¶meters))) - return; - - g_test_message ("Connecting to %s...", f->socket_dbus_address); - f->confined_conn = g_dbus_connection_new_for_address_sync ( - f->socket_dbus_address, - (G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION | - G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT), - NULL, NULL, &f->error); - g_assert_no_error (f->error); - - g_test_message ("Inspecting connection credentials..."); - confined_unique_name = g_dbus_connection_get_unique_name (f->confined_conn); - tuple = g_dbus_connection_call_sync (f->confined_conn, DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, - "GetConnectionCredentials", - g_variant_new ("(s)", - confined_unique_name), - G_VARIANT_TYPE ("(a{sv})"), - G_DBUS_CALL_FLAGS_NONE, -1, NULL, - &f->error); - g_assert_no_error (f->error); - g_assert_nonnull (tuple); - g_assert_cmpstr (g_variant_get_type_string (tuple), ==, "(a{sv})"); - asv = g_variant_get_child_value (tuple, 0); - g_variant_dict_init (&dict, asv); - g_assert_true (g_variant_dict_lookup (&dict, - DBUS_INTERFACE_CONTAINERS1 ".Instance", - "&o", &path_from_query)); - g_assert_cmpstr (path_from_query, ==, f->instance_path); - g_variant_dict_clear (&dict); - g_clear_pointer (&asv, g_variant_unref); - g_clear_pointer (&tuple, g_variant_unref); - - g_test_message ("Inspecting connection container info"); - tuple = g_dbus_proxy_call_sync (f->proxy, "GetConnectionInstance", - g_variant_new ("(s)", confined_unique_name), - G_DBUS_CALL_FLAGS_NONE, -1, NULL, &f->error); - g_assert_no_error (f->error); - g_assert_nonnull (tuple); - g_assert_cmpstr (g_variant_get_type_string (tuple), ==, "(oa{sv}ssa{sv})"); - g_variant_get (tuple, "(&o@a{sv}&s&s@a{sv})", - &path_from_query, &creator, &type, &name, &asv); - g_assert_cmpstr (path_from_query, ==, f->instance_path); - g_variant_dict_init (&dict, creator); - g_assert_true (g_variant_dict_lookup (&dict, "UnixUserID", "u", &uid)); - g_assert_cmpuint (uid, ==, _dbus_getuid ()); - g_variant_dict_clear (&dict); - g_assert_cmpstr (type, ==, "org.example.Springwatch"); - g_assert_cmpstr (name, ==, ""); - g_variant_dict_init (&dict, asv); - g_assert_true (g_variant_dict_lookup (&dict, "NChildren", "u", &u)); - g_assert_cmpuint (u, ==, 2); - g_assert_true (g_variant_dict_lookup (&dict, "IsCrepuscular", "b", &b)); - g_assert_cmpint (b, ==, TRUE); - g_assert_true (g_variant_dict_lookup (&dict, "Species", "&s", &s)); - g_assert_cmpstr (s, ==, "Martes martes"); - g_variant_dict_clear (&dict); - g_assert_cmpuint (g_variant_n_children (asv), ==, 3); - g_clear_pointer (&asv, g_variant_unref); - g_clear_pointer (&creator, g_variant_unref); - g_clear_pointer (&tuple, g_variant_unref); - - g_test_message ("Inspecting container instance info"); - tuple = g_dbus_proxy_call_sync (f->proxy, "GetInstanceInfo", - g_variant_new ("(o)", f->instance_path), - G_DBUS_CALL_FLAGS_NONE, -1, NULL, &f->error); - g_assert_no_error (f->error); - g_assert_nonnull (tuple); - g_assert_cmpstr (g_variant_get_type_string (tuple), ==, "(a{sv}ssa{sv})"); - g_variant_get (tuple, "(@a{sv}&s&s@a{sv})", &creator, &type, &name, &asv); - g_variant_dict_init (&dict, creator); - g_assert_true (g_variant_dict_lookup (&dict, "UnixUserID", "u", &uid)); - g_assert_cmpuint (uid, ==, _dbus_getuid ()); - g_variant_dict_clear (&dict); - g_assert_cmpstr (type, ==, "org.example.Springwatch"); - g_assert_cmpstr (name, ==, ""); - g_variant_dict_init (&dict, asv); - g_assert_true (g_variant_dict_lookup (&dict, "NChildren", "u", &u)); - g_assert_cmpuint (u, ==, 2); - g_assert_true (g_variant_dict_lookup (&dict, "IsCrepuscular", "b", &b)); - g_assert_cmpint (b, ==, TRUE); - g_assert_true (g_variant_dict_lookup (&dict, "Species", "&s", &s)); - g_assert_cmpstr (s, ==, "Martes martes"); - g_variant_dict_clear (&dict); - g_assert_cmpuint (g_variant_n_children (asv), ==, 3); - g_clear_pointer (&asv, g_variant_unref); - g_clear_pointer (&creator, g_variant_unref); - g_clear_pointer (&tuple, g_variant_unref); - -#else /* !HAVE_CONTAINERS_TEST */ - g_test_skip ("Containers or gio-unix-2.0 not supported"); -#endif /* !HAVE_CONTAINERS_TEST */ -} - -/* - * With config->stop_server == STOP_SERVER_WITH_MANAGER: - * Assert that without special parameters, when the container manager - * disappears from the bus, so does the confined server. - * - * With config->stop_server == STOP_SERVER_EXPLICITLY or - * config->stop_server == STOP_SERVER_DISCONNECT_FIRST: - * Test StopListening(), which just closes the listening socket. - * - * With config->stop_server == STOP_SERVER_FORCE: - * Test StopInstance(), which closes the listening socket and - * disconnects all its clients. - */ -static void -test_stop_server (Fixture *f, - gconstpointer context) -{ -#ifdef HAVE_CONTAINERS_TEST - const Config *config = context; - GDBusConnection *attacker; - GDBusConnection *second_confined_conn; - GDBusProxy *attacker_proxy; - GSocket *client_socket; - GSocketAddress *socket_address; - GVariant *tuple; - GVariant *parameters; - gchar *error_name; - const gchar *confined_unique_name; - const gchar *name_owner; - gboolean gone = FALSE; - guint name_watch; - guint i; - - g_assert_nonnull (config); - - if (f->skip) - return; - - f->observer_proxy = g_dbus_proxy_new_sync (f->observer_conn, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, - NULL, DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_CONTAINERS1, NULL, - &f->error); - g_assert_no_error (f->error); - - parameters = g_variant_new ("(ssa{sv}a{sv})", - "com.example.NotFlatpak", - "sample-app", - NULL, /* no metadata */ - NULL); /* no named arguments */ - if (!add_container_server (f, g_steal_pointer (¶meters))) - return; - - socket_address = g_unix_socket_address_new (f->socket_path); - - if (config->stop_server != STOP_SERVER_NEVER_CONNECTED) - { - g_test_message ("Connecting to %s...", f->socket_dbus_address); - f->confined_conn = g_dbus_connection_new_for_address_sync ( - f->socket_dbus_address, - (G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION | - G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT), - NULL, NULL, &f->error); - g_assert_no_error (f->error); - - if (config->stop_server == STOP_SERVER_DISCONNECT_FIRST) - { - g_test_message ("Disconnecting confined connection..."); - gone = FALSE; - confined_unique_name = g_dbus_connection_get_unique_name ( - f->confined_conn); - name_watch = g_bus_watch_name_on_connection (f->observer_conn, - confined_unique_name, - G_BUS_NAME_WATCHER_FLAGS_NONE, - NULL, - name_gone_set_boolean_cb, - &gone, NULL); - g_dbus_connection_close_sync (f->confined_conn, NULL, &f->error); - g_assert_no_error (f->error); - - g_test_message ("Waiting for confined app bus name to disappear..."); - - while (!gone) - g_main_context_iteration (NULL, TRUE); - - g_bus_unwatch_name (name_watch); - } - } - - /* If we are able to switch uid (i.e. we are root), check that a local - * attacker with a different uid cannot close our container instances. */ - attacker = test_try_connect_gdbus_as_user (f->bus_address, TEST_USER_OTHER, - &f->error); - - if (attacker != NULL) - { - attacker_proxy = g_dbus_proxy_new_sync (attacker, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, - NULL, DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_CONTAINERS1, NULL, - &f->error); - g_assert_no_error (f->error); - - tuple = g_dbus_proxy_call_sync (attacker_proxy, "StopListening", - g_variant_new ("(o)", f->instance_path), - G_DBUS_CALL_FLAGS_NONE, -1, NULL, - &f->error); - g_assert_error (f->error, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED); - g_assert_null (tuple); - g_clear_error (&f->error); - - tuple = g_dbus_proxy_call_sync (attacker_proxy, "StopInstance", - g_variant_new ("(o)", f->instance_path), - G_DBUS_CALL_FLAGS_NONE, -1, NULL, - &f->error); - g_assert_error (f->error, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED); - g_assert_null (tuple); - g_clear_error (&f->error); - - g_clear_object (&attacker_proxy); - g_dbus_connection_close_sync (attacker, NULL, &f->error); - g_assert_no_error (f->error); - g_clear_object (&attacker); - } - else - { - /* If we aren't running as root, it's OK to not be able to connect again - * as some other user (usually 'nobody'). We don't g_test_skip() here - * because this is just extra coverage */ - g_assert_error (f->error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED); - g_clear_error (&f->error); - } - - g_assert_false (g_hash_table_contains (f->containers_removed, - f->instance_path)); - - switch (config->stop_server) - { - case STOP_SERVER_WITH_MANAGER: - /* Close the unconfined connection (the container manager) and wait - * for it to go away */ - g_test_message ("Closing container manager..."); - name_watch = g_bus_watch_name_on_connection (f->confined_conn, - f->unconfined_unique_name, - G_BUS_NAME_WATCHER_FLAGS_NONE, - NULL, - name_gone_set_boolean_cb, - &gone, NULL); - fixture_disconnect_unconfined (f); - - g_test_message ("Waiting for container manager bus name to disappear..."); - - while (!gone) - g_main_context_iteration (NULL, TRUE); - - g_bus_unwatch_name (name_watch); - break; - - case STOP_SERVER_EXPLICITLY: - g_test_message ("Stopping server (but not confined connection)..."); - tuple = g_dbus_proxy_call_sync (f->proxy, "StopListening", - g_variant_new ("(o)", f->instance_path), - G_DBUS_CALL_FLAGS_NONE, -1, NULL, - &f->error); - g_assert_no_error (f->error); - g_variant_unref (tuple); - - /* The container instance remains open, because the connection has - * not gone away yet. Do another method call: if we were going to - * get the signal, it would arrive before the reply to this second - * method call. Any method will do here, even one that doesn't - * exist. */ - g_test_message ("Checking we do not get InstanceRemoved..."); - tuple = g_dbus_proxy_call_sync (f->proxy, "NoSuchMethod", NULL, - G_DBUS_CALL_FLAGS_NONE, -1, NULL, - &f->error); - g_assert_error (f->error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD); - g_assert_null (tuple); - g_clear_error (&f->error); - break; - - case STOP_SERVER_DISCONNECT_FIRST: - case STOP_SERVER_NEVER_CONNECTED: - g_test_message ("Stopping server (with no confined connections)..."); - tuple = g_dbus_proxy_call_sync (f->proxy, "StopListening", - g_variant_new ("(o)", f->instance_path), - G_DBUS_CALL_FLAGS_NONE, -1, NULL, - &f->error); - g_assert_no_error (f->error); - g_variant_unref (tuple); - - g_test_message ("Waiting for InstanceRemoved..."); - while (!g_hash_table_contains (f->containers_removed, f->instance_path)) - g_main_context_iteration (NULL, TRUE); - - break; - - case STOP_SERVER_FORCE: - g_test_message ("Stopping server and all confined connections..."); - tuple = g_dbus_proxy_call_sync (f->proxy, "StopInstance", - g_variant_new ("(o)", f->instance_path), - G_DBUS_CALL_FLAGS_NONE, -1, NULL, - &f->error); - g_assert_no_error (f->error); - g_variant_unref (tuple); - - g_test_message ("Waiting for InstanceRemoved..."); - while (!g_hash_table_contains (f->containers_removed, f->instance_path)) - g_main_context_iteration (NULL, TRUE); - - break; - - default: - g_assert_not_reached (); - } - - /* Now if we try to connect to the server again, it will fail (eventually - - * closing the socket is not synchronous with respect to the name owner - * change, so try a few times) */ - for (i = 0; i < 50; i++) - { - g_test_message ("Trying to connect to %s again...", f->socket_path); - client_socket = g_socket_new (G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, - G_SOCKET_PROTOCOL_DEFAULT, &f->error); - g_assert_no_error (f->error); - - if (!g_socket_connect (client_socket, socket_address, NULL, &f->error)) - { - g_assert_cmpstr (g_quark_to_string (f->error->domain), ==, - g_quark_to_string (G_IO_ERROR)); - - if (f->error->code != G_IO_ERROR_CONNECTION_REFUSED && - f->error->code != G_IO_ERROR_NOT_FOUND) - g_error ("Unexpected error code %d", f->error->code); - - g_clear_error (&f->error); - g_clear_object (&client_socket); - break; - } - - g_clear_object (&client_socket); - g_usleep (G_USEC_PER_SEC / 10); - } - - /* The same thing happens for a D-Bus connection */ - g_test_message ("Trying to connect to %s again...", f->socket_dbus_address); - second_confined_conn = g_dbus_connection_new_for_address_sync ( - f->socket_dbus_address, - (G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION | - G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT), - NULL, NULL, &f->error); - g_assert_cmpstr (g_quark_to_string (f->error->domain), ==, - g_quark_to_string (G_IO_ERROR)); - - if (f->error->code != G_IO_ERROR_CONNECTION_REFUSED && - f->error->code != G_IO_ERROR_NOT_FOUND) - g_error ("Unexpected error code %d", f->error->code); - - g_clear_error (&f->error); - g_assert_null (second_confined_conn); - - /* Deleting the socket is not synchronous with respect to stopping - * listening on it, so again we are willing to wait a few seconds */ - for (i = 0; i < 50; i++) - { - if (g_file_test (f->socket_path, G_FILE_TEST_EXISTS)) - g_usleep (G_USEC_PER_SEC / 10); - } - - /* The socket has been deleted */ - g_assert_false (g_file_test (f->socket_path, G_FILE_TEST_EXISTS)); - - switch (config->stop_server) - { - case STOP_SERVER_FORCE: - g_test_message ("Checking that the confined app gets disconnected..."); - - while (!g_dbus_connection_is_closed (f->confined_conn)) - g_main_context_iteration (NULL, TRUE); - break; - - case STOP_SERVER_DISCONNECT_FIRST: - case STOP_SERVER_NEVER_CONNECTED: - /* Nothing to be done here, no confined app is connected */ - break; - - case STOP_SERVER_EXPLICITLY: - case STOP_SERVER_WITH_MANAGER: - g_test_message ("Checking that the confined app still works..."); - tuple = g_dbus_connection_call_sync (f->confined_conn, - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - "GetNameOwner", - g_variant_new ("(s)", - DBUS_SERVICE_DBUS), - G_VARIANT_TYPE ("(s)"), - G_DBUS_CALL_FLAGS_NONE, -1, - NULL, &f->error); - g_assert_no_error (f->error); - g_assert_nonnull (tuple); - g_assert_cmpstr (g_variant_get_type_string (tuple), ==, "(s)"); - g_variant_get (tuple, "(&s)", &name_owner); - g_assert_cmpstr (name_owner, ==, DBUS_SERVICE_DBUS); - g_clear_pointer (&tuple, g_variant_unref); - - /* The container instance will not disappear from the bus - * until the confined connection goes away */ - tuple = g_dbus_proxy_call_sync (f->observer_proxy, "GetInstanceInfo", - g_variant_new ("(o)", f->instance_path), - G_DBUS_CALL_FLAGS_NONE, -1, NULL, - &f->error); - g_assert_no_error (f->error); - g_assert_nonnull (tuple); - g_clear_pointer (&tuple, g_variant_unref); - - /* Now disconnect the last confined connection, which will make the - * container instance go away */ - g_test_message ("Closing confined connection..."); - g_dbus_connection_close_sync (f->confined_conn, NULL, &f->error); - g_assert_no_error (f->error); - break; - - default: - g_assert_not_reached (); - } - - /* Whatever happened above, by now it has gone away */ - - g_test_message ("Waiting for InstanceRemoved..."); - while (!g_hash_table_contains (f->containers_removed, f->instance_path)) - g_main_context_iteration (NULL, TRUE); - - tuple = g_dbus_proxy_call_sync (f->observer_proxy, "GetInstanceInfo", - g_variant_new ("(o)", f->instance_path), - G_DBUS_CALL_FLAGS_NONE, -1, NULL, - &f->error); - g_assert_nonnull (f->error); - error_name = g_dbus_error_get_remote_error (f->error); - g_assert_cmpstr (error_name, ==, DBUS_ERROR_NOT_CONTAINER); - g_free (error_name); - g_assert_null (tuple); - g_clear_error (&f->error); - g_clear_object (&socket_address); - -#else /* !HAVE_CONTAINERS_TEST */ - g_test_skip ("Containers or gio-unix-2.0 not supported"); -#endif /* !HAVE_CONTAINERS_TEST */ -} - -/* - * Assert that we cannot get the container metadata for a path that - * isn't a container instance, or a bus name that isn't in a container - * or doesn't exist at all. - */ -static void -test_invalid_metadata_getters (Fixture *f, - gconstpointer context) -{ - const gchar *unique_name; - GVariant *tuple; - gchar *error_name; - - f->proxy = g_dbus_proxy_new_sync (f->unconfined_conn, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, - NULL, DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, DBUS_INTERFACE_CONTAINERS1, - NULL, &f->error); - g_assert_no_error (f->error); - - g_test_message ("Inspecting unconfined connection"); - unique_name = g_dbus_connection_get_unique_name (f->unconfined_conn); - tuple = g_dbus_proxy_call_sync (f->proxy, "GetConnectionInstance", - g_variant_new ("(s)", unique_name), - G_DBUS_CALL_FLAGS_NONE, -1, NULL, &f->error); - g_assert_nonnull (f->error); - g_assert_null (tuple); - error_name = g_dbus_error_get_remote_error (f->error); -#ifdef DBUS_ENABLE_CONTAINERS - g_assert_cmpstr (error_name, ==, DBUS_ERROR_NOT_CONTAINER); -#else - /* TODO: We can use g_assert_error for this when we depend on GLib 2.42 */ - g_assert_cmpstr (error_name, ==, DBUS_ERROR_UNKNOWN_INTERFACE); -#endif - g_free (error_name); - g_clear_error (&f->error); - - g_test_message ("Inspecting dbus-daemon"); - tuple = g_dbus_proxy_call_sync (f->proxy, "GetConnectionInstance", - g_variant_new ("(s)", DBUS_SERVICE_DBUS), - G_DBUS_CALL_FLAGS_NONE, -1, NULL, &f->error); - g_assert_nonnull (f->error); - g_assert_null (tuple); - error_name = g_dbus_error_get_remote_error (f->error); -#ifdef DBUS_ENABLE_CONTAINERS - g_assert_cmpstr (error_name, ==, DBUS_ERROR_NOT_CONTAINER); -#else - /* TODO: We can use g_assert_error for this when we depend on GLib 2.42 */ - g_assert_cmpstr (error_name, ==, DBUS_ERROR_UNKNOWN_INTERFACE); -#endif - g_free (error_name); - g_clear_error (&f->error); - - g_test_message ("Inspecting a non-connection"); - unique_name = g_dbus_connection_get_unique_name (f->unconfined_conn); - tuple = g_dbus_proxy_call_sync (f->proxy, "GetConnectionInstance", - g_variant_new ("(s)", "com.example.Nope"), - G_DBUS_CALL_FLAGS_NONE, -1, NULL, &f->error); - g_assert_nonnull (f->error); - g_assert_null (tuple); -#ifdef DBUS_ENABLE_CONTAINERS - g_assert_error (f->error, G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER); -#else - /* TODO: We can use g_assert_error for this when we depend on GLib 2.42 */ - error_name = g_dbus_error_get_remote_error (f->error); - g_assert_cmpstr (error_name, ==, DBUS_ERROR_UNKNOWN_INTERFACE); - g_free (error_name); -#endif - g_clear_error (&f->error); - - - g_test_message ("Inspecting container instance info"); - tuple = g_dbus_proxy_call_sync (f->proxy, "GetInstanceInfo", - g_variant_new ("(o)", "/nope"), - G_DBUS_CALL_FLAGS_NONE, -1, NULL, &f->error); - g_assert_nonnull (f->error); - g_assert_null (tuple); - error_name = g_dbus_error_get_remote_error (f->error); -#ifdef DBUS_ENABLE_CONTAINERS - g_assert_cmpstr (error_name, ==, DBUS_ERROR_NOT_CONTAINER); -#else - /* TODO: We can use g_assert_error for this when we depend on GLib 2.42 */ - g_assert_cmpstr (error_name, ==, DBUS_ERROR_UNKNOWN_INTERFACE); -#endif - g_free (error_name); - g_clear_error (&f->error); -} - -/* - * Assert that named arguments are validated: passing an unsupported - * named argument causes an error. - */ -static void -test_unsupported_parameter (Fixture *f, - gconstpointer context) -{ -#ifdef HAVE_CONTAINERS_TEST - GVariant *tuple; - GVariant *parameters; - GVariantDict named_argument_builder; - - if (f->skip) - return; - - f->proxy = g_dbus_proxy_new_sync (f->unconfined_conn, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, - NULL, DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, DBUS_INTERFACE_CONTAINERS1, - NULL, &f->error); - g_assert_no_error (f->error); - - g_variant_dict_init (&named_argument_builder, NULL); - g_variant_dict_insert (&named_argument_builder, - "ThisArgumentIsntImplemented", - "b", FALSE); - - parameters = g_variant_new ("(ssa{sv}@a{sv})", - "com.example.NotFlatpak", - "sample-app", - NULL, /* no metadata */ - g_variant_dict_end (&named_argument_builder)); - tuple = g_dbus_proxy_call_sync (f->proxy, "AddServer", - g_steal_pointer (¶meters), - G_DBUS_CALL_FLAGS_NONE, -1, NULL, &f->error); - - g_assert_error (f->error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS); - g_assert_null (tuple); - g_clear_error (&f->error); -#else /* !HAVE_CONTAINERS_TEST */ - g_test_skip ("Containers or gio-unix-2.0 not supported"); -#endif /* !HAVE_CONTAINERS_TEST */ -} - -/* - * Assert that container types are validated: a container type (container - * technology) that is not a syntactically valid D-Bus interface name - * causes an error. - */ -static void -test_invalid_type_name (Fixture *f, - gconstpointer context) -{ -#ifdef HAVE_CONTAINERS_TEST - GVariant *tuple; - GVariant *parameters; - - if (f->skip) - return; - - f->proxy = g_dbus_proxy_new_sync (f->unconfined_conn, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, - NULL, DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, DBUS_INTERFACE_CONTAINERS1, - NULL, &f->error); - g_assert_no_error (f->error); - - parameters = g_variant_new ("(ssa{sv}a{sv})", - "this is not a valid container type name", - "sample-app", - NULL, /* no metadata */ - NULL); /* no named arguments */ - tuple = g_dbus_proxy_call_sync (f->proxy, "AddServer", - g_steal_pointer (¶meters), - G_DBUS_CALL_FLAGS_NONE, -1, NULL, &f->error); - - g_assert_error (f->error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS); - g_assert_null (tuple); - g_clear_error (&f->error); -#else /* !HAVE_CONTAINERS_TEST */ - g_test_skip ("Containers or gio-unix-2.0 not supported"); -#endif /* !HAVE_CONTAINERS_TEST */ -} - -/* - * Assert that a request to create a container server cannot come from a - * connection to an existing container server. - * (You cannot put containers in your container so you can sandbox while - * you sandbox.) - */ -static void -test_invalid_nesting (Fixture *f, - gconstpointer context) -{ -#ifdef HAVE_CONTAINERS_TEST - GDBusProxy *nested_proxy; - GVariant *tuple; - GVariant *parameters; - - if (f->skip) - return; - - parameters = g_variant_new ("(ssa{sv}a{sv})", - "com.example.NotFlatpak", - "sample-app", - NULL, /* no metadata */ - NULL); /* no named arguments */ - if (!add_container_server (f, g_steal_pointer (¶meters))) - return; - - g_test_message ("Connecting to %s...", f->socket_dbus_address); - f->confined_conn = g_dbus_connection_new_for_address_sync ( - f->socket_dbus_address, - (G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION | - G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT), - NULL, NULL, &f->error); - g_assert_no_error (f->error); - - g_test_message ("Checking that confined app cannot nest containers..."); - nested_proxy = g_dbus_proxy_new_sync (f->confined_conn, - G_DBUS_PROXY_FLAGS_NONE, NULL, - DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, - DBUS_INTERFACE_CONTAINERS1, NULL, - &f->error); - g_assert_no_error (f->error); - - parameters = g_variant_new ("(ssa{sv}a{sv})", - "com.example.NotFlatpak", - "inner-app", - NULL, /* no metadata */ - NULL); /* no named arguments */ - tuple = g_dbus_proxy_call_sync (nested_proxy, "AddServer", - g_steal_pointer (¶meters), - G_DBUS_CALL_FLAGS_NONE, - -1, NULL, &f->error); - - g_assert_error (f->error, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED); - g_assert_null (tuple); - g_clear_error (&f->error); - - g_clear_object (&nested_proxy); - -#else /* !HAVE_CONTAINERS_TEST */ - g_test_skip ("Containers or gio-unix-2.0 not supported"); -#endif /* !HAVE_CONTAINERS_TEST */ -} - -/* - * Assert that we can have up to 3 containers, but no more than that, - * either because max-containers.conf imposes max_containers=3 - * or because limit-containers.conf imposes max_containers_per_user=3 - * (and we only have one uid). - */ -static void -test_max_containers (Fixture *f, - gconstpointer context) -{ -#ifdef HAVE_CONTAINERS_TEST - GVariant *parameters; - GVariant *tuple; - /* Length must match max_containers in max-containers.conf, and also - * max_containers_per_user in limit-containers.conf */ - gchar *placeholders[3] = { NULL }; - guint i; - - if (f->skip) - return; - - f->proxy = g_dbus_proxy_new_sync (f->unconfined_conn, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, - NULL, DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, DBUS_INTERFACE_CONTAINERS1, - NULL, &f->error); - g_assert_no_error (f->error); - - parameters = g_variant_new ("(ssa{sv}a{sv})", - "com.example.NotFlatpak", - "sample-app", - NULL, /* no metadata */ - NULL); /* no named arguments */ - /* We will reuse this variant several times, so don't use floating refs */ - g_variant_ref_sink (parameters); - - /* We can go up to the limit without exceeding it */ - for (i = 0; i < G_N_ELEMENTS (placeholders); i++) - { - tuple = g_dbus_proxy_call_sync (f->proxy, "AddServer", - parameters, G_DBUS_CALL_FLAGS_NONE, -1, - NULL, &f->error); - g_assert_no_error (f->error); - g_assert_nonnull (tuple); - g_variant_get (tuple, "(o^ays)", &placeholders[i], NULL, NULL); - g_variant_unref (tuple); - g_test_message ("Placeholder server at %s", placeholders[i]); - } - - /* We cannot exceed the limit */ - tuple = g_dbus_proxy_call_sync (f->proxy, "AddServer", - parameters, G_DBUS_CALL_FLAGS_NONE, -1, - NULL, &f->error); - g_assert_error (f->error, G_DBUS_ERROR, G_DBUS_ERROR_LIMITS_EXCEEDED); - g_clear_error (&f->error); - g_assert_null (tuple); - - /* Stop one of the placeholders */ - tuple = g_dbus_proxy_call_sync (f->proxy, "StopListening", - g_variant_new ("(o)", placeholders[1]), - G_DBUS_CALL_FLAGS_NONE, -1, NULL, - &f->error); - g_assert_no_error (f->error); - g_assert_nonnull (tuple); - g_variant_unref (tuple); - - /* We can have another container server now that we are back below the - * limit */ - tuple = g_dbus_proxy_call_sync (f->proxy, "AddServer", - parameters, G_DBUS_CALL_FLAGS_NONE, -1, - NULL, &f->error); - g_assert_no_error (f->error); - g_assert_nonnull (tuple); - g_variant_unref (tuple); - - g_variant_unref (parameters); - - for (i = 0; i < G_N_ELEMENTS (placeholders); i++) - g_free (placeholders[i]); - -#else /* !HAVE_CONTAINERS_TEST */ - g_test_skip ("Containers or gio-unix-2.0 not supported"); -#endif /* !HAVE_CONTAINERS_TEST */ -} - -#ifdef HAVE_CONTAINERS_TEST -static void -assert_connection_closed (GError *error) -{ - /* "before 2.44 some "connection closed" errors returned - * G_IO_ERROR_BROKEN_PIPE, but others returned G_IO_ERROR_FAILED" - * —GIO documentation */ - if (error->code == G_IO_ERROR_BROKEN_PIPE) - { - g_assert_error (error, G_IO_ERROR, G_IO_ERROR_BROKEN_PIPE); - } - else - { - g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED); - g_test_message ("Old GLib: %s", error->message); - /* This is wrong and bad, but it's the only way to detect this, and - * the older GLib versions that raised FAILED are no longer a moving - * target */ - g_assert_true (strstr (error->message, g_strerror (ECONNRESET)) != NULL); - } -} -#endif - -/* - * Test that if we have multiple app-containers, - * max_connections_per_container applies to each one individually. - */ -static void -test_max_connections_per_container (Fixture *f, - gconstpointer context) -{ -#ifdef HAVE_CONTAINERS_TEST - /* Length is arbitrary */ - gchar *socket_paths[2] = { NULL }; - gchar *dbus_addresses[G_N_ELEMENTS (socket_paths)] = { NULL }; - GSocketAddress *socket_addresses[G_N_ELEMENTS (socket_paths)] = { NULL }; - /* Length must be length of socket_paths * max_connections_per_container in - * limit-containers.conf */ - GSocket *placeholders[G_N_ELEMENTS (socket_paths) * 3] = { NULL }; - GVariant *parameters; - GVariant *tuple; - guint i; - - if (f->skip) - return; - - f->proxy = g_dbus_proxy_new_sync (f->unconfined_conn, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, - NULL, DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, DBUS_INTERFACE_CONTAINERS1, - NULL, &f->error); - g_assert_no_error (f->error); - - parameters = g_variant_new ("(ssa{sv}a{sv})", - "com.example.NotFlatpak", - "sample-app", - NULL, /* no metadata */ - NULL); /* no named arguments */ - /* We will reuse this variant several times, so don't use floating refs */ - g_variant_ref_sink (parameters); - - for (i = 0; i < G_N_ELEMENTS (socket_paths); i++) - { - tuple = g_dbus_proxy_call_sync (f->proxy, "AddServer", - parameters, G_DBUS_CALL_FLAGS_NONE, -1, - NULL, &f->error); - g_assert_no_error (f->error); - g_assert_nonnull (tuple); - g_variant_get (tuple, "(o^ays)", NULL, &socket_paths[i], - &dbus_addresses[i]); - g_variant_unref (tuple); - socket_addresses[i] = g_unix_socket_address_new (socket_paths[i]); - g_test_message ("Server #%u at %s", i, socket_paths[i]); - } - - for (i = 0; i < G_N_ELEMENTS (placeholders); i++) - { - /* We enforce the resource limit for any connection to the socket, - * not just D-Bus connections that have done the handshake */ - placeholders[i] = g_socket_new (G_SOCKET_FAMILY_UNIX, - G_SOCKET_TYPE_STREAM, - G_SOCKET_PROTOCOL_DEFAULT, &f->error); - g_assert_no_error (f->error); - - g_socket_connect (placeholders[i], - socket_addresses[i % G_N_ELEMENTS (socket_paths)], - NULL, &f->error); - g_assert_no_error (f->error); - g_test_message ("Placeholder connection #%u to %s", i, - socket_paths[i % G_N_ELEMENTS (socket_paths)]); - } - - /* An extra connection to either of the sockets fails: they are both at - * capacity now */ - for (i = 0; i < G_N_ELEMENTS (socket_paths); i++) - { - f->confined_conn = g_dbus_connection_new_for_address_sync ( - dbus_addresses[i], - (G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION | - G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT), - NULL, NULL, &f->error); - assert_connection_closed (f->error); - - g_clear_error (&f->error); - g_assert_null (f->confined_conn); - } - - /* Free up one slot (this happens to be connected to socket_paths[0]) */ - g_socket_close (placeholders[2], &f->error); - g_assert_no_error (f->error); - - /* Now we can connect, but only once. Use a retry loop since the dbus-daemon - * won't necessarily notice our socket closing synchronously. */ - while (f->confined_conn == NULL) - { - g_test_message ("Trying to use the slot we just freed up..."); - f->confined_conn = g_dbus_connection_new_for_address_sync ( - dbus_addresses[0], - (G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION | - G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT), - NULL, NULL, &f->error); - - if (f->confined_conn == NULL) - { - assert_connection_closed (f->error); - g_clear_error (&f->error); - g_assert_nonnull (f->confined_conn); - } - else - { - g_assert_no_error (f->error); - } - } - - /* An extra connection to either of the sockets fails: they are both at - * capacity again */ - for (i = 0; i < G_N_ELEMENTS (socket_paths); i++) - { - GDBusConnection *another = g_dbus_connection_new_for_address_sync ( - dbus_addresses[i], - (G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION | - G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT), - NULL, NULL, &f->error); - - assert_connection_closed (f->error); - g_clear_error (&f->error); - g_assert_null (another); - } - - g_variant_unref (parameters); - - for (i = 0; i < G_N_ELEMENTS (socket_paths); i++) - { - g_free (socket_paths[i]); - g_free (dbus_addresses[i]); - g_clear_object (&socket_addresses[i]); - } - - for (i = 0; i < G_N_ELEMENTS (placeholders); i++) - g_clear_object (&placeholders[i]); - -#undef LIMIT -#else /* !HAVE_CONTAINERS_TEST */ - g_test_skip ("Containers or gio-unix-2.0 not supported"); -#endif /* !HAVE_CONTAINERS_TEST */ -} - -/* - * Test what happens when we exceed max_container_metadata_bytes. - * test_metadata() exercises the non-excessive case with the same - * configuration. - */ -static void -test_max_container_metadata_bytes (Fixture *f, - gconstpointer context) -{ -#ifdef HAVE_CONTAINERS_TEST - /* Must be >= max_container_metadata_bytes in limit-containers.conf, so that - * when the serialization overhead, app-container type and app name are - * added, it is too much for the limit */ - guchar waste_of_space[4096] = { 0 }; - GVariant *tuple; - GVariant *parameters; - GVariantDict dict; - - if (f->skip) - return; - - f->proxy = g_dbus_proxy_new_sync (f->unconfined_conn, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, - NULL, DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, DBUS_INTERFACE_CONTAINERS1, - NULL, &f->error); - g_assert_no_error (f->error); - - g_variant_dict_init (&dict, NULL); - g_variant_dict_insert (&dict, "waste of space", "@ay", - g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, - waste_of_space, - sizeof (waste_of_space), - 1)); - - /* Floating reference, call_..._sync takes ownership */ - parameters = g_variant_new ("(ss@a{sv}a{sv})", - "com.wasteheadquarters", - "Packt Like Sardines in a Crushd Tin Box", - g_variant_dict_end (&dict), - NULL); /* no named arguments */ - - tuple = g_dbus_proxy_call_sync (f->proxy, "AddServer", parameters, - G_DBUS_CALL_FLAGS_NONE, -1, NULL, &f->error); - g_assert_error (f->error, G_DBUS_ERROR, G_DBUS_ERROR_LIMITS_EXCEEDED); - g_assert_null (tuple); - g_clear_error (&f->error); - -#else /* !HAVE_CONTAINERS_TEST */ - g_test_skip ("Containers or gio-unix-2.0 not supported"); -#endif /* !HAVE_CONTAINERS_TEST */ -} - -static void -teardown (Fixture *f, - gconstpointer context G_GNUC_UNUSED) -{ - g_clear_object (&f->proxy); - - fixture_disconnect_observer (f); - g_clear_pointer (&f->containers_removed, g_hash_table_unref); - - if (f->libdbus_observer != NULL) - { - dbus_connection_remove_filter (f->libdbus_observer, - observe_shouting_cb, f); - test_connection_shutdown (f->ctx, f->libdbus_observer); - dbus_connection_close (f->libdbus_observer); - } - - dbus_clear_connection (&f->libdbus_observer); - - fixture_disconnect_unconfined (f); - - if (f->confined_conn != NULL) - { - GError *error = NULL; - - g_dbus_connection_close_sync (f->confined_conn, NULL, &error); - - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED)) - g_clear_error (&error); - else - g_assert_no_error (error); - } - - g_clear_object (&f->confined_conn); - - if (f->daemon_pid != 0) - { - test_kill_pid (f->daemon_pid); - g_spawn_close_pid (f->daemon_pid); - f->daemon_pid = 0; - } - - dbus_clear_message (&f->latest_shout); - g_free (f->instance_path); - g_free (f->socket_path); - g_free (f->socket_dbus_address); - g_free (f->bus_address); - g_clear_error (&f->error); - test_main_context_unref (f->ctx); - g_free (f->unconfined_unique_name); -} - -static const Config stop_server_explicitly = -{ - "valid-config-files/multi-user.conf", - STOP_SERVER_EXPLICITLY -}; -static const Config stop_server_disconnect_first = -{ - "valid-config-files/multi-user.conf", - STOP_SERVER_DISCONNECT_FIRST -}; -static const Config stop_server_never_connected = -{ - "valid-config-files/multi-user.conf", - STOP_SERVER_NEVER_CONNECTED -}; -static const Config stop_server_force = -{ - "valid-config-files/multi-user.conf", - STOP_SERVER_FORCE -}; -static const Config stop_server_with_manager = -{ - "valid-config-files/multi-user.conf", - STOP_SERVER_WITH_MANAGER -}; -static const Config limit_containers = -{ - "valid-config-files/limit-containers.conf", - 0 /* not relevant for this test */ -}; -static const Config max_containers = -{ - "valid-config-files/max-containers.conf", - 0 /* not relevant for this test */ -}; - -int -main (int argc, - char **argv) -{ - GError *error = NULL; - gchar *runtime_dir; - gchar *runtime_dbus_dir; - gchar *runtime_containers_dir; - gchar *runtime_services_dir; - int ret; - - runtime_dir = g_dir_make_tmp ("dbus-test-containers.XXXXXX", &error); - - if (runtime_dir == NULL) - { - g_print ("Bail out! %s\n", error->message); - g_clear_error (&error); - return 1; - } - - g_setenv ("XDG_RUNTIME_DIR", runtime_dir, TRUE); - runtime_dbus_dir = g_build_filename (runtime_dir, "dbus-1", NULL); - runtime_containers_dir = g_build_filename (runtime_dir, "dbus-1", - "containers", NULL); - runtime_services_dir = g_build_filename (runtime_dir, "dbus-1", - "services", NULL); - - test_init (&argc, &argv); - - g_test_add ("/containers/get-supported-arguments", Fixture, NULL, - setup, test_get_supported_arguments, teardown); - g_test_add ("/containers/basic", Fixture, NULL, - setup, test_basic, teardown); - g_test_add ("/containers/wrong-uid", Fixture, NULL, - setup, test_wrong_uid, teardown); - g_test_add ("/containers/stop-server/explicitly", Fixture, - &stop_server_explicitly, setup, test_stop_server, teardown); - g_test_add ("/containers/stop-server/disconnect-first", Fixture, - &stop_server_disconnect_first, setup, test_stop_server, teardown); - g_test_add ("/containers/stop-server/never-connected", Fixture, - &stop_server_never_connected, setup, test_stop_server, teardown); - g_test_add ("/containers/stop-server/force", Fixture, - &stop_server_force, setup, test_stop_server, teardown); - g_test_add ("/containers/stop-server/with-manager", Fixture, - &stop_server_with_manager, setup, test_stop_server, teardown); - g_test_add ("/containers/metadata", Fixture, &limit_containers, - setup, test_metadata, teardown); - g_test_add ("/containers/invalid-metadata-getters", Fixture, NULL, - setup, test_invalid_metadata_getters, teardown); - g_test_add ("/containers/unsupported-parameter", Fixture, NULL, - setup, test_unsupported_parameter, teardown); - g_test_add ("/containers/invalid-type-name", Fixture, NULL, - setup, test_invalid_type_name, teardown); - g_test_add ("/containers/invalid-nesting", Fixture, NULL, - setup, test_invalid_nesting, teardown); - g_test_add ("/containers/max-containers", Fixture, &max_containers, - setup, test_max_containers, teardown); - g_test_add ("/containers/max-containers-per-user", Fixture, &limit_containers, - setup, test_max_containers, teardown); - g_test_add ("/containers/max-connections-per-container", Fixture, - &limit_containers, - setup, test_max_connections_per_container, teardown); - g_test_add ("/containers/max-container-metadata-bytes", Fixture, - &limit_containers, - setup, test_max_container_metadata_bytes, teardown); - - ret = g_test_run (); - - test_rmdir_if_exists (runtime_containers_dir); - test_rmdir_if_exists (runtime_services_dir); - test_rmdir_if_exists (runtime_dbus_dir); - test_rmdir_must_exist (runtime_dir); - g_free (runtime_containers_dir); - g_free (runtime_services_dir); - g_free (runtime_dbus_dir); - g_free (runtime_dir); - dbus_shutdown (); - return ret; -} diff --git a/test/meson.build b/test/meson.build index d66c6410..1e61679a 100644 --- a/test/meson.build +++ b/test/meson.build @@ -591,12 +591,6 @@ if use_glib if platform_unix tests += [ - { 'name': 'containers', - 'srcs': [ 'containers.c' ], - 'link': [ libdbus_testutils, ], - 'deps': [ glib, gio, ], - 'suite': ['runs-dbus-daemon'], - }, { 'name': 'sd-activation', 'srcs': [ 'sd-activation.c' ], 'link': [ libdbus_testutils, ],