diff --git a/CMakeLists.txt b/CMakeLists.txt index c6aa0a08..35c1d76c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,6 +125,7 @@ endif() option(DBUS_DISABLE_ASSERT "Disable assertion checking" OFF) option(DBUS_ENABLE_STATS "enable bus daemon usage statistics" OFF) +option(DBUS_ENABLE_CONTAINERS "enable restricted servers for app-containers" OFF) option(ENABLE_TRADITIONAL_ACTIVATION "Enable traditional activation (without using systemd)" ON) find_package(PkgConfig) diff --git a/README.cmake b/README.cmake index 81cac84b..389e11b4 100644 --- a/README.cmake +++ b/README.cmake @@ -152,6 +152,9 @@ ENABLE_QT_HELP:STRING=AUTO // enable bus daemon usage statistics DBUS_ENABLE_STATS:BOOL=OFF +// enable restricted servers for app containers +DBUS_ENABLE_CONTAINERS:BOOL=OFF + // build with systemd at_console support ENABLE_SYSTEMD:STRING=AUTO diff --git a/bus/connection.c b/bus/connection.c index f0177c6f..dccb0d61 100644 --- a/bus/connection.c +++ b/bus/connection.c @@ -595,7 +595,8 @@ cache_peer_loginfo_string (BusConnectionData *d, dbus_bool_t prev_added; const char *container = NULL; const char *container_type = NULL; - const char *container_name = NULL; + const char *app_id = NULL; + const char *instance_id = NULL; DBusCredentials *credentials; if (!_dbus_string_init (&loginfo_buf)) @@ -679,7 +680,8 @@ cache_peer_loginfo_string (BusConnectionData *d, /* This does have to come from the connection, not the credentials */ if (bus_containers_connection_is_contained (connection, &container, &container_type, - &container_name)) + &app_id, + &instance_id)) { dbus_bool_t did_append; @@ -690,10 +692,11 @@ cache_peer_loginfo_string (BusConnectionData *d, } did_append = _dbus_string_append_printf (&loginfo_buf, - "container=%s %s=\"%s\")", + "container=%s %s=\"%s\" inst=\"%s\")", container, container_type, - container_name); + app_id, + instance_id); if (!did_append) goto oom; else @@ -2478,17 +2481,17 @@ bus_transaction_send (BusTransaction *transaction, * 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) + if ((d->want_headers & BUS_EXTRA_HEADERS_CONTAINER_PATH) && + dbus_message_get_container_path (message) == NULL) { const char *path; if (sender == NULL || !bus_containers_connection_is_contained (sender, &path, - NULL, NULL)) + NULL, NULL, NULL)) path = "/"; - if (!dbus_message_set_container_instance (message, path)) + if (!dbus_message_set_container_path (message, path)) return FALSE; } diff --git a/bus/connection.h b/bus/connection.h index 0ce60d11..f3eca5d0 100644 --- a/bus/connection.h +++ b/bus/connection.h @@ -32,7 +32,7 @@ typedef enum { - BUS_EXTRA_HEADERS_CONTAINER_INSTANCE = (1 << 0), + BUS_EXTRA_HEADERS_CONTAINER_PATH = (1 << 0), BUS_EXTRA_HEADERS_NONE = 0 } BusExtraHeaders; diff --git a/bus/containers.c b/bus/containers.c index 816f3e1b..9f8c638f 100644 --- a/bus/containers.c +++ b/bus/containers.c @@ -1,6 +1,6 @@ /* containers.c - restricted bus servers for containers * - * Copyright © 2017 Collabora Ltd. + * Copyright © 2017-2023 Collabora Ltd. * * SPDX-License-Identifier: AFL-2.1 OR GPL-2.0-or-later * @@ -29,17 +29,18 @@ #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 +#include "dbus/dbus-asv-util.h" #include "dbus/dbus-hash.h" #include "dbus/dbus-message-internal.h" #include "dbus/dbus-sysdeps-unix.h" +#include "dbus/dbus-watch.h" #include "connection.h" #include "dispatch.h" @@ -47,7 +48,7 @@ #include "utils.h" /* - * A container instance groups together a per-app-container server with + * A container server groups together a per-app-container server with * all the connections for which it is responsible. */ typedef struct @@ -55,7 +56,8 @@ typedef struct int refcount; char *path; char *type; - char *name; + char *app_id; + char *instance_id; DBusVariant *metadata; BusContext *context; BusContainers *containers; @@ -64,16 +66,19 @@ typedef struct /* List of owned DBusConnection, removed when the DBusConnection is * removed from the bus */ DBusList *connections; + DBusWatch *stop_on_notify_watch; unsigned long uid; + int stop_on_notify_fd; unsigned announced:1; -} BusContainerInstance; + unsigned stop_on_disconnect:1; +} BusContainerServer; -/* Data attached to a DBusConnection that has created container instances. */ +/* Data attached to a DBusConnection that has created container servers. */ typedef struct { - /* List of instances created by this connection; unowned. - * The BusContainerInstance removes itself from here on destruction. */ - DBusList *instances; + /* List of servers created by this connection; unowned. + * The BusContainerServer removes itself from here on destruction. */ + DBusList *servers; } BusContainerCreatorData; /* Data slot on DBusConnection, holding BusContainerCreatorData */ @@ -86,16 +91,16 @@ static dbus_int32_t container_creator_data_slot = -1; struct BusContainers { int refcount; - /* path borrowed from BusContainerInstance => unowned BusContainerInstance - * The BusContainerInstance removes itself from here on destruction. */ - DBusHashTable *instances_by_path; + /* path borrowed from BusContainerServer => unowned BusContainerServer + * The BusContainerServer removes itself from here on destruction. */ + DBusHashTable *servers_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 */ +/* Data slot on DBusConnection, holding BusContainerServer */ static dbus_int32_t contained_data_slot = -1; BusContainers * @@ -122,7 +127,7 @@ bus_containers_new (void) goto oom; self->refcount = 1; - self->instances_by_path = NULL; + self->servers_by_path = NULL; self->next_container_id = DBUS_UINT64_CONSTANT (0); self->address_template = invalid; @@ -195,7 +200,7 @@ bus_containers_unref (BusContainers *self) if (--self->refcount == 0) { - _dbus_clear_hash_table (&self->instances_by_path); + _dbus_clear_hash_table (&self->servers_by_path); _dbus_clear_hash_table (&self->n_containers_by_user); _dbus_string_free (&self->address_template); dbus_free (self); @@ -208,8 +213,8 @@ bus_containers_unref (BusContainers *self) } } -static BusContainerInstance * -bus_container_instance_ref (BusContainerInstance *self) +static BusContainerServer * +bus_container_server_ref (BusContainerServer *self) { _dbus_assert (self->refcount > 0); _dbus_assert (self->refcount < _DBUS_INT_MAX); @@ -219,7 +224,7 @@ bus_container_instance_ref (BusContainerInstance *self) } static dbus_bool_t -bus_container_instance_emit_removed (BusContainerInstance *self) +bus_container_server_emit_removed (BusContainerServer *self) { BusTransaction *transaction = NULL; DBusMessage *message = NULL; @@ -232,7 +237,7 @@ bus_container_instance_emit_removed (BusContainerInstance *self) message = dbus_message_new_signal (DBUS_PATH_DBUS, DBUS_INTERFACE_CONTAINERS1, - "InstanceRemoved"); + "ServerRemoved"); if (message == NULL || !dbus_message_set_sender (message, DBUS_SERVICE_DBUS) || @@ -253,7 +258,7 @@ bus_container_instance_emit_removed (BusContainerInstance *self) * 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 " + _dbus_warn ("Failed to send ServerRemoved for a reason " "other than OOM: %s: %s", error.name, error.message); dbus_error_free (&error); } @@ -274,7 +279,30 @@ oom: } static void -bus_container_instance_unref (BusContainerInstance *self) +bus_container_server_remove_notify (BusContainerServer *self) +{ + DBusWatch *watch; + + /* Transfer the reference to this function */ + watch = self->stop_on_notify_watch; + self->stop_on_notify_watch = NULL; + + if (watch != NULL) + { + _dbus_loop_remove_watch (bus_context_get_loop (self->context), watch); + _dbus_watch_invalidate (watch); + _dbus_watch_unref (watch); + } + + if (self->stop_on_notify_fd >= 0) + { + close (self->stop_on_notify_fd); + self->stop_on_notify_fd = -1; + } +} + +static void +bus_container_server_unref (BusContainerServer *self) { _dbus_assert (self->refcount > 0); @@ -282,10 +310,10 @@ bus_container_instance_unref (BusContainerInstance *self) { BusContainerCreatorData *creator_data; - /* If we announced the container instance in a reply from + /* If we announced the container server 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. + * ServerRemoved for it. * * Similar to bus/connection.c dropping well-known name ownership, * this isn't really a situation where we can "fail", because @@ -293,29 +321,31 @@ bus_container_instance_unref (BusContainerInstance *self) * connection disconnecting; so we use a retry loop on OOM. */ for (; self->announced; _dbus_wait_for_memory ()) { - if (bus_container_instance_emit_removed (self)) + if (bus_container_server_emit_removed (self)) self->announced = FALSE; } - /* As long as the server is listening, the BusContainerInstance can't + bus_container_server_remove_notify (self); + + /* As long as the server is listening, the BusContainerServer can't * be freed, because the DBusServer holds a reference to the - * BusContainerInstance */ + * BusContainerServer */ _dbus_assert (self->server == NULL); - /* Similarly, as long as there are connections, the BusContainerInstance + /* Similarly, as long as there are connections, the BusContainerServer * can't be freed, because each connection holds a reference to the - * BusContainerInstance */ + * BusContainerServer */ _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); + _dbus_list_remove (&creator_data->servers, self); - /* It's OK to do this even if we were never added to instances_by_path, + /* It's OK to do this even if we were never added to servers_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, + if (self->path != NULL && self->containers->servers_by_path != NULL && + _dbus_hash_table_remove_string (self->containers->servers_by_path, self->path)) { DBusHashIter entry; @@ -325,7 +355,7 @@ bus_container_instance_unref (BusContainerInstance *self) (void *) (uintptr_t) self->uid, FALSE, &entry)) _dbus_assert_not_reached ("Container should not be placed in " - "instances_by_path until its " + "servers_by_path until its " "n_containers_by_user entry has " "been allocated"); @@ -341,23 +371,26 @@ bus_container_instance_unref (BusContainerInstance *self) dbus_connection_unref (self->creator); dbus_free (self->path); dbus_free (self->type); - dbus_free (self->name); + dbus_free (self->app_id); + dbus_free (self->instance_id); dbus_free (self); } } static inline void -bus_clear_container_instance (BusContainerInstance **instance_p) +bus_clear_container_server (BusContainerServer **server_p) { - _dbus_clear_pointer_impl (BusContainerInstance, instance_p, - bus_container_instance_unref); + _dbus_clear_pointer_impl (BusContainerServer, server_p, + bus_container_server_unref); } static void -bus_container_instance_stop_listening (BusContainerInstance *self) +bus_container_server_stop_listening (BusContainerServer *self) { /* In case the DBusServer holds the last reference to self */ - bus_container_instance_ref (self); + bus_container_server_ref (self); + + bus_container_server_remove_notify (self); if (self->server != NULL) { @@ -366,16 +399,16 @@ bus_container_instance_stop_listening (BusContainerInstance *self) dbus_clear_server (&self->server); } - bus_container_instance_unref (self); + bus_container_server_unref (self); } -static BusContainerInstance * -bus_container_instance_new (BusContext *context, - BusContainers *containers, - DBusConnection *creator, - DBusError *error) +static BusContainerServer * +bus_container_server_new (BusContext *context, + BusContainers *containers, + DBusConnection *creator, + DBusError *error) { - BusContainerInstance *self = NULL; + BusContainerServer *self = NULL; DBusString path = _DBUS_STRING_INIT_INVALID; _dbus_assert (context != NULL); @@ -389,7 +422,7 @@ bus_container_instance_new (BusContext *context, goto fail; } - self = dbus_new0 (BusContainerInstance, 1); + self = dbus_new0 (BusContainerServer, 1); if (self == NULL) { @@ -399,12 +432,15 @@ bus_container_instance_new (BusContext *context, self->refcount = 1; self->type = NULL; - self->name = NULL; + self->app_id = NULL; + self->instance_id = 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); + self->stop_on_notify_fd = -1; + self->stop_on_disconnect = TRUE; if (containers->next_container_id >= DBUS_UINT64_CONSTANT (0xFFFFFFFFFFFFFFFF)) @@ -434,7 +470,7 @@ fail: _dbus_string_free (&path); if (self != NULL) - bus_container_instance_unref (self); + bus_container_server_unref (self); return NULL; } @@ -442,9 +478,9 @@ fail: static void bus_container_creator_data_free (BusContainerCreatorData *self) { - /* Each instance holds a ref to the creator, so there should be + /* Each server holds a ref to the creator, so there should be * nothing here */ - _dbus_assert (self->instances == NULL); + _dbus_assert (self->servers == NULL); dbus_free (self); } @@ -474,74 +510,74 @@ allow_same_uid_only (DBusConnection *connection, } static void -bus_container_instance_lost_connection (BusContainerInstance *instance, - DBusConnection *connection) +bus_container_server_lost_connection (BusContainerServer *server, + DBusConnection *connection) { - bus_container_instance_ref (instance); + bus_container_server_ref (server); 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)) + * container server. */ + if (_dbus_list_remove (&server->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 + * reference to the server will be cleaned up on last-unref, and + * the list removal above ensures that the server does not hold a * circular ref to the connection, so the last-unref will happen. */ dbus_connection_unref (connection); - bus_container_instance_unref (instance); + bus_container_server_unref (server); } static void -new_connection_cb (DBusServer *server, +new_connection_cb (DBusServer *lower_level_server, DBusConnection *new_connection, void *data) { - BusContainerInstance *instance = data; - int limit = bus_context_get_max_connections_per_container (instance->context); + BusContainerServer *server = data; + int limit = bus_context_get_max_connections_per_container (server->context); /* This is O(n), but we assume n is small in practice. */ - if (_dbus_list_get_length (&instance->connections) >= limit) + if (_dbus_list_get_length (&server->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, + bus_context_log (server->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); + server->path, server->type, server->app_id, limit); return; } if (!dbus_connection_set_data (new_connection, contained_data_slot, - bus_container_instance_ref (instance), - (DBusFreeFunction) bus_container_instance_unref)) + bus_container_server_ref (server), + (DBusFreeFunction) bus_container_server_unref)) { - bus_container_instance_unref (instance); - bus_container_instance_lost_connection (instance, new_connection); + bus_container_server_unref (server); + bus_container_server_lost_connection (server, new_connection); return; } - if (_dbus_list_append (&instance->connections, new_connection)) + if (_dbus_list_append (&server->connections, new_connection)) { dbus_connection_ref (new_connection); } else { - bus_container_instance_lost_connection (instance, new_connection); + bus_container_server_lost_connection (server, 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)) + if (!bus_context_add_incoming_connection (server->context, new_connection)) { - bus_container_instance_lost_connection (instance, new_connection); + bus_container_server_lost_connection (server, new_connection); return; } @@ -559,7 +595,7 @@ new_connection_cb (DBusServer *server, * allow_same_uid_only ensures that * this cast does not lose * information */ - (void *) (uintptr_t) instance->uid, + (void *) (uintptr_t) server->uid, NULL); } @@ -637,8 +673,8 @@ out: } static dbus_bool_t -bus_container_instance_listen (BusContainerInstance *self, - DBusError *error) +bus_container_server_listen (BusContainerServer *self, + DBusError *error) { BusContainers *containers = bus_context_get_containers (self->context); const char *address; @@ -665,8 +701,40 @@ bus_container_instance_listen (BusContainerInstance *self, /* 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); + bus_container_server_ref (self), + (DBusFreeFunction) bus_container_server_unref); + return TRUE; +} + +static dbus_bool_t +check_named_parameter_type (DBusMessageIter *variant_iter, + const char *param_name, + int expected_type, + DBusError *error) +{ + if (dbus_message_iter_get_arg_type (variant_iter) != expected_type) + { + dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, + "Named parameter %s should have type '%c', not '%c'", + param_name, expected_type, + dbus_message_iter_get_arg_type (variant_iter)); + return FALSE; + } + + return TRUE; +} + +static dbus_bool_t +bus_containers_handle_stop_notify (DBusWatch *watch, + unsigned int flags, + void *data) +{ + BusContainerServer *server = data; + + _dbus_assert (watch == server->stop_on_notify_watch); + _dbus_verbose ("Stopping %s because notify fd became readable", + server->path); + bus_container_server_stop_listening (server); return TRUE; } @@ -679,12 +747,13 @@ bus_containers_handle_add_server (DBusConnection *connection, BusContainerCreatorData *creator_data; DBusMessageIter iter; DBusMessageIter dict_iter; - DBusMessageIter writer; - DBusMessageIter array_writer; + DBusMessageIter writer = DBUS_MESSAGE_ITER_INIT_CLOSED; + DBusMessageIter asv_writer = DBUS_MESSAGE_ITER_INIT_CLOSED; const char *type; - const char *name; + const char *app_id; + const char *instance_id; const char *path; - BusContainerInstance *instance = NULL; + BusContainerServer *server = NULL; BusContext *context; BusContainers *containers; char *address = NULL; @@ -709,7 +778,7 @@ bus_containers_handle_add_server (DBusConnection *connection, if (creator_data == NULL) goto oom; - creator_data->instances = NULL; + creator_data->servers = NULL; if (!dbus_connection_set_data (connection, container_creator_data_slot, creator_data, @@ -720,13 +789,13 @@ bus_containers_handle_add_server (DBusConnection *connection, } } - instance = bus_container_instance_new (context, containers, connection, - error); + server = bus_container_server_new (context, containers, connection, + error); - if (instance == NULL) + if (server == NULL) goto fail; - if (!dbus_connection_get_unix_user (connection, &instance->uid)) + if (!dbus_connection_get_unix_user (connection, &server->uid)) { dbus_set_error (error, DBUS_ERROR_FAILED, "Unable to determine user ID of caller"); @@ -734,7 +803,7 @@ bus_containers_handle_add_server (DBusConnection *connection, } /* We already checked this in bus_driver_handle_message() */ - _dbus_assert (dbus_message_has_signature (message, "ssa{sv}a{sv}")); + _dbus_assert (dbus_message_has_signature (message, "sssa{sv}a{sv}")); /* Argument 0: Container type */ if (!dbus_message_iter_init (message, &iter)) @@ -742,9 +811,9 @@ bus_containers_handle_add_server (DBusConnection *connection, _dbus_assert (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_STRING); dbus_message_iter_get_basic (&iter, &type); - instance->type = _dbus_strdup (type); + server->type = _dbus_strdup (type); - if (instance->type == NULL) + if (server->type == NULL) goto oom; if (!dbus_validate_interface (type, NULL)) @@ -755,35 +824,47 @@ bus_containers_handle_add_server (DBusConnection *connection, goto fail; } - /* Argument 1: Name as defined by container manager */ + /* Argument 1: app-ID 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); + dbus_message_iter_get_basic (&iter, &app_id); + server->app_id = _dbus_strdup (app_id); - if (instance->name == NULL) + if (server->app_id == NULL) goto oom; - /* Argument 2: Metadata as defined by container manager */ + /* Argument 2: instance-ID 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, &instance_id); + server->instance_id = _dbus_strdup (instance_id); + + if (server->instance_id == NULL) + goto oom; + + /* Argument 3: 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), + server->metadata = _dbus_variant_read (&iter); + _dbus_assert (strcmp (_dbus_variant_get_signature (server->metadata), "a{sv}") == 0); - /* For simplicity we don't count the size of the BusContainerInstance + /* For simplicity we don't count the size of the BusContainerServer * 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) + + metadata_size = _dbus_variant_get_length (server->metadata) + (int) strlen (type) + - (int) strlen (name); + (int) strlen (app_id) + + (int) strlen (instance_id); limit = bus_context_get_max_container_metadata_bytes (context); if (metadata_size > limit) @@ -803,16 +884,19 @@ bus_containers_handle_add_server (DBusConnection *connection, goto fail; } - /* Argument 3: Named parameters */ + /* Argument 4: 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) + for (; + dbus_message_iter_get_arg_type (&dict_iter) != DBUS_TYPE_INVALID; + dbus_message_iter_next (&dict_iter)) { DBusMessageIter pair_iter; + DBusMessageIter variant_iter; const char *param_name; _dbus_assert (dbus_message_iter_get_arg_type (&dict_iter) == @@ -823,22 +907,75 @@ bus_containers_handle_add_server (DBusConnection *connection, 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; + if (!dbus_message_iter_next (&pair_iter)) + _dbus_assert_not_reached ("dict entry with less than 2 items"); + + _dbus_assert (dbus_message_iter_get_arg_type (&pair_iter) == + DBUS_TYPE_VARIANT); + dbus_message_iter_recurse (&pair_iter, &variant_iter); + + if (strcmp (param_name, "StopOnDisconnect") == 0) + { + dbus_bool_t value; + + if (!check_named_parameter_type (&variant_iter, param_name, + DBUS_TYPE_BOOLEAN, error)) + goto fail; + + dbus_message_iter_get_basic (&variant_iter, &value); + server->stop_on_disconnect = !!value; + } + else if (strcmp (param_name, "StopOnNotify") == 0) + { + if (!check_named_parameter_type (&variant_iter, param_name, + DBUS_TYPE_UNIX_FD, error)) + goto fail; + + dbus_message_iter_get_basic (&variant_iter, + &server->stop_on_notify_fd); + + if (server->stop_on_notify_fd < 0) + { + dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, + "Unable to retrieve StopOnNotify fd"); + goto fail; + } + + server->stop_on_notify_watch = _dbus_watch_new (server->stop_on_notify_fd, + DBUS_WATCH_READABLE, + TRUE, /* enabled */ + bus_containers_handle_stop_notify, + server, + NULL); + + if (server->stop_on_notify_watch == NULL || + !_dbus_loop_add_watch (bus_context_get_loop (context), + server->stop_on_notify_watch)) + { + BUS_SET_OOM (error); + goto fail; + } + } + else + { + dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, + "Named parameter %s is not understood", param_name); + goto fail; + } + + if (dbus_message_iter_next (&pair_iter)) + _dbus_assert_not_reached ("dict entry with more than 2 items"); } /* End of arguments */ _dbus_assert (!dbus_message_iter_has_next (&iter)); - if (containers->instances_by_path == NULL) + if (containers->servers_by_path == NULL) { - containers->instances_by_path = _dbus_hash_table_new (DBUS_HASH_STRING, - NULL, NULL); + containers->servers_by_path = _dbus_hash_table_new (DBUS_HASH_STRING, + NULL, NULL); - if (containers->instances_by_path == NULL) + if (containers->servers_by_path == NULL) goto oom; } @@ -853,7 +990,7 @@ bus_containers_handle_add_server (DBusConnection *connection, limit = bus_context_get_max_containers (context); - if (_dbus_hash_table_get_n_entries (containers->instances_by_path) >= limit) + if (_dbus_hash_table_get_n_entries (containers->servers_by_path) >= limit) { DBusError local_error = DBUS_ERROR_INIT; @@ -872,7 +1009,7 @@ bus_containers_handle_add_server (DBusConnection *connection, 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, + (void *) (uintptr_t) server->uid, TRUE, &n_containers_by_user_entry)) goto oom; @@ -891,34 +1028,34 @@ bus_containers_handle_add_server (DBusConnection *connection, "(max_containers_per_user=%d)", bus_connection_get_name (connection), bus_connection_get_loginfo (connection), - instance->uid, limit); + server->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)) + if (!_dbus_hash_table_insert_string (containers->servers_by_path, + server->path, server)) 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. */ + * we already succeeded in adding it to servers_by_path. The matching + * decrement is done whenever we remove it from servers_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)) + if (!_dbus_list_append (&creator_data->servers, server)) 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)) + if (!bus_container_server_listen (server, error)) goto fail; - address = dbus_server_get_address (instance->server); + address = dbus_server_get_address (server->server); if (!dbus_parse_address (address, &entries, &n_entries, error)) _dbus_assert_not_reached ("listening on unix:dir= should yield a valid address"); @@ -932,40 +1069,34 @@ bus_containers_handle_add_server (DBusConnection *connection, reply = dbus_message_new_method_return (message); if (!dbus_message_append_args (reply, - DBUS_TYPE_OBJECT_PATH, &instance->path, + DBUS_TYPE_OBJECT_PATH, &server->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)) + if (!dbus_message_iter_open_container (&writer, DBUS_TYPE_ARRAY, "{sv}", + &asv_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)) + if (!_dbus_asv_add_string (&asv_writer, "Address", address)) goto oom; - if (!dbus_message_append_args (reply, - DBUS_TYPE_STRING, &address, - DBUS_TYPE_INVALID)) + if (!_dbus_asv_add_byte_array (&asv_writer, "SocketPath", + path, strlen (path) + 1)) goto oom; - _dbus_assert (dbus_message_has_signature (reply, "oays")); + if (!dbus_message_iter_close_container (&writer, &asv_writer)) + goto oom; + + _dbus_assert (dbus_message_has_signature (reply, "oa{sv}")); if (! bus_transaction_send_from_driver (transaction, connection, reply)) goto oom; - instance->announced = TRUE; + server->announced = TRUE; dbus_message_unref (reply); - bus_container_instance_unref (instance); + bus_container_server_unref (server); dbus_address_entries_free (entries); dbus_free (address); return TRUE; @@ -974,38 +1105,59 @@ oom: BUS_SET_OOM (error); /* fall through */ fail: - if (instance != NULL) - bus_container_instance_stop_listening (instance); + dbus_message_iter_abandon_container_if_open (&writer, &asv_writer); + + if (server != NULL) + bus_container_server_stop_listening (server); dbus_clear_message (&reply); dbus_clear_address_entries (&entries); - bus_clear_container_instance (&instance); + bus_clear_container_server (&server); dbus_free (address); return FALSE; } dbus_bool_t -bus_containers_supported_arguments_getter (BusContext *context, +bus_containers_supported_arguments_getter (BusContext *server, DBusMessageIter *var_iter) { + /* Please keep these sorted in strcmp (LC_ALL=C sort) order */ + static const char * const supported[] = + { + "StopOnDisconnect", + "StopOnNotify", + }; DBusMessageIter arr_iter; + size_t i; - /* 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); + if (!dbus_message_iter_open_container (var_iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_STRING_AS_STRING, + &arr_iter)) + return FALSE; + + for (i = 0; i < _DBUS_N_ELEMENTS (supported); i++) + { + if (!dbus_message_iter_append_basic (&arr_iter, + DBUS_TYPE_STRING, + &supported[i])) + { + dbus_message_iter_abandon_container (var_iter, &arr_iter); + return FALSE; + } + } + + return 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) +bus_containers_handle_stop_server (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) { BusContext *context; BusContainers *containers; - BusContainerInstance *instance = NULL; + BusContainerServer *server = NULL; DBusList *iter; const char *path; unsigned long uid; @@ -1018,13 +1170,13 @@ bus_containers_handle_stop_instance (DBusConnection *connection, context = bus_transaction_get_context (transaction); containers = bus_context_get_containers (context); - if (containers->instances_by_path != NULL) + if (containers->servers_by_path != NULL) { - instance = _dbus_hash_table_lookup_string (containers->instances_by_path, - path); + server = _dbus_hash_table_lookup_string (containers->servers_by_path, + path); } - if (instance == NULL) + if (server == NULL) { dbus_set_error (error, DBUS_ERROR_NOT_CONTAINER, "There is no container with path '%s'", path); @@ -1038,23 +1190,23 @@ bus_containers_handle_stop_instance (DBusConnection *connection, goto failed; } - if (uid != instance->uid) + if (uid != server->uid) { dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, "User %lu cannot stop a container server started by " - "user %lu", uid, instance->uid); + "user %lu", uid, server->uid); goto failed; } - bus_container_instance_ref (instance); - bus_container_instance_stop_listening (instance); + bus_container_server_ref (server); + bus_container_server_stop_listening (server); - for (iter = _dbus_list_get_first_link (&instance->connections); + for (iter = _dbus_list_get_first_link (&server->connections); iter != NULL; - iter = _dbus_list_get_next_link (&instance->connections, iter)) + iter = _dbus_list_get_next_link (&server->connections, iter)) dbus_connection_close (iter->data); - bus_container_instance_unref (instance); + bus_container_server_unref (server); if (!bus_driver_send_ack_reply (connection, transaction, message, error)) goto failed; @@ -1074,7 +1226,7 @@ bus_containers_handle_stop_listening (DBusConnection *connection, { BusContext *context; BusContainers *containers; - BusContainerInstance *instance = NULL; + BusContainerServer *server = NULL; const char *path; unsigned long uid; @@ -1086,13 +1238,13 @@ bus_containers_handle_stop_listening (DBusConnection *connection, context = bus_transaction_get_context (transaction); containers = bus_context_get_containers (context); - if (containers->instances_by_path != NULL) + if (containers->servers_by_path != NULL) { - instance = _dbus_hash_table_lookup_string (containers->instances_by_path, - path); + server = _dbus_hash_table_lookup_string (containers->servers_by_path, + path); } - if (instance == NULL) + if (server == NULL) { dbus_set_error (error, DBUS_ERROR_NOT_CONTAINER, "There is no container with path '%s'", path); @@ -1106,17 +1258,17 @@ bus_containers_handle_stop_listening (DBusConnection *connection, goto failed; } - if (uid != instance->uid) + if (uid != server->uid) { dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, "User %lu cannot stop a container server started by " - "user %lu", uid, instance->uid); + "user %lu", uid, server->uid); goto failed; } - bus_container_instance_ref (instance); - bus_container_instance_stop_listening (instance); - bus_container_instance_unref (instance); + bus_container_server_ref (server); + bus_container_server_stop_listening (server); + bus_container_server_unref (server); if (!bus_driver_send_ack_reply (connection, transaction, message, error)) goto failed; @@ -1133,8 +1285,8 @@ failed: * 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) +static BusContainerServer * +connection_get_server (DBusConnection *connection) { if (connection == NULL) return NULL; @@ -1146,12 +1298,12 @@ connection_get_instance (DBusConnection *connection) } dbus_bool_t -bus_containers_handle_get_connection_instance (DBusConnection *caller, - BusTransaction *transaction, - DBusMessage *message, - DBusError *error) +bus_containers_handle_get_connection_info (DBusConnection *caller, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) { - BusContainerInstance *instance; + BusContainerServer *server; BusDriverFound found; DBusConnection *subject; DBusMessage *reply = NULL; @@ -1161,7 +1313,7 @@ bus_containers_handle_get_connection_instance (DBusConnection *caller, _DBUS_ASSERT_ERROR_IS_CLEAR (error); - found = bus_driver_get_conn_helper (caller, message, "container instance", + found = bus_driver_get_conn_helper (caller, message, "container information", &bus_name, &subject, error); switch (found) @@ -1180,9 +1332,9 @@ bus_containers_handle_get_connection_instance (DBusConnection *caller, goto failed; } - instance = connection_get_instance (subject); + server = connection_get_server (subject); - if (instance == NULL) + if (server == NULL) { dbus_set_error (error, DBUS_ERROR_NOT_CONTAINER, "Connection '%s' is not in a container", bus_name); @@ -1195,7 +1347,7 @@ bus_containers_handle_get_connection_instance (DBusConnection *caller, goto oom; if (!dbus_message_append_args (reply, - DBUS_TYPE_OBJECT_PATH, &instance->path, + DBUS_TYPE_OBJECT_PATH, &server->path, DBUS_TYPE_INVALID)) goto oom; @@ -1205,7 +1357,7 @@ bus_containers_handle_get_connection_instance (DBusConnection *caller, &arr_writer)) goto oom; - if (!bus_driver_fill_connection_credentials (NULL, instance->creator, + if (!bus_driver_fill_connection_credentials (NULL, server->creator, caller, &arr_writer)) { @@ -1217,14 +1369,15 @@ bus_containers_handle_get_connection_instance (DBusConnection *caller, goto oom; if (!dbus_message_append_args (reply, - DBUS_TYPE_STRING, &instance->type, - DBUS_TYPE_STRING, &instance->name, + DBUS_TYPE_STRING, &server->type, + DBUS_TYPE_STRING, &server->app_id, + DBUS_TYPE_STRING, &server->instance_id, DBUS_TYPE_INVALID)) goto oom; dbus_message_iter_init_append (reply, &writer); - if (!_dbus_variant_write (instance->metadata, &writer)) + if (!_dbus_variant_write (server->metadata, &writer)) goto oom; if (!bus_transaction_send_from_driver (transaction, caller, reply)) @@ -1244,14 +1397,14 @@ failed: } dbus_bool_t -bus_containers_handle_get_instance_info (DBusConnection *connection, - BusTransaction *transaction, - DBusMessage *message, - DBusError *error) +bus_containers_handle_get_server_info (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) { BusContext *context; BusContainers *containers; - BusContainerInstance *instance = NULL; + BusContainerServer *server = NULL; DBusMessage *reply = NULL; DBusMessageIter writer; DBusMessageIter arr_writer; @@ -1265,13 +1418,13 @@ bus_containers_handle_get_instance_info (DBusConnection *connection, context = bus_transaction_get_context (transaction); containers = bus_context_get_containers (context); - if (containers->instances_by_path != NULL) + if (containers->servers_by_path != NULL) { - instance = _dbus_hash_table_lookup_string (containers->instances_by_path, - path); + server = _dbus_hash_table_lookup_string (containers->servers_by_path, + path); } - if (instance == NULL) + if (server == NULL) { dbus_set_error (error, DBUS_ERROR_NOT_CONTAINER, "There is no container with path '%s'", path); @@ -1289,7 +1442,7 @@ bus_containers_handle_get_instance_info (DBusConnection *connection, &arr_writer)) goto oom; - if (!bus_driver_fill_connection_credentials (NULL, instance->creator, + if (!bus_driver_fill_connection_credentials (NULL, server->creator, connection, &arr_writer)) { @@ -1301,14 +1454,15 @@ bus_containers_handle_get_instance_info (DBusConnection *connection, goto oom; if (!dbus_message_append_args (reply, - DBUS_TYPE_STRING, &instance->type, - DBUS_TYPE_STRING, &instance->name, + DBUS_TYPE_STRING, &server->type, + DBUS_TYPE_STRING, &server->app_id, + DBUS_TYPE_STRING, &server->instance_id, DBUS_TYPE_INVALID)) goto oom; dbus_message_iter_init_append (reply, &writer); - if (!_dbus_variant_write (instance->metadata, &writer)) + if (!_dbus_variant_write (server->metadata, &writer)) goto oom; if (!bus_transaction_send_from_driver (transaction, connection, reply)) @@ -1348,7 +1502,7 @@ bus_containers_handle_request_header (DBusConnection *caller, } bus_connection_request_headers (caller, - BUS_EXTRA_HEADERS_CONTAINER_INSTANCE); + BUS_EXTRA_HEADERS_CONTAINER_PATH); ret = TRUE; out: @@ -1359,17 +1513,17 @@ out: void bus_containers_stop_listening (BusContainers *self) { - if (self->instances_by_path != NULL) + if (self->servers_by_path != NULL) { DBusHashIter iter; - _dbus_hash_iter_init (self->instances_by_path, &iter); + _dbus_hash_iter_init (self->servers_by_path, &iter); while (_dbus_hash_iter_next (&iter)) { - BusContainerInstance *instance = _dbus_hash_iter_get_value (&iter); + BusContainerServer *server = _dbus_hash_iter_get_value (&iter); - bus_container_instance_stop_listening (instance); + bus_container_server_stop_listening (server); } } } @@ -1412,7 +1566,7 @@ bus_containers_remove_connection (BusContainers *self, { #ifdef DBUS_ENABLE_CONTAINERS BusContainerCreatorData *creator_data; - BusContainerInstance *instance; + BusContainerServer *server; dbus_connection_ref (connection); creator_data = dbus_connection_get_data (connection, @@ -1423,28 +1577,43 @@ bus_containers_remove_connection (BusContainers *self, DBusList *iter; DBusList *next; - for (iter = _dbus_list_get_first_link (&creator_data->instances); + _dbus_verbose ("Closing connection %s (%s) which has owned at least " + "one server", + bus_connection_get_name (connection), + bus_connection_get_loginfo (connection)); + + for (iter = _dbus_list_get_first_link (&creator_data->servers); iter != NULL; iter = next) { - instance = iter->data; + server = 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); + * iter and server */ + next = _dbus_list_get_next_link (&creator_data->servers, iter); - _dbus_assert (instance->creator == connection); + _dbus_assert (server->creator == connection); - /* This will invalidate iter and instance if there are no open - * connections to this instance */ - bus_container_instance_stop_listening (instance); + if (server->stop_on_disconnect) + { + _dbus_verbose ("Stopping %s", server->path); + /* This will invalidate iter and server if there are no open + * connections to this server */ + bus_container_server_stop_listening (server); + } + else + { + _dbus_verbose ("Not stopping %s because it was created with " + "StopOnDisconnect=FALSE", + server->path); + } } } - instance = connection_get_instance (connection); + server = connection_get_server (connection); - if (instance != NULL) - bus_container_instance_lost_connection (instance, connection); + if (server != NULL) + bus_container_server_lost_connection (server, connection); dbus_connection_unref (connection); #endif /* DBUS_ENABLE_CONTAINERS */ @@ -1454,23 +1623,27 @@ dbus_bool_t bus_containers_connection_is_contained (DBusConnection *connection, const char **path, const char **type, - const char **name) + const char **app_id, + const char **instance_id) { #ifdef DBUS_ENABLE_CONTAINERS - BusContainerInstance *instance; + BusContainerServer *server; - instance = connection_get_instance (connection); + server = connection_get_server (connection); - if (instance != NULL) + if (server != NULL) { if (path != NULL) - *path = instance->path; + *path = server->path; if (type != NULL) - *type = instance->type; + *type = server->type; - if (name != NULL) - *name = instance->name; + if (app_id != NULL) + *app_id = server->app_id; + + if (instance_id != NULL) + *instance_id = server->instance_id; return TRUE; } diff --git a/bus/containers.h b/bus/containers.h index 842a43f4..4e3af6a7 100644 --- a/bus/containers.h +++ b/bus/containers.h @@ -38,7 +38,7 @@ dbus_bool_t bus_containers_handle_add_server (DBusConnection *connecti BusTransaction *transaction, DBusMessage *message, DBusError *error); -dbus_bool_t bus_containers_handle_stop_instance (DBusConnection *connection, +dbus_bool_t bus_containers_handle_stop_server (DBusConnection *connection, BusTransaction *transaction, DBusMessage *message, DBusError *error); @@ -46,14 +46,14 @@ dbus_bool_t bus_containers_handle_stop_listening (DBusConnection *connecti BusTransaction *transaction, DBusMessage *message, DBusError *error); -dbus_bool_t bus_containers_handle_get_instance_info (DBusConnection *connection, +dbus_bool_t bus_containers_handle_get_server_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_get_connection_info (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error); dbus_bool_t bus_containers_handle_request_header (DBusConnection *connection, BusTransaction *transaction, DBusMessage *message, @@ -66,7 +66,8 @@ void bus_containers_remove_connection (BusContainers *self, dbus_bool_t bus_containers_connection_is_contained (DBusConnection *connection, const char **path, const char **type, - const char **name); + const char **app_id, + const char **instance_id); static inline void bus_clear_containers (BusContainers **containers_p) diff --git a/bus/dispatch.c b/bus/dispatch.c index 9bfdf795..b61d9917 100644 --- a/bus/dispatch.c +++ b/bus/dispatch.c @@ -293,7 +293,7 @@ bus_dispatch (DBusConnection *connection, * don't understand (or validate), so that we can add header fields * in future and clients can assume that we have checked them. */ if (!_dbus_message_remove_unknown_fields (message) || - !dbus_message_set_container_instance (message, NULL)) + !dbus_message_set_container_path (message, NULL)) { BUS_SET_OOM (&error); goto out; diff --git a/bus/driver.c b/bus/driver.c index ebd98015..f0063247 100644 --- a/bus/driver.c +++ b/bus/driver.c @@ -118,7 +118,7 @@ bus_driver_check_caller_is_not_container (DBusConnection *connection, DBusMessage *message, DBusError *error) { - if (bus_containers_connection_is_contained (connection, NULL, NULL, NULL)) + if (bus_containers_connection_is_contained (connection, NULL, NULL, NULL, NULL)) { const char *method = dbus_message_get_member (message); @@ -1970,9 +1970,7 @@ 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,17 +2031,15 @@ 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)) + bus_containers_connection_is_contained (peer_conn, &path, NULL, NULL, NULL)) { if (!_dbus_asv_add_object_path (asv_iter, - DBUS_INTERFACE_CONTAINERS1 ".Instance", + DBUS_INTERFACE_CONTAINERS1 ".Path", path)) return FALSE; } -#endif #ifdef HAVE_UNIX_FD_PASSING if (caller_conn != NULL && pid_fd >= 0 && @@ -2500,7 +2496,7 @@ 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. */ METHOD_FLAG_NO_CONTAINERS = (1 << 2), METHOD_FLAG_NONE = 0 @@ -2651,16 +2647,16 @@ static const MessageHandler introspectable_message_handlers[] = { #ifdef DBUS_ENABLE_CONTAINERS static const MessageHandler containers_message_handlers[] = { - { "AddServer", "ssa{sv}a{sv}", "oays", bus_containers_handle_add_server, + { "AddServer", "sssa{sv}a{sv}", "oa{sv}", bus_containers_handle_add_server, METHOD_FLAG_NO_CONTAINERS }, - { "StopInstance", "o", "", bus_containers_handle_stop_instance, + { "StopServer", "o", "", bus_containers_handle_stop_server, 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, + { "GetConnectionInfo", "s", "oa{sv}sssa{sv}", + bus_containers_handle_get_connection_info, METHOD_FLAG_NONE }, - { "GetInstanceInfo", "o", "a{sv}ssa{sv}", bus_containers_handle_get_instance_info, + { "GetServerInfo", "o", "a{sv}sssa{sv}", bus_containers_handle_get_server_info, METHOD_FLAG_NONE }, { "RequestHeader", "", "", bus_containers_handle_request_header, METHOD_FLAG_NONE }, @@ -2780,7 +2776,7 @@ static InterfaceHandler interface_handlers[] = { #endif #ifdef DBUS_ENABLE_CONTAINERS { DBUS_INTERFACE_CONTAINERS1, containers_message_handlers, - " \n" + " \n" " \n" " \n", INTERFACE_FLAG_NONE, containers_property_handlers }, diff --git a/bus/session.conf.in b/bus/session.conf.in index affa7f1d..ace073c9 100644 --- a/bus/session.conf.in +++ b/bus/session.conf.in @@ -76,5 +76,11 @@ 50000 50000 50000 + 10000 + 10000 + 1000000000 + + 16 diff --git a/bus/system.conf.in b/bus/system.conf.in index dea09bd5..b8d3172a 100644 --- a/bus/system.conf.in +++ b/bus/system.conf.in @@ -126,6 +126,10 @@ + + + + diff --git a/cmake/config.h.cmake b/cmake/config.h.cmake index eaa3ee85..f914c286 100644 --- a/cmake/config.h.cmake +++ b/cmake/config.h.cmake @@ -40,6 +40,7 @@ #cmakedefine DBUS_RUNSTATEDIR "@DBUS_RUNSTATEDIR@" #cmakedefine DBUS_ENABLE_STATS +#cmakedefine DBUS_ENABLE_CONTAINERS #cmakedefine ENABLE_TRADITIONAL_ACTIVATION #define TEST_LISTEN "@TEST_LISTEN@" diff --git a/dbus/dbus-marshal-header.c b/dbus/dbus-marshal-header.c index 30636d79..c4824318 100644 --- a/dbus/dbus-marshal-header.c +++ b/dbus/dbus-marshal-header.c @@ -86,7 +86,7 @@ _dbus_header_field_types[DBUS_HEADER_FIELD_LAST+1] = { { DBUS_HEADER_FIELD_SENDER, DBUS_TYPE_STRING }, { DBUS_HEADER_FIELD_SIGNATURE, DBUS_TYPE_SIGNATURE }, { DBUS_HEADER_FIELD_UNIX_FDS, DBUS_TYPE_UINT32 }, - { DBUS_HEADER_FIELD_CONTAINER_INSTANCE, DBUS_TYPE_OBJECT_PATH } + { DBUS_HEADER_FIELD_CONTAINER_PATH, DBUS_TYPE_OBJECT_PATH } }; /** Macro to look up the correct type for a field */ @@ -922,7 +922,7 @@ load_and_validate_field (DBusHeader *header, string_validation_func = NULL; break; - case DBUS_HEADER_FIELD_CONTAINER_INSTANCE: + case DBUS_HEADER_FIELD_CONTAINER_PATH: /* OBJECT_PATH was validated generically due to its type */ string_validation_func = NULL; break; diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index b47a8638..edca49fa 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -4097,7 +4097,7 @@ dbus_message_contains_unix_fds(DBusMessage *message) } /** - * Sets the container instance this message was sent from. + * Sets the container context this message was sent from. * * The path must contain only valid characters for an object path * as defined in the D-Bus specification. @@ -4107,8 +4107,8 @@ dbus_message_contains_unix_fds(DBusMessage *message) * @returns #FALSE if not enough memory */ dbus_bool_t -dbus_message_set_container_instance (DBusMessage *message, - const char *object_path) +dbus_message_set_container_path (DBusMessage *message, + const char *object_path) { _dbus_return_val_if_fail (message != NULL, FALSE); _dbus_return_val_if_fail (!message->locked, FALSE); @@ -4117,13 +4117,27 @@ dbus_message_set_container_instance (DBusMessage *message, FALSE); return set_or_delete_string_field (message, - DBUS_HEADER_FIELD_CONTAINER_INSTANCE, + DBUS_HEADER_FIELD_CONTAINER_PATH, DBUS_TYPE_OBJECT_PATH, object_path); } /** - * Gets the container instance this message was sent from, or #NULL + * Deprecated alias for dbus_message_set_container_path(). + * + * @param message the message + * @param object_path the path or #NULL to unset + * @returns #FALSE if not enough memory + */ +dbus_bool_t +dbus_message_set_container_instance (DBusMessage *message, + const char *object_path) +{ + return dbus_message_set_container_path (message, object_path); +} + +/** + * Gets the container context this message was sent from, or #NULL * if none. * * The returned string becomes invalid if the message is @@ -4133,7 +4147,7 @@ dbus_message_set_container_instance (DBusMessage *message, * @returns the path (should not be freed) or #NULL */ const char * -dbus_message_get_container_instance (DBusMessage *message) +dbus_message_get_container_path (DBusMessage *message) { const char *v; @@ -4141,12 +4155,24 @@ dbus_message_get_container_instance (DBusMessage *message) v = NULL; /* in case field doesn't exist */ _dbus_header_get_field_basic (&message->header, - DBUS_HEADER_FIELD_CONTAINER_INSTANCE, + DBUS_HEADER_FIELD_CONTAINER_PATH, DBUS_TYPE_OBJECT_PATH, (void *) &v); return v; } +/** + * Deprecated alias for dbus_message_set_container_instance(). + * + * @param message the message + * @returns the path (should not be freed) or #NULL + */ +const char * +dbus_message_get_container_instance (DBusMessage *message) +{ + return dbus_message_get_container_path (message); +} + /** @} */ /** diff --git a/dbus/dbus-message.h b/dbus/dbus-message.h index 0bbad3d1..3b9e2ded 100644 --- a/dbus/dbus-message.h +++ b/dbus/dbus-message.h @@ -236,10 +236,17 @@ dbus_bool_t dbus_message_get_path_decomposed (DBusMessage *message, char ***path); DBUS_EXPORT -const char *dbus_message_get_container_instance (DBusMessage *message); +const char *dbus_message_get_container_path (DBusMessage *message); DBUS_EXPORT +dbus_bool_t dbus_message_set_container_path (DBusMessage *message, + const char *object_path); +#ifndef DBUS_DISABLE_DEPRECATED +DBUS_EXPORT DBUS_DEPRECATED +const char *dbus_message_get_container_instance (DBusMessage *message); +DBUS_EXPORT DBUS_DEPRECATED dbus_bool_t dbus_message_set_container_instance (DBusMessage *message, const char *object_path); +#endif DBUS_EXPORT dbus_bool_t dbus_message_append_args (DBusMessage *message, diff --git a/dbus/dbus-protocol.h b/dbus/dbus-protocol.h index 33e39df3..8bcd289a 100644 --- a/dbus/dbus-protocol.h +++ b/dbus/dbus-protocol.h @@ -303,9 +303,15 @@ extern "C" { */ #define DBUS_HEADER_FIELD_UNIX_FDS 9 /** - * Header field code for the container instance that sent this message. + * Header field code for the container context that sent this message. */ +#define DBUS_HEADER_FIELD_CONTAINER_PATH 10 +/** + * Deprecated alias for #DBUS_HEADER_FIELD_CONTAINER_PATH + */ +#ifndef DBUS_DISABLE_DEPRECATED #define DBUS_HEADER_FIELD_CONTAINER_INSTANCE 10 +#endif /** @@ -314,7 +320,7 @@ extern "C" { * that unknown codes must be ignored, so check for that before * indexing the array. */ -#define DBUS_HEADER_FIELD_LAST DBUS_HEADER_FIELD_CONTAINER_INSTANCE +#define DBUS_HEADER_FIELD_LAST DBUS_HEADER_FIELD_CONTAINER_PATH /** Header format is defined as a signature: * byte byte order diff --git a/dbus/dbus-shared.h b/dbus/dbus-shared.h index 87c0bd84..59b33e94 100644 --- a/dbus/dbus-shared.h +++ b/dbus/dbus-shared.h @@ -88,6 +88,8 @@ typedef enum */ /** The interface exported by the object with #DBUS_SERVICE_DBUS and #DBUS_PATH_DBUS */ #define DBUS_INTERFACE_DBUS "org.freedesktop.DBus" +/** The restricted container interface exported by the dbus-daemon */ +#define DBUS_INTERFACE_CONTAINERS1 "org.freedesktop.DBus.Containers1" /** The monitoring interface exported by the dbus-daemon */ #define DBUS_INTERFACE_MONITORING "org.freedesktop.DBus.Monitoring" diff --git a/dbus/dbus-spawn-unix.c b/dbus/dbus-spawn-unix.c index af90962d..742215ec 100644 --- a/dbus/dbus-spawn-unix.c +++ b/dbus/dbus-spawn-unix.c @@ -922,48 +922,6 @@ close_and_invalidate (int *fd) return ret; } -static dbus_bool_t -make_pipe (int p[2], - DBusError *error) -{ - int retval; - -#ifdef HAVE_PIPE2 - dbus_bool_t cloexec_done; - - retval = pipe2 (p, O_CLOEXEC); - cloexec_done = retval >= 0; - - /* Check if kernel seems to be too old to know pipe2(). We assume - that if pipe2 is available, O_CLOEXEC is too. */ - if (retval < 0 && errno == ENOSYS) -#endif - { - retval = pipe(p); - } - - _DBUS_ASSERT_ERROR_IS_CLEAR (error); - - if (retval < 0) - { - dbus_set_error (error, - DBUS_ERROR_SPAWN_FAILED, - "Failed to create pipe for communicating with child process (%s)", - _dbus_strerror (errno)); - return FALSE; - } - -#ifdef HAVE_PIPE2 - if (!cloexec_done) -#endif - { - _dbus_fd_set_close_on_exec (p[0]); - _dbus_fd_set_close_on_exec (p[1]); - } - - return TRUE; -} - static void do_write (int fd, const void *buf, size_t count) { @@ -1323,7 +1281,7 @@ _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p, goto cleanup_and_fail; } - if (!make_pipe (child_err_report_pipe, error)) + if (!_dbus_unix_make_pipe (child_err_report_pipe, error)) goto cleanup_and_fail; if (!_dbus_socketpair (&babysitter_pipe[0], &babysitter_pipe[1], TRUE, error)) diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c index 40b2af3b..5bab8238 100644 --- a/dbus/dbus-sysdeps-unix.c +++ b/dbus/dbus-sysdeps-unix.c @@ -5290,4 +5290,46 @@ _dbus_get_low_level_socket_errno (void) return errno; } +dbus_bool_t +_dbus_unix_make_pipe (int p[2], + DBusError *error) +{ + int retval; + +#ifdef HAVE_PIPE2 + dbus_bool_t cloexec_done; + + retval = pipe2 (p, O_CLOEXEC); + cloexec_done = retval >= 0; + + /* Check if kernel seems to be too old to know pipe2(). We assume + that if pipe2 is available, O_CLOEXEC is too. */ + if (retval < 0 && errno == ENOSYS) +#endif + { + retval = pipe(p); + } + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (retval < 0) + { + dbus_set_error (error, + _dbus_error_from_errno (errno), + "Failed to create pipe (%s)", + _dbus_strerror (errno)); + return FALSE; + } + +#ifdef HAVE_PIPE2 + if (!cloexec_done) +#endif + { + _dbus_fd_set_close_on_exec (p[0]); + _dbus_fd_set_close_on_exec (p[1]); + } + + return TRUE; +} + /* tests in dbus-sysdeps-util.c */ diff --git a/dbus/dbus-sysdeps-unix.h b/dbus/dbus-sysdeps-unix.h index b400cf86..8c4addcc 100644 --- a/dbus/dbus-sysdeps-unix.h +++ b/dbus/dbus-sysdeps-unix.h @@ -162,6 +162,10 @@ void _dbus_set_signal_handler (int sig, dbus_bool_t _dbus_reset_oom_score_adj (const char **error_str_p); +DBUS_PRIVATE_EXPORT +dbus_bool_t _dbus_unix_make_pipe (int p[2], + DBusError *error); + /** @} */ DBUS_END_DECLS diff --git a/doc/dbus-daemon.1.xml.in b/doc/dbus-daemon.1.xml.in index 5bf93b93..987f9bc0 100644 --- a/doc/dbus-daemon.1.xml.in +++ b/doc/dbus-daemon.1.xml.in @@ -856,6 +856,14 @@ Available limit names are: (number of calls-in-progress) "reply_timeout" : milliseconds (thousandths) until a method call times out + "max_containers" : max number of restricted servers for use + in app-containers, in total + "max_containers_per_user" : max number of app-containers per Unix uid + "max_container_metadata_bytes": max number of bytes of metadata to store + for each app-container + "max_connections_per_container": max number of (authenticated or + unauthenticated) connections to each + app-container diff --git a/doc/dbus-specification.xml b/doc/dbus-specification.xml index 01bf7dff..7185bfa0 100644 --- a/doc/dbus-specification.xml +++ b/doc/dbus-specification.xml @@ -7044,6 +7044,19 @@ + + org.freedesktop.DBus.Containers1.Path + OBJECT_PATH + + The object path of the container-specific server through + which this connection is connected, as returned by the + AddServer method. Omitted from the + dictionary if this connection is not via a container's + server. + + + @@ -7452,6 +7465,764 @@ + + Containers Interface v1: <literal>org.freedesktop.DBus.Containers1</literal> + + The special message bus name org.freedesktop.DBus + may optionally implement the + org.freedesktop.DBus.Containers1 interface on + the object path /org/freedesktop/DBus. + + + + This interface allows container managers and similar sandboxing + mechanisms to ask the message bus to create a special socket + for each sandboxed application, + which uniquely identifies the application to other message bus + clients without introducing race conditions. + For this mechanism to be useful, the sandboxed application must be + prevented from connecting to the message bus's usual socket. + This interface is a D-Bus equivalent of the + Wayland security-context extension. + + + + As currently implemented, this interface does not apply any + special filtering to the D-Bus messages sent and received by a + sandboxed application. + To limit what a sandboxed application can do on D-Bus, it is + likely to be necessary to impose restrictions, + perhaps by using a Linux security module such as AppArmor or a + filtering proxy such as + xdg-dbus-proxy. + A future version of this specification might add a mechanism for + the creator of a confined socket to specify filtering rules. + + + + Method: <literal>org.freedesktop.DBus.Containers1.AddServer</literal> + + As a method: + + AddServer (in STRING container_type, + in STRING app_id, + in STRING instance_id, + in DICT<STRING,VARIANT> metadata, + in DICT<STRING,VARIANT> named_arguments, + out OBJECT_PATH server_path, + out DICT<STRING,VARIANT> results) + + Message arguments: + + + + + Argument + Type + Description + + + + + 0 + STRING + + Reversed domain name identifying a container manager + or container technology, such as + org.flatpak or + io.snapcraft. It must follow the + same syntactic rules as a + D-Bus + interface name. + Container managers should use the same identifier here + that they use for the + set_sandbox_engine request in the + Wayland security-context extension. + + + + 1 + STRING + + Some unique identifier for an application or + container, whose meaning is defined by the + maintainers of the container type. If the container + type does not have a concept of identifying or + naming its applications or containers by a string, + using the empty string here is suggested. + Container managers should use the same identifier here + that they use for the + set_app_id request in the + Wayland security-context extension. + + + + 2 + STRING + + Some unique identifier for a particular instance of an + application or container, whose meaning is defined by the + maintainers of the container type. If the container + type does not have a concept of identifying or + naming instances by a string, + using the empty string here is suggested. + Container managers should use the same identifier here + that they use for the + set_instance_id request in the + Wayland security-context extension. + + + + 3 + DICT<STRING,VARIANT> + + Metadata describing the application or container. + All keys and values are reserved for future standardization, + either in this specification or in a separate + freedesktop.org specification referenced by this one. + + + + 4 + DICT<STRING,VARIANT> + + Additional arguments that extend this method. + The only named arguments that are allowed are the ones + listed in the + org.freedesktop.DBus.Containers1.SupportedArguments + property. All other named arguments are an error. + + + + 5 + OBJECT_PATH + + An opaque object path identifying the new container + context. + + + + 6 + DICT<STRING,VARIANT> + + Details of the container-specific server that was + created (see below). + + + + + + + + + Set up a new server socket for use in an application container. + Clients can connect to that socket, and the result will be as + though they had connected to the message bus, with a few differences. + The intention is that a container manager will call this method + to get a new server socket, bind-mount the server socket + into a location that is accessible by the confined (sandboxed) + application, and ensure that the normal message bus socket is + not accessible by the confined application. + + + + Each call to this method creates a new + container server, identified by an object + path. Even if the specified container type, app ID and instance ID + are the same as for a pre-existing container server, each call + creates a new server with a new unique object path, because + the new container server might represent a different + version of the confined application with different + characteristics and restrictions (although in practice it is + expected that container managers are most likely to create one + server per instance ID). The message bus may provide + an object at the given object path, but is not required to + do so. + + + + Metadata from the first three arguments is stored by the message + bus, but not interpreted; software that interacts with the + container manager can use this metadata. + The method call may fail with the error + org.freedesktop.DBus.Error.LimitsExceeded + if the caller provides more metadata than the message bus + is willing to store. + + + + The last argument (the named arguments) + can be used to modify + the behaviour of this method call; all keys in this dictionary not + containing . are reserved by this specification + for this purpose. It can also contain implementation-specific + arguments for a particular message bus implementation, which + should start with a reversed domain name in the same way as + interface names. For example, GLib's gdbus-daemon might use + org.gtk.GDBus.SomeArgument if it used this + extension point. + + + + The only named arguments that are allowed are the ones + listed in the + org.freedesktop.DBus.Containers1.SupportedArguments + property. All other named arguments are an error. + The possible keys currently defined for the named arguments are: + + + + + Key + Value type + Default value + Meaning + + + + + StopOnDisconnect + BOOLEAN + true + + If true or omitted, the server socket will cease to + listen for new connections (in the same way as if + StopListening had been called + successfully) when the caller of this method + disconnects from the bus. Any confined connections + that are already active are unaffected. + If false, the server socket continues to listen after + the caller disconnects, until there is some other reason + for it to stop. + + + + StopOnNotify + UNIX_FD + (none) + + A file descriptor which will become readable (either + data available or end-of-file) when it is time to stop + listening for new connections. In practice, this is + expected to be the read end of a Unix pipe, for which + the corresponding write end will be closed (either + explicitly or when its owning process exits) when the + container manager detects that the application has + stopped running. This will often be combined with + { "StopOnDisconnect": false }. + + + + + + + + + Keys in the returned result dictionary not containing "." are defined + by this specification. Bus daemon implementors wishing to emit + information not mentioned in this document should use keys + containing "." and starting with a reversed domain name. + Additional keys may be added to the result at any time, and + callers must accept and ignore unknown keys in this dictionary. + + + + The defined keys for the result dictionary are: + + + + + Key + Value type + Value + + + + + Address + STRING + + A connectable D-Bus address, for example + unix:path=/run/user/1000/dbus-12345vwxyz. + + + + SocketPath + ARRAY of BYTE + + The absolute filesystem path of the resulting + AF_UNIX socket, followed by a single + zero (nul) byte, for example + /run/user/1000/dbus-12345vwxyz\x00 + where \x00 represents the terminating zero byte. + + + + + + + + + In the most basic form of a call to this method, the new server + socket is an AF_UNIX socket at a path chosen + by the message bus and returned from the method. + When operating in this way, each successful call will return a + result dictionary containing both Address and + SocketPath. + Callers may use whichever of those members is more convenient. + If a future version of this specification adds a mechanism to + request that the server listens in some way that makes these two + members inapplicable, for example receiving a socket from the + caller in the named arguments dictionary via file descriptor passing + and arranging for it to listen for connections, then those members + will be omitted from the result dictionary. + + + + Connections to the new server socket are said to be + confined. The message bus may prevent + confined connections from calling certain security-sensitive methods, + and may apply lower limits to these connections. However, container + managers and services must not rely on confined connections having + any particular filtering applied to them by the message bus. + + + + The container server object path remains valid for as + long as one or more confined connection via the same server + socket remain open, or there is a way for the server socket + to produce new connections in future (in other words, + either it is preparing to listen for new connections, or + it is currently listening for new connections). When the + container server has ceased to listen for new connections + and no longer has any confined connections, the object path + becomes invalid, and API calls that specify it will fail with + the org.freedesktop.DBus.Error.NotContainer + error. + + + + + Method: <literal>org.freedesktop.DBus.Containers1.StopServer</literal> + + As a method: + + StopServer (in OBJECT_PATH server_path) + + Message arguments: + + + + + Argument + Type + Description + + + + + 0 + OBJECT_PATH + + The opaque object path that was returned from the + AddServer method, identifying a + per-container server. + + + + + + + + + Terminate the container server. The server will stop + listening for new connections, and any existing connections to + that server will be disconnected. When all connections have + been disconnected, the context will cease to exist. + + + If the given object path does not represent a valid container + context (see + ), the + org.freedesktop.DBus.Error.NotContainer + error is returned. In particular, if this method is called + twice, the second call will fail in this way. + + + If the given container server exists but the caller of this + method is not allowed to stop it (for example because the + caller is in a container server or because its user ID does + not match the user ID of the creator of the container + context), + the org.freedesktop.DBus.Error.AccessDenied + error is returned and nothing is stopped. + + + + + Method: <literal>org.freedesktop.DBus.Containers1.StopListening</literal> + + As a method: + + StopListening (in OBJECT_PATH server_path) + + Message arguments: + + + + + Argument + Type + Description + + + + + 0 + OBJECT_PATH + + The opaque object path that was returned from the + AddServer method, identifying a + container server. + + + + + + + + + Stop listening for new connections to the given per-container + server, but do not disconnect any existing connections. + + + If this method is called more than once, while the container + context still exists because connections to it are still + open, the second and subsequent calls will be successful but + will have no practical effect. + + + If the given object path does not represent a valid container + context (see + ), the + org.freedesktop.DBus.Error.NotContainer + error is returned. In particular, this will happen if the + per-container server already stopped listening, and all + connections to it (if any) were already closed. + + + If the given per-container server exists but the caller of this + method is not allowed to stop it (for example because the + caller is itself in a container, or because its user ID does + not match the user ID of the creator of the container server), + the org.freedesktop.DBus.Error.AccessDenied + error is returned and nothing is stopped. + + + + + Method: <literal>org.freedesktop.DBus.Containers1.GetConnectionInfo</literal> + + As a method: + + GetConnectionInfo (in STRING bus_name, + out OBJECT_PATH server_path, + out DICT<STRING,VARIANT> creator, + out STRING container_type, + out STRING app_id, + out STRING instance_id, + out DICT<STRING,VARIANT> metadata) + + Message arguments: + + + + + Argument + Type + Description + + + + + 0 + STRING + + Unique or well-known bus name of the connection to + query, such as :12.34 or + com.example.tea. + + + + 1 + OBJECT_PATH + + The opaque object path that was returned from the + AddServer method, identifying a + per-container server. + This output parameter is produced by the message bus. + + + + 2 + DICT<STRING,VARIANT> + + Credentials of the connection that created this + per-container server. + The keys and values are the same as those that are + documented for + GetConnectionCredentials. + This output parameter is produced by the message bus + and is appropriate to use in trust decisions. + + + + 3 + STRING + + Reversed domain name identifying a container + manager or container technology, as passed to the + AddServer method, such as + org.flatpak or + io.snapcraft. + This output parameter is controlled by the creator + of the per-container server. + + + + 4 + STRING + + A unique identifier for an application or container, + whose meaning is defined by the maintainers of the + container type. + For example, Flatpak would use a freedesktop.org app ID + such as org.mozilla.firefox, but + Snap might use a Snap app ID such as + firefox. + This output parameter is controlled by the creator + of the per-container server. + Depending on the container type, it might be possible + to look up further metadata for the application in a + container-type-specific way. + + + + 5 + STRING + + A unique identifier for a particular instance of an + application or container, whose meaning is defined by + the maintainers of the container type. + For example, Flatpak would use the same numeric + instance ID that is shown by flatpak ps. + This output parameter is controlled by the creator + of the per-container server. + Depending on the container type, it might be possible + to look up further metadata for the instance in a + container-type-specific way, for example by reading + $XDG_RUNTIME_DIR/.flatpak/$INSTANCE/info + for a Flatpak app. + + + + 6 + DICT<STRING,VARIANT> + + Metadata describing the application or container. + All keys and values are reserved for future standardization, + either in this specification or in a separate + freedesktop.org specification referenced by this one. + This output parameter is controlled by the creator + of the per-container server. + + + + + + + + + If the given unique or well-known bus name is a connection to a + container server, return information about that per-container server. + If the bus name exists but is not confined (in other words, if it + is a direct connection to the main message bus socket), the + org.freedesktop.DBus.Error.NotContainer error + is returned instead. If the given bus name has no owner at all, the + org.freedesktop.DBus.Error.NameHasNoOwner error + is returned instead. + + + Several of the output parameters are controlled by the creator of + the per-container server. + On a bus that accepts connections from multiple clients at + different privilege levels, it is not appropriate to trust those + output parameters or use them in trust decisions unless the + process identified by the creator parameter + is trusted. + + + + + Method: <literal>org.freedesktop.DBus.Containers1.GetServerInfo</literal> + + As a method: + + GetServerInfo (in OBJECT_PATH server_path, + out DICT<STRING,VARIANT> creator, + out STRING container_type, + out STRING app_id, + out STRING instance_id, + out DICT<STRING,VARIANT> metadata) + + Message arguments: + + + + + Argument + Type + Description + + + + + 0 + OBJECT_PATH + + The opaque object path that was returned from the + AddServer method, identifying a + per-container server. + + + + 1 + DICT<STRING,VARIANT> + + Credentials of the connection that created this + per-container server. + The keys and values are the same as those that are + documented for + GetConnectionCredentials. + This output parameter is produced by the message bus + and is appropriate to use in trust decisions. + + + + 2 + STRING + + Reversed domain name identifying a container + manager or container technology, + the same as the corresponding parameter in + GetConnectionInfo. + This output parameter is controlled by the creator + of the per-container server. + + + + 3 + STRING + + Some unique identifier for an application or container, + the same as the corresponding parameter in + GetConnectionInfo. + This output parameter is controlled by the creator + of the per-container server. + + + + 4 + STRING + + Some unique identifier for a particular instance of an + application or container, + the same as the corresponding parameter in + GetConnectionInfo. + This output parameter is controlled by the creator + of the per-container server. + + + + 5 + DICT<STRING,VARIANT> + + Metadata describing the application or container, + the same as the corresponding parameter in + GetConnectionInfo. + This output parameter is controlled by the creator + of the per-container server. + + + + + + + + + If the given object path represents a valid per-container server + (see ), + return information about it. Otherwise, the + org.freedesktop.DBus.Error.NotContainer error + is returned. + + + Several of the output parameters are controlled by the creator of + the per-container server. + See + for more details. + + + + + Signal: <literal>org.freedesktop.DBus.Containers1.ServerRemoved</literal> + + As a signal emitted by the message bus: + + ServerRemoved (OBJECT_PATH server_path) + + Message arguments: + + + + + Argument + Type + Description + + + + + 0 + OBJECT_PATH + + The opaque object path that was returned from the + AddServer method, identifying a + per-container server. + + + + + + + + + Emitted when a per-container server ceases to exist. A per-container + server continues to exist as long as it is listening for + new connections, or as long as connections to the server + are open, whichever is longer. + + + + + Monitoring Interface: <literal>org.freedesktop.DBus.Monitoring</literal> @@ -7502,7 +8273,12 @@ monitor connections In the reference implementation, - the default configuration is that each user (identified by + the default configuration is that connections to a + container server managed by + the + Containers1 interface + are not privileged and cannot become a monitor; + otherwise, each user (identified by numeric user ID) may monitor their own session bus, and the root user (user ID zero) may monitor the system bus. diff --git a/test/containers.c b/test/containers.c index 79636460..a80db915 100644 --- a/test/containers.c +++ b/test/containers.c @@ -47,8 +47,6 @@ #include "test-utils-glib.h" -#define DBUS_INTERFACE_CONTAINERS1 "org.freedesktop.DBus.Containers1" - typedef struct { TestMainContext *ctx; gboolean skip; @@ -58,7 +56,7 @@ typedef struct { GDBusProxy *proxy; - gchar *instance_path; + gchar *server_path; gchar *socket_path; gchar *socket_dbus_address; GDBusConnection *unconfined_conn; @@ -67,10 +65,11 @@ typedef struct { GDBusConnection *observer_conn; GDBusProxy *observer_proxy; - GHashTable *containers_removed; + GHashTable *servers_removed; guint removed_sub; DBusConnection *libdbus_observer; DBusMessage *latest_shout; + int stop_on_notify_pipe_write_end; } Fixture; typedef struct @@ -82,6 +81,8 @@ typedef struct STOP_SERVER_DISCONNECT_FIRST, STOP_SERVER_NEVER_CONNECTED, STOP_SERVER_FORCE, + STOP_SERVER_VIA_NOTIFY, + STOP_SERVER_VIA_NOTIFY_NOT_MANAGER, STOP_SERVER_WITH_MANAGER } stop_server; @@ -138,13 +139,13 @@ observe_shouting_cb (DBusConnection *observer, } static void -instance_removed_cb (GDBusConnection *observer, - const gchar *sender, - const gchar *path, - const gchar *iface, - const gchar *member, - GVariant *parameters, - gpointer user_data) +server_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; @@ -152,11 +153,11 @@ instance_removed_cb (GDBusConnection *observer, 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 (member, ==, "ServerRemoved"); 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)); + g_assert (!g_hash_table_contains (f->servers_removed, container)); + g_hash_table_add (f->servers_removed, g_strdup (container)); } static void @@ -177,6 +178,33 @@ fixture_disconnect_unconfined (Fixture *f) g_clear_object (&f->unconfined_conn); } +#ifdef DBUS_ENABLE_CONTAINERS +static void +fixture_disconnect_unconfined_and_wait (Fixture *f) +{ + guint name_watch; + gboolean gone = FALSE; + + /* 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); +} +#endif + static void fixture_disconnect_observer (Fixture *f) { @@ -233,15 +261,15 @@ setup (Fixture *f, 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->servers_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", + "ServerRemoved", DBUS_PATH_DBUS, NULL, G_DBUS_SIGNAL_FLAGS_NONE, - instance_removed_cb, + server_removed_cb, f, NULL); /* We have to use libdbus for new header fields, because GDBus doesn't @@ -253,6 +281,8 @@ setup (Fixture *f, if (!dbus_connection_add_filter (f->libdbus_observer, observe_shouting_cb, f, NULL)) g_error ("OOM"); + + f->stop_on_notify_pipe_write_end = -1; } /* @@ -265,6 +295,7 @@ test_get_supported_arguments (Fixture *f, GVariant *v; #ifdef DBUS_ENABLE_CONTAINERS const gchar **args; + gsize i; gsize len; #endif @@ -286,8 +317,11 @@ test_get_supported_arguments (Fixture *f, 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_assert_cmpuint (len, ==, 2); + i = 0; + g_assert_cmpstr (args[i++], ==, "StopOnDisconnect"); + g_assert_cmpstr (args[i++], ==, "StopOnNotify"); + g_assert_cmpstr (args[i++], ==, NULL); g_free (args); g_variant_unref (v); @@ -308,10 +342,15 @@ test_get_supported_arguments (Fixture *f, */ static gboolean add_container_server (Fixture *f, - GVariant *parameters) + GVariant *parameters, + GUnixFDList *fds, + GUnixFDList **fds_out) { GVariant *tuple; + GVariant *named_results; GStatBuf stat_buf; + gboolean found; + gchar *stringified_args; f->proxy = g_dbus_proxy_new_sync (f->unconfined_conn, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, @@ -320,9 +359,33 @@ add_container_server (Fixture *f, 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); + stringified_args = g_variant_print (parameters, TRUE); + g_test_message ("Calling AddServer%s...", stringified_args); + g_free (stringified_args); + + if (fds != NULL || fds_out != NULL) + { + if (fds != NULL) + g_test_message ("Sending %d fds", g_unix_fd_list_get_length (fds)); + + if (fds_out != NULL) + g_test_message ("Expecting to receive fds in result"); + + tuple = g_dbus_proxy_call_with_unix_fd_list_sync (f->proxy, + "AddServer", + parameters, + G_DBUS_CALL_FLAGS_NONE, + -1, + fds, + fds_out, + NULL, + &f->error); + } + else + { + 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 @@ -341,22 +404,34 @@ add_container_server (Fixture *f, 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); + stringified_args = g_variant_print (tuple, TRUE); + g_test_message ("-> %s", stringified_args); + g_free (stringified_args); + + g_assert_cmpstr (g_variant_get_type_string (tuple), ==, "(oa{sv})"); + g_variant_get (tuple, "(o@a{sv})", &f->server_path, &named_results); + g_assert_nonnull (f->server_path); + g_assert_true (g_variant_is_object_path (f->server_path)); + + found = g_variant_lookup (named_results, "Address", + "s", &f->socket_dbus_address); + g_assert_true (found); + g_assert_nonnull (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)); + found = g_variant_lookup (named_results, "SocketPath", + "^ay", &f->socket_path); + g_assert_true (found); 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); + + g_clear_pointer (&named_results, g_variant_unref); + g_clear_pointer (&tuple, g_variant_unref); return TRUE; } #endif @@ -380,7 +455,8 @@ test_basic (Fixture *f, GVariantDict dict; const gchar *confined_unique_name; const gchar *path_from_query; - const gchar *name; + const gchar *app_id; + const gchar *instance_id; const gchar *name_owner; const gchar *type; guint32 uid; @@ -389,16 +465,18 @@ test_basic (Fixture *f, DBusMessage *libdbus_message = NULL; DBusMessage *libdbus_reply = NULL; DBusError libdbus_error = DBUS_ERROR_INIT; + gchar *stringified_result; if (f->skip) return; - parameters = g_variant_new ("(ssa{sv}a{sv})", + parameters = g_variant_new ("(sssa{sv}a{sv})", "com.example.NotFlatpak", "sample-app", + "sample-instance", NULL, /* no metadata */ NULL); /* no named arguments */ - if (!add_container_server (f, g_steal_pointer (¶meters))) + if (!add_container_server (f, g_steal_pointer (¶meters), NULL, NULL)) return; g_test_message ("Connecting to %s...", f->socket_dbus_address); @@ -445,7 +523,7 @@ test_basic (Fixture *f, while (f->latest_shout == NULL) iterate_both_main_loops (f->ctx); - g_assert_cmpstr (dbus_message_get_container_instance (f->latest_shout), ==, + g_assert_cmpstr (dbus_message_get_container_path (f->latest_shout), ==, NULL); dbus_clear_message (&f->latest_shout); @@ -456,7 +534,7 @@ test_basic (Fixture *f, while (f->latest_shout == NULL) iterate_both_main_loops (f->ctx); - g_assert_cmpstr (dbus_message_get_container_instance (f->latest_shout), ==, + g_assert_cmpstr (dbus_message_get_container_path (f->latest_shout), ==, NULL); dbus_clear_message (&f->latest_shout); @@ -484,8 +562,8 @@ test_basic (Fixture *f, 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); + g_assert_cmpstr (dbus_message_get_container_path (f->latest_shout), ==, + f->server_path); dbus_clear_message (&f->latest_shout); g_dbus_connection_emit_signal (f->unconfined_conn, NULL, "/", @@ -495,7 +573,7 @@ test_basic (Fixture *f, while (f->latest_shout == NULL) iterate_both_main_loops (f->ctx); - g_assert_cmpstr (dbus_message_get_container_instance (f->latest_shout), ==, + g_assert_cmpstr (dbus_message_get_container_path (f->latest_shout), ==, "/"); dbus_clear_message (&f->latest_shout); @@ -514,41 +592,50 @@ test_basic (Fixture *f, 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", + tuple = g_dbus_proxy_call_sync (f->proxy, "GetConnectionInfo", 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); + stringified_result = g_variant_print (tuple, TRUE); + g_test_message ("GetConnectionInfo() -> %s", stringified_result); + g_free (stringified_result); + g_assert_cmpstr (g_variant_get_type_string (tuple), ==, "(oa{sv}sssa{sv})"); + g_variant_get (tuple, "(&o@a{sv}&s&s&s@a{sv})", + &path_from_query, &creator, &type, &app_id, &instance_id, &asv); + g_assert_cmpstr (path_from_query, ==, f->server_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"); + g_assert_cmpstr (app_id, ==, "sample-app"); + g_assert_cmpstr (instance_id, ==, "sample-instance"); /* 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_test_message ("Inspecting container server info"); + tuple = g_dbus_proxy_call_sync (f->proxy, "GetServerInfo", + g_variant_new ("(o)", f->server_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); + stringified_result = g_variant_print (tuple, TRUE); + g_test_message ("GetServerInfo() -> %s", stringified_result); + g_free (stringified_result); + g_assert_cmpstr (g_variant_get_type_string (tuple), ==, "(a{sv}sssa{sv})"); + g_variant_get (tuple, "(@a{sv}&s&s&s@a{sv})", + &creator, &type, &app_id, &instance_id, &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"); + g_assert_cmpstr (app_id, ==, "sample-app"); + g_assert_cmpstr (instance_id, ==, "sample-instance"); /* Trivial case: the metadata a{sv} is empty */ g_assert_cmpuint (g_variant_n_children (asv), ==, 0); g_clear_pointer (&asv, g_variant_unref); @@ -584,12 +671,13 @@ test_wrong_uid (Fixture *f, if (f->skip) return; - parameters = g_variant_new ("(ssa{sv}a{sv})", + parameters = g_variant_new ("(sssa{sv}a{sv})", "com.example.NotFlatpak", "sample-app", + "instance1", NULL, /* no metadata */ NULL); /* no named arguments */ - if (!add_container_server (f, g_steal_pointer (¶meters))) + if (!add_container_server (f, g_steal_pointer (¶meters), NULL, NULL)) return; g_test_message ("Connecting to %s...", f->socket_dbus_address); @@ -615,7 +703,8 @@ test_wrong_uid (Fixture *f, /* * 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. + * carried through correctly, and that the app/instance IDs are + * allowed to be empty. */ static void test_metadata (Fixture *f, @@ -629,7 +718,8 @@ test_metadata (Fixture *f, GVariantDict dict; const gchar *confined_unique_name; const gchar *path_from_query; - const gchar *name; + const gchar *app_id; + const gchar *instance_id; const gchar *type; guint32 uid; guint u; @@ -644,13 +734,15 @@ test_metadata (Fixture *f, 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})", + parameters = g_variant_new ("(sss@a{sv}a{sv})", "org.example.Springwatch", - /* Verify that empty app names are OK */ + /* Verify that empty app IDs are OK */ + "", + /* Verify that empty instance IDs are OK */ "", g_variant_dict_end (&dict), NULL); /* no named arguments */ - if (!add_container_server (f, g_steal_pointer (¶meters))) + if (!add_container_server (f, g_steal_pointer (¶meters), NULL, NULL)) return; g_test_message ("Connecting to %s...", f->socket_dbus_address); @@ -677,29 +769,30 @@ test_metadata (Fixture *f, 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", + DBUS_INTERFACE_CONTAINERS1 ".Path", "&o", &path_from_query)); - g_assert_cmpstr (path_from_query, ==, f->instance_path); + g_assert_cmpstr (path_from_query, ==, f->server_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", + tuple = g_dbus_proxy_call_sync (f->proxy, "GetConnectionInfo", 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_assert_cmpstr (g_variant_get_type_string (tuple), ==, "(oa{sv}sssa{sv})"); + g_variant_get (tuple, "(&o@a{sv}&s&s&s@a{sv})", + &path_from_query, &creator, &type, &app_id, &instance_id, &asv); + g_assert_cmpstr (path_from_query, ==, f->server_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_assert_cmpstr (app_id, ==, ""); + g_assert_cmpstr (instance_id, ==, ""); g_variant_dict_init (&dict, asv); g_assert_true (g_variant_dict_lookup (&dict, "NChildren", "u", &u)); g_assert_cmpuint (u, ==, 2); @@ -713,20 +806,22 @@ test_metadata (Fixture *f, 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_test_message ("Inspecting container server info"); + tuple = g_dbus_proxy_call_sync (f->proxy, "GetServerInfo", + g_variant_new ("(o)", f->server_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_assert_cmpstr (g_variant_get_type_string (tuple), ==, "(a{sv}sssa{sv})"); + g_variant_get (tuple, "(@a{sv}&s&s&s@a{sv})", + &creator, &type, &app_id, &instance_id, &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_assert_cmpstr (app_id, ==, ""); + g_assert_cmpstr (instance_id, ==, ""); g_variant_dict_init (&dict, asv); g_assert_true (g_variant_dict_lookup (&dict, "NChildren", "u", &u)); g_assert_cmpuint (u, ==, 2); @@ -755,7 +850,7 @@ test_metadata (Fixture *f, * Test StopListening(), which just closes the listening socket. * * With config->stop_server == STOP_SERVER_FORCE: - * Test StopInstance(), which closes the listening socket and + * Test StopServer(), which closes the listening socket and * disconnects all its clients. */ static void @@ -769,14 +864,22 @@ test_stop_server (Fixture *f, GDBusProxy *attacker_proxy; GSocket *client_socket; GSocketAddress *socket_address; + GUnixFDList *fds = NULL; GVariant *tuple; + GVariant *creator; GVariant *parameters; + GVariant *asv; + GVariantDict dict; + GVariantDict named_argument_builder; gchar *error_name; + gchar *stringified_result; const gchar *confined_unique_name; const gchar *name_owner; - gboolean gone = FALSE; - guint name_watch; + const char *type; + const char *app_id; + const char *instance_id; guint i; + guint32 uid; g_assert_nonnull (config); @@ -791,12 +894,43 @@ test_stop_server (Fixture *f, &f->error); g_assert_no_error (f->error); - parameters = g_variant_new ("(ssa{sv}a{sv})", + g_variant_dict_init (&named_argument_builder, NULL); + fds = g_unix_fd_list_new (); + + if (config->stop_server == STOP_SERVER_VIA_NOTIFY_NOT_MANAGER) + g_variant_dict_insert (&named_argument_builder, "StopOnDisconnect", + "b", FALSE); + + if (config->stop_server == STOP_SERVER_VIA_NOTIFY || + config->stop_server == STOP_SERVER_VIA_NOTIFY_NOT_MANAGER) + { + DBusError error = DBUS_ERROR_INIT; + int notify_pipe[2]; + int fd_index; + + _dbus_unix_make_pipe (notify_pipe, &error); + test_assert_no_error (&error); + + /* transfer ownership */ + f->stop_on_notify_pipe_write_end = notify_pipe[1]; + + /* duplicate into the fd list and close the original */ + fd_index = g_unix_fd_list_append (fds, notify_pipe[0], &f->error); + g_assert_no_error (f->error); + g_assert_cmpint (fd_index, >=, 0); + close (notify_pipe[0]); + + g_variant_dict_insert (&named_argument_builder, "StopOnNotify", + "h", fd_index); + } + + parameters = g_variant_new ("(sssa{sv}@a{sv})", "com.example.NotFlatpak", "sample-app", + "", NULL, /* no metadata */ - NULL); /* no named arguments */ - if (!add_container_server (f, g_steal_pointer (¶meters))) + g_variant_dict_end (&named_argument_builder)); + if (!add_container_server (f, g_steal_pointer (¶meters), fds, NULL)) return; socket_address = g_unix_socket_address_new (f->socket_path); @@ -813,6 +947,9 @@ test_stop_server (Fixture *f, if (config->stop_server == STOP_SERVER_DISCONNECT_FIRST) { + guint name_watch; + gboolean gone = FALSE; + g_test_message ("Disconnecting confined connection..."); gone = FALSE; confined_unique_name = g_dbus_connection_get_unique_name ( @@ -836,7 +973,7 @@ test_stop_server (Fixture *f, } /* 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 with a different uid cannot close our container servers. */ attacker = test_try_connect_gdbus_as_user (f->bus_address, TEST_USER_OTHER, &f->error); @@ -851,15 +988,15 @@ test_stop_server (Fixture *f, g_assert_no_error (f->error); tuple = g_dbus_proxy_call_sync (attacker_proxy, "StopListening", - g_variant_new ("(o)", f->instance_path), + g_variant_new ("(o)", f->server_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), + tuple = g_dbus_proxy_call_sync (attacker_proxy, "StopServer", + g_variant_new ("(o)", f->server_path), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &f->error); g_assert_error (f->error, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED); @@ -880,46 +1017,32 @@ test_stop_server (Fixture *f, g_clear_error (&f->error); } - g_assert_false (g_hash_table_contains (f->containers_removed, - f->instance_path)); + g_assert_false (g_hash_table_contains (f->servers_removed, + f->server_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); + g_test_message ("Stopping server (but not confined connection) by " + "disconnecting container manager from bus"); + fixture_disconnect_unconfined_and_wait (f); 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_variant_new ("(o)", f->server_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 + /* The container server 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..."); + g_test_message ("Checking we do not get ServerRemoved..."); tuple = g_dbus_proxy_call_sync (f->proxy, "NoSuchMethod", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &f->error); @@ -928,33 +1051,49 @@ test_stop_server (Fixture *f, g_clear_error (&f->error); break; + case STOP_SERVER_VIA_NOTIFY_NOT_MANAGER: + fixture_disconnect_unconfined_and_wait (f); + + /* Assert that the server is still functional at this point, + * because we configured it with StopOnDisconnect=FALSE */ + g_assert_true (g_file_test (f->socket_path, G_FILE_TEST_EXISTS)); + /* fall through */ + + case STOP_SERVER_VIA_NOTIFY: + g_test_message ("Stopping server (but not confined connection) by " + "closing pipe fd"); + g_close (f->stop_on_notify_pipe_write_end, &f->error); + g_assert_no_error (f->error); + f->stop_on_notify_pipe_write_end = -1; + 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_variant_new ("(o)", f->server_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_test_message ("Waiting for ServerRemoved..."); + while (!g_hash_table_contains (f->servers_removed, f->server_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), + tuple = g_dbus_proxy_call_sync (f->proxy, "StopServer", + g_variant_new ("(o)", f->server_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_test_message ("Waiting for ServerRemoved..."); + while (!g_hash_table_contains (f->servers_removed, f->server_path)) g_main_context_iteration (NULL, TRUE); break; @@ -1034,6 +1173,8 @@ test_stop_server (Fixture *f, break; case STOP_SERVER_EXPLICITLY: + case STOP_SERVER_VIA_NOTIFY: + case STOP_SERVER_VIA_NOTIFY_NOT_MANAGER: case STOP_SERVER_WITH_MANAGER: g_test_message ("Checking that the confined app still works..."); tuple = g_dbus_connection_call_sync (f->confined_conn, @@ -1053,18 +1194,34 @@ test_stop_server (Fixture *f, g_assert_cmpstr (name_owner, ==, DBUS_SERVICE_DBUS); g_clear_pointer (&tuple, g_variant_unref); - /* The container instance will not disappear from the bus + /* The container server 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), + tuple = g_dbus_proxy_call_sync (f->observer_proxy, "GetServerInfo", + g_variant_new ("(o)", f->server_path), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &f->error); g_assert_no_error (f->error); g_assert_nonnull (tuple); + stringified_result = g_variant_print (tuple, TRUE); + g_test_message ("GetServerInfo() -> %s", stringified_result); + g_free (stringified_result); + g_assert_cmpstr (g_variant_get_type_string (tuple), ==, "(a{sv}sssa{sv})"); + g_variant_get (tuple, "(@a{sv}&s&s&s@a{sv})", + &creator, &type, &app_id, &instance_id, &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 (app_id, ==, "sample-app"); + g_assert_cmpstr (instance_id, ==, ""); + 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); /* Now disconnect the last confined connection, which will make the - * container instance go away */ + * container server 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); @@ -1076,12 +1233,12 @@ test_stop_server (Fixture *f, /* 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_test_message ("Waiting for ServerRemoved..."); + while (!g_hash_table_contains (f->servers_removed, f->server_path)) g_main_context_iteration (NULL, TRUE); - tuple = g_dbus_proxy_call_sync (f->observer_proxy, "GetInstanceInfo", - g_variant_new ("(o)", f->instance_path), + tuple = g_dbus_proxy_call_sync (f->observer_proxy, "GetServerInfo", + g_variant_new ("(o)", f->server_path), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &f->error); g_assert_nonnull (f->error); @@ -1099,7 +1256,7 @@ test_stop_server (Fixture *f, /* * 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 + * isn't a container server, or a bus name that isn't in a container * or doesn't exist at all. */ static void @@ -1119,7 +1276,7 @@ test_invalid_metadata_getters (Fixture *f, 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", + tuple = g_dbus_proxy_call_sync (f->proxy, "GetConnectionInfo", g_variant_new ("(s)", unique_name), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &f->error); g_assert_nonnull (f->error); @@ -1135,7 +1292,7 @@ test_invalid_metadata_getters (Fixture *f, g_clear_error (&f->error); g_test_message ("Inspecting dbus-daemon"); - tuple = g_dbus_proxy_call_sync (f->proxy, "GetConnectionInstance", + tuple = g_dbus_proxy_call_sync (f->proxy, "GetConnectionInfo", g_variant_new ("(s)", DBUS_SERVICE_DBUS), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &f->error); g_assert_nonnull (f->error); @@ -1152,7 +1309,7 @@ test_invalid_metadata_getters (Fixture *f, 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", + tuple = g_dbus_proxy_call_sync (f->proxy, "GetConnectionInfo", g_variant_new ("(s)", "com.example.Nope"), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &f->error); g_assert_nonnull (f->error); @@ -1168,8 +1325,8 @@ test_invalid_metadata_getters (Fixture *f, g_clear_error (&f->error); - g_test_message ("Inspecting container instance info"); - tuple = g_dbus_proxy_call_sync (f->proxy, "GetInstanceInfo", + g_test_message ("Inspecting container server info"); + tuple = g_dbus_proxy_call_sync (f->proxy, "GetServerInfo", g_variant_new ("(o)", "/nope"), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &f->error); g_assert_nonnull (f->error); @@ -1213,9 +1370,10 @@ test_unsupported_parameter (Fixture *f, "ThisArgumentIsntImplemented", "b", FALSE); - parameters = g_variant_new ("(ssa{sv}@a{sv})", + parameters = g_variant_new ("(sssa{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", @@ -1253,9 +1411,10 @@ test_invalid_type_name (Fixture *f, NULL, &f->error); g_assert_no_error (f->error); - parameters = g_variant_new ("(ssa{sv}a{sv})", + parameters = g_variant_new ("(sssa{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", @@ -1288,12 +1447,13 @@ test_invalid_nesting (Fixture *f, if (f->skip) return; - parameters = g_variant_new ("(ssa{sv}a{sv})", + parameters = g_variant_new ("(sssa{sv}a{sv})", "com.example.NotFlatpak", "sample-app", + "instance0", NULL, /* no metadata */ NULL); /* no named arguments */ - if (!add_container_server (f, g_steal_pointer (¶meters))) + if (!add_container_server (f, g_steal_pointer (¶meters), NULL, NULL)) return; g_test_message ("Connecting to %s...", f->socket_dbus_address); @@ -1312,9 +1472,10 @@ test_invalid_nesting (Fixture *f, &f->error); g_assert_no_error (f->error); - parameters = g_variant_new ("(ssa{sv}a{sv})", + parameters = g_variant_new ("(sssa{sv}a{sv})", "com.example.NotFlatpak", "inner-app", + "instance1", NULL, /* no metadata */ NULL); /* no named arguments */ tuple = g_dbus_proxy_call_sync (nested_proxy, "AddServer", @@ -1361,9 +1522,10 @@ test_max_containers (Fixture *f, NULL, &f->error); g_assert_no_error (f->error); - parameters = g_variant_new ("(ssa{sv}a{sv})", + parameters = g_variant_new ("(sssa{sv}a{sv})", "com.example.NotFlatpak", "sample-app", + "instance1", NULL, /* no metadata */ NULL); /* no named arguments */ /* We will reuse this variant several times, so don't use floating refs */ @@ -1377,7 +1539,7 @@ test_max_containers (Fixture *f, 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_get (tuple, "(o@a{sv})", &placeholders[i], NULL); g_variant_unref (tuple); g_test_message ("Placeholder server at %s", placeholders[i]); } @@ -1458,7 +1620,6 @@ test_max_connections_per_container (Fixture *f, * limit-containers.conf */ GSocket *placeholders[G_N_ELEMENTS (socket_paths) * 3] = { NULL }; GVariant *parameters; - GVariant *tuple; guint i; if (f->skip) @@ -1471,9 +1632,10 @@ test_max_connections_per_container (Fixture *f, NULL, &f->error); g_assert_no_error (f->error); - parameters = g_variant_new ("(ssa{sv}a{sv})", + parameters = g_variant_new ("(sssa{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 */ @@ -1481,13 +1643,25 @@ test_max_connections_per_container (Fixture *f, for (i = 0; i < G_N_ELEMENTS (socket_paths); i++) { + GVariant *tuple; + GVariant *named_results; + gboolean found; + 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_get (tuple, "(o@a{sv})", NULL, &named_results); + + found = g_variant_lookup (named_results, "Address", + "s", &dbus_addresses[i]); + g_assert_true (found); + found = g_variant_lookup (named_results, "SocketPath", + "^ay", &socket_paths[i]); + g_assert_true (found); + + g_variant_unref (named_results); 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]); @@ -1621,9 +1795,10 @@ test_max_container_metadata_bytes (Fixture *f, 1)); /* Floating reference, call_..._sync takes ownership */ - parameters = g_variant_new ("(ss@a{sv}a{sv})", + parameters = g_variant_new ("(sss@a{sv}a{sv})", "com.wasteheadquarters", "Packt Like Sardines in a Crushd Tin Box", + "", g_variant_dict_end (&dict), NULL); /* no named arguments */ @@ -1645,7 +1820,7 @@ teardown (Fixture *f, g_clear_object (&f->proxy); fixture_disconnect_observer (f); - g_clear_pointer (&f->containers_removed, g_hash_table_unref); + g_clear_pointer (&f->servers_removed, g_hash_table_unref); if (f->libdbus_observer != NULL) { @@ -1680,8 +1855,17 @@ teardown (Fixture *f, f->daemon_pid = 0; } + if (f->stop_on_notify_pipe_write_end >= 0) + { + GError *error = NULL; + + g_close (f->stop_on_notify_pipe_write_end, &error); + g_assert_no_error (error); + f->stop_on_notify_pipe_write_end = -1; + } + dbus_clear_message (&f->latest_shout); - g_free (f->instance_path); + g_free (f->server_path); g_free (f->socket_path); g_free (f->socket_dbus_address); g_free (f->bus_address); @@ -1710,6 +1894,16 @@ static const Config stop_server_force = "valid-config-files/multi-user.conf", STOP_SERVER_FORCE }; +static const Config stop_server_via_notify = +{ + "valid-config-files/multi-user.conf", + STOP_SERVER_VIA_NOTIFY +}; +static const Config stop_server_not_with_manager = +{ + "valid-config-files/multi-user.conf", + STOP_SERVER_VIA_NOTIFY_NOT_MANAGER +}; static const Config stop_server_with_manager = { "valid-config-files/multi-user.conf", @@ -1769,6 +1963,10 @@ main (int argc, &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/via-notify", Fixture, + &stop_server_via_notify, setup, test_stop_server, teardown); + g_test_add ("/containers/stop-server/not-with-manager", Fixture, + &stop_server_not_with_manager, 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, diff --git a/test/data/valid-config-files/limit-containers.conf.in b/test/data/valid-config-files/limit-containers.conf.in index 44dd3979..3cc3bb05 100644 --- a/test/data/valid-config-files/limit-containers.conf.in +++ b/test/data/valid-config-files/limit-containers.conf.in @@ -13,4 +13,9 @@ + + 5 + 3 + 4096 + 3 diff --git a/test/data/valid-config-files/tmp-session.conf.in b/test/data/valid-config-files/tmp-session.conf.in index d1effae1..502619dd 100644 --- a/test/data/valid-config-files/tmp-session.conf.in +++ b/test/data/valid-config-files/tmp-session.conf.in @@ -57,4 +57,11 @@ 50000 50000 50000 + 10000 + 10000 + 1000000000 + + 16 + diff --git a/test/dbus-daemon.c b/test/dbus-daemon.c index 1288fe0c..772fac5f 100644 --- a/test/dbus-daemon.c +++ b/test/dbus-daemon.c @@ -637,6 +637,10 @@ test_creds (Fixture *f, g_assert_not_reached (); #endif } + else if (g_str_has_prefix (name, DBUS_INTERFACE_CONTAINERS1 ".")) + { + g_assert_not_reached (); + } dbus_message_iter_next (&arr_iter); } diff --git a/test/internals/dbus-message-util.c b/test/internals/dbus-message-util.c index 310822d6..cd8259c7 100644 --- a/test/internals/dbus-message-util.c +++ b/test/internals/dbus-message-util.c @@ -1170,9 +1170,9 @@ _dbus_message_test (const char *test_data_dir _DBUS_GNUC_UNUSED) _dbus_assert (strcmp (dbus_message_get_path (message), "/foo") == 0); - if (!dbus_message_set_container_instance (message, "/org/freedesktop/DBus/Containers1/c42")) + if (!dbus_message_set_container_path (message, "/org/freedesktop/DBus/Containers1/c42")) _dbus_test_fatal ("out of memory"); - _dbus_assert (strcmp (dbus_message_get_container_instance (message), + _dbus_assert (strcmp (dbus_message_get_container_path (message), "/org/freedesktop/DBus/Containers1/c42") == 0); if (!dbus_message_set_interface (message, "org.Foo")) diff --git a/tools/ci-build.sh b/tools/ci-build.sh index b258c951..86b58131 100755 --- a/tools/ci-build.sh +++ b/tools/ci-build.sh @@ -377,6 +377,7 @@ case "$ci_buildsys" in fi set -- -Db_pie=true "$@" + set -- -Dcontainers=true "$@" set -- -Duser_session=true "$@" ;; esac @@ -401,6 +402,7 @@ case "$ci_buildsys" in set "$@" -Dlibaudit=disabled -Dvalgrind=disabled # Disable optional features, some of which are on by # default + set "$@" -Dcontainers=false set "$@" -Dstats=false set "$@" -Duser_session=false shift @@ -462,6 +464,12 @@ case "$ci_buildsys" in $meson_setup "$@" "$srcdir" meson compile -v + if [ "$(id -u)" = 0 ]; then + # In production, this would be /run/dbus/containers and would + # have been set up by the init script or tmpfiles.d + mkdir -p /var/local/run/dbus/containers + fi + # This is too slow and verbose to keep enabled at the moment export DBUS_TEST_MALLOC_FAILURES=0