From: Simon McVittie Date: Tue, 19 Nov 2024 13:11:13 +0000 (+0000) Subject: Completely remove the Containers1 interface X-Git-Tag: dbus-1.15.90~3^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c0d4873704fa3586e2eaceb12080aa503bee43cf;p=thirdparty%2Fdbus.git Completely remove the Containers1 interface This interface is still not ready for production use. To minimize confusion, let's remove it from the 1.16.x stable branch. We can have another try during the 1.17.x cycle, via dbus/dbus!449. Signed-off-by: Simon McVittie --- diff --git a/bus/CMakeLists.txt b/bus/CMakeLists.txt index febfaeb03..e464f6057 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 62d58f8e9..eaa8f2aea 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 88451ebbf..b970be656 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 f0177c6f8..e79177789 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 816f3e1b2..000000000 --- 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 842a43f47..000000000 --- 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 ebd98015d..fa4213c1c 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 058e3b25a..176894d62 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 4bf1b02b8..000000000 --- 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 91dd13f3c..f866879ce 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 09f2e3fa9..9ec005808 100644 --- a/meson.build +++ b/meson.build @@ -1078,7 +1078,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') @@ -1325,7 +1324,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 83c1c9217..e63f4bd6b 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 796364600..000000000 --- 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 d66c64109..1e61679aa 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, ],