static dbus_bool_t create_unique_client_name (BusRegistry *registry, DBusString *str) { /* We never want to use the same unique client name twice, because * we want to guarantee that if you send a message to a given unique * name, you always get the same application. So we use two numbers * for INT_MAX * INT_MAX combinations, should be pretty safe against * wraparound. */ /* FIXME these should be in BusRegistry rather than static vars */ static int next_major_number = 0; static int next_minor_number = 0; int len; len = _dbus_string_get_length (str); while (TRUE) { /* start out with 1-0, go to 1-1, 1-2, 1-3, * up to 1-MAXINT, then 2-0, 2-1, etc. */ if (next_minor_number <= 0) { next_major_number += 1; next_minor_number = 0; if (next_major_number <= 0) _dbus_assert_not_reached ("INT_MAX * INT_MAX clients were added"); } _dbus_assert (next_major_number > 0); _dbus_assert (next_minor_number >= 0); /* appname:MAJOR-MINOR */ if (!_dbus_string_append (str, ":")) return FALSE; if (!_dbus_string_append_int (str, next_major_number)) return FALSE; if (!_dbus_string_append (str, ".")) return FALSE; if (!_dbus_string_append_int (str, next_minor_number)) return FALSE; next_minor_number += 1; /* Check if a client with the name exists */ if (bus_registry_lookup (registry, str) == NULL) break; /* drop the number again, try the next one. */ _dbus_string_set_length (str, len); } return TRUE; }
dbus_bool_t bus_registry_release_service (BusRegistry *registry, DBusConnection *connection, const DBusString *service_name, dbus_uint32_t *result, BusTransaction *transaction, DBusError *error) { dbus_bool_t retval; BusService *service; retval = FALSE; if (!_dbus_validate_bus_name (service_name, 0, _dbus_string_get_length (service_name))) { dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Given bus name \"%s\" is not valid", _dbus_string_get_const_data (service_name)); _dbus_verbose ("Attempt to release invalid service name\n"); goto out; } if (_dbus_string_get_byte (service_name, 0) == ':') { /* Not allowed; the base service name cannot be created or released */ dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Cannot release a service starting with ':' such as \"%s\"", _dbus_string_get_const_data (service_name)); _dbus_verbose ("Attempt to release invalid base service name \"%s\"", _dbus_string_get_const_data (service_name)); goto out; } if (_dbus_string_equal_c_str (service_name, DBUS_SERVICE_DBUS)) { /* Not allowed; the base service name cannot be created or released */ dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Cannot release the %s service because it is owned by the bus", DBUS_SERVICE_DBUS); _dbus_verbose ("Attempt to release service name \"%s\"", DBUS_SERVICE_DBUS); goto out; } service = bus_registry_lookup (registry, service_name); if (service == NULL) { *result = DBUS_RELEASE_NAME_REPLY_NON_EXISTENT; } else if (!bus_service_has_owner (service, connection)) { *result = DBUS_RELEASE_NAME_REPLY_NOT_OWNER; } else { if (!bus_service_remove_owner (service, connection, transaction, error)) goto out; _dbus_assert (!bus_service_has_owner (service, connection)); *result = DBUS_RELEASE_NAME_REPLY_RELEASED; } retval = TRUE; out: return retval; }
dbus_bool_t bus_registry_acquire_service (BusRegistry *registry, DBusConnection *connection, const DBusString *service_name, dbus_uint32_t flags, dbus_uint32_t *result, BusTransaction *transaction, DBusError *error) { dbus_bool_t retval; DBusConnection *old_owner_conn; BusClientPolicy *policy; BusService *service; BusActivation *activation; BusSELinuxID *sid; BusOwner *primary_owner; retval = FALSE; if (!_dbus_validate_bus_name (service_name, 0, _dbus_string_get_length (service_name))) { dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Requested bus name \"%s\" is not valid", _dbus_string_get_const_data (service_name)); _dbus_verbose ("Attempt to acquire invalid service name\n"); goto out; } if (_dbus_string_get_byte (service_name, 0) == ':') { /* Not allowed; only base services can start with ':' */ dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Cannot acquire a service starting with ':' such as \"%s\"", _dbus_string_get_const_data (service_name)); _dbus_verbose ("Attempt to acquire invalid base service name \"%s\"", _dbus_string_get_const_data (service_name)); goto out; } if (_dbus_string_equal_c_str (service_name, DBUS_SERVICE_DBUS)) { dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Connection \"%s\" is not allowed to own the service \"%s\"because " "it is reserved for D-Bus' use only", bus_connection_is_active (connection) ? bus_connection_get_name (connection) : "(inactive)", DBUS_SERVICE_DBUS); goto out; } policy = bus_connection_get_policy (connection); _dbus_assert (policy != NULL); /* Note that if sid is #NULL then the bus's own context gets used * in bus_connection_selinux_allows_acquire_service() */ sid = bus_selinux_id_table_lookup (registry->service_sid_table, service_name); if (!bus_selinux_allows_acquire_service (connection, sid, _dbus_string_get_const_data (service_name), error)) { if (dbus_error_is_set (error) && dbus_error_has_name (error, DBUS_ERROR_NO_MEMORY)) { goto out; } dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, "Connection \"%s\" is not allowed to own the service \"%s\" due " "to SELinux policy", bus_connection_is_active (connection) ? bus_connection_get_name (connection) : "(inactive)", _dbus_string_get_const_data (service_name)); goto out; } if (!bus_client_policy_check_can_own (policy, service_name)) { dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, "Connection \"%s\" is not allowed to own the service \"%s\" due " "to security policies in the configuration file", bus_connection_is_active (connection) ? bus_connection_get_name (connection) : "(inactive)", _dbus_string_get_const_data (service_name)); goto out; } if (bus_connection_get_n_services_owned (connection) >= bus_context_get_max_services_per_connection (registry->context)) { dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, "Connection \"%s\" is not allowed to own more services " "(increase limits in configuration file if required)", bus_connection_is_active (connection) ? bus_connection_get_name (connection) : "(inactive)"); goto out; } service = bus_registry_lookup (registry, service_name); if (service != NULL) { primary_owner = bus_service_get_primary_owner (service); if (primary_owner != NULL) old_owner_conn = primary_owner->conn; else old_owner_conn = NULL; } else old_owner_conn = NULL; if (service == NULL) { service = bus_registry_ensure (registry, service_name, connection, flags, transaction, error); if (service == NULL) goto out; } primary_owner = bus_service_get_primary_owner (service); if (primary_owner == NULL) goto out; if (old_owner_conn == NULL) { _dbus_assert (primary_owner->conn == connection); *result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER; } else if (old_owner_conn == connection) { bus_owner_set_flags (primary_owner, flags); *result = DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER; } else if (((flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) && !(bus_service_get_allow_replacement (service))) || ((flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) && !(flags & DBUS_NAME_FLAG_REPLACE_EXISTING))) { DBusList *link; BusOwner *temp_owner; /* Since we can't be queued if we are already in the queue remove us */ link = _bus_service_find_owner_link (service, connection); if (link != NULL) { _dbus_list_unlink (&service->owners, link); temp_owner = (BusOwner *)link->data; bus_owner_unref (temp_owner); _dbus_list_free_link (link); } *result = DBUS_REQUEST_NAME_REPLY_EXISTS; } else if (!(flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) && (!(flags & DBUS_NAME_FLAG_REPLACE_EXISTING) || !(bus_service_get_allow_replacement (service)))) { /* Queue the connection */ if (!bus_service_add_owner (service, connection, flags, transaction, error)) goto out; *result = DBUS_REQUEST_NAME_REPLY_IN_QUEUE; } else { /* Replace the current owner */ /* We enqueue the new owner and remove the first one because * that will cause NameAcquired and NameLost messages to * be sent. */ if (!bus_service_add_owner (service, connection, flags, transaction, error)) goto out; if (primary_owner->do_not_queue) { if (!bus_service_remove_owner (service, old_owner_conn, transaction, error)) goto out; } else { if (!bus_service_swap_owner (service, old_owner_conn, transaction, error)) goto out; } _dbus_assert (connection == bus_service_get_primary_owner (service)->conn); *result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER; } activation = bus_context_get_activation (registry->context); retval = bus_activation_send_pending_auto_activation_messages (activation, service, transaction); if (!retval) BUS_SET_OOM (error); out: return retval; }
static dbus_bool_t bus_driver_handle_list_queued_owners (DBusConnection *connection, BusTransaction *transaction, DBusMessage *message, DBusError *error) { const char *text; DBusList *base_names; DBusList *link; DBusString str; BusRegistry *registry; BusService *service; DBusMessage *reply; DBusMessageIter iter, array_iter; char *dbus_service_name = DBUS_SERVICE_DBUS; _DBUS_ASSERT_ERROR_IS_CLEAR (error); registry = bus_connection_get_registry (connection); base_names = NULL; text = NULL; reply = NULL; if (! dbus_message_get_args (message, error, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID)) goto failed; _dbus_string_init_const (&str, text); service = bus_registry_lookup (registry, &str); if (service == NULL && _dbus_string_equal_c_str (&str, DBUS_SERVICE_DBUS)) { /* ORG_FREEDESKTOP_DBUS owns itself */ if (! _dbus_list_append (&base_names, dbus_service_name)) goto oom; } else if (service == NULL) { dbus_set_error (error, DBUS_ERROR_NAME_HAS_NO_OWNER, "Could not get owners of name '%s': no such name", text); goto failed; } else { if (!bus_service_list_queued_owners (service, &base_names, error)) goto failed; } _dbus_assert (base_names != NULL); reply = dbus_message_new_method_return (message); if (reply == NULL) goto oom; dbus_message_iter_init_append (reply, &iter); if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, &array_iter)) goto oom; link = _dbus_list_get_first_link (&base_names); while (link != NULL) { char *uname; _dbus_assert (link->data != NULL); uname = (char *)link->data; if (!dbus_message_iter_append_basic (&array_iter, DBUS_TYPE_STRING, &uname)) goto oom; link = _dbus_list_get_next_link (&base_names, link); } if (! dbus_message_iter_close_container (&iter, &array_iter)) goto oom; if (! bus_transaction_send_from_driver (transaction, connection, reply)) goto oom; dbus_message_unref (reply); return TRUE; oom: BUS_SET_OOM (error); failed: _DBUS_ASSERT_ERROR_IS_SET (error); if (reply) dbus_message_unref (reply); if (base_names) _dbus_list_clear (&base_names); return FALSE; }
static dbus_bool_t bus_driver_handle_get_service_owner (DBusConnection *connection, BusTransaction *transaction, DBusMessage *message, DBusError *error) { const char *text; const char *base_name; DBusString str; BusRegistry *registry; BusService *service; DBusMessage *reply; _DBUS_ASSERT_ERROR_IS_CLEAR (error); registry = bus_connection_get_registry (connection); text = NULL; reply = NULL; if (! dbus_message_get_args (message, error, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID)) goto failed; _dbus_string_init_const (&str, text); service = bus_registry_lookup (registry, &str); if (service == NULL && _dbus_string_equal_c_str (&str, DBUS_SERVICE_DBUS)) { /* ORG_FREEDESKTOP_DBUS owns itself */ base_name = DBUS_SERVICE_DBUS; } else if (service == NULL) { dbus_set_error (error, DBUS_ERROR_NAME_HAS_NO_OWNER, "Could not get owner of name '%s': no such name", text); goto failed; } else { base_name = bus_connection_get_name (bus_service_get_primary_owners_connection (service)); if (base_name == NULL) { /* FIXME - how is this error possible? */ dbus_set_error (error, DBUS_ERROR_FAILED, "Could not determine unique name for '%s'", text); goto failed; } _dbus_assert (*base_name == ':'); } _dbus_assert (base_name != NULL); reply = dbus_message_new_method_return (message); if (reply == NULL) goto oom; if (! dbus_message_append_args (reply, DBUS_TYPE_STRING, &base_name, DBUS_TYPE_INVALID)) goto oom; if (! bus_transaction_send_from_driver (transaction, connection, reply)) goto oom; dbus_message_unref (reply); return TRUE; oom: BUS_SET_OOM (error); failed: _DBUS_ASSERT_ERROR_IS_SET (error); if (reply) dbus_message_unref (reply); return FALSE; }
static dbus_bool_t bus_driver_handle_service_exists (DBusConnection *connection, BusTransaction *transaction, DBusMessage *message, DBusError *error) { DBusMessage *reply; DBusString service_name; BusService *service; dbus_bool_t service_exists; const char *name; dbus_bool_t retval; BusRegistry *registry; _DBUS_ASSERT_ERROR_IS_CLEAR (error); registry = bus_connection_get_registry (connection); if (!dbus_message_get_args (message, error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) return FALSE; retval = FALSE; if (strcmp (name, DBUS_SERVICE_DBUS) == 0) { service_exists = TRUE; } else { _dbus_string_init_const (&service_name, name); service = bus_registry_lookup (registry, &service_name); service_exists = service != NULL; } reply = dbus_message_new_method_return (message); if (reply == NULL) { BUS_SET_OOM (error); goto out; } if (!dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &service_exists, 0)) { BUS_SET_OOM (error); goto out; } if (!bus_transaction_send_from_driver (transaction, connection, reply)) { BUS_SET_OOM (error); goto out; } retval = TRUE; out: if (reply) dbus_message_unref (reply); return retval; }
static dbus_bool_t bus_driver_handle_get_connection_selinux_security_context (DBusConnection *connection, BusTransaction *transaction, DBusMessage *message, DBusError *error) { const char *service; DBusString str; BusRegistry *registry; BusService *serv; DBusConnection *conn; DBusMessage *reply; BusSELinuxID *context; _DBUS_ASSERT_ERROR_IS_CLEAR (error); registry = bus_connection_get_registry (connection); service = NULL; reply = NULL; if (! dbus_message_get_args (message, error, DBUS_TYPE_STRING, &service, DBUS_TYPE_INVALID)) goto failed; _dbus_verbose ("asked for security context of connection %s\n", service); _dbus_string_init_const (&str, service); serv = bus_registry_lookup (registry, &str); if (serv == NULL) { dbus_set_error (error, DBUS_ERROR_NAME_HAS_NO_OWNER, "Could not get security context of name '%s': no such name", service); goto failed; } conn = bus_service_get_primary_owners_connection (serv); reply = dbus_message_new_method_return (message); if (reply == NULL) goto oom; context = bus_connection_get_selinux_id (conn); if (!context) { dbus_set_error (error, DBUS_ERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN, "Could not determine security context for '%s'", service); goto failed; } if (! bus_selinux_append_context (reply, context, error)) goto failed; if (! bus_transaction_send_from_driver (transaction, connection, reply)) goto oom; dbus_message_unref (reply); return TRUE; oom: BUS_SET_OOM (error); failed: _DBUS_ASSERT_ERROR_IS_SET (error); if (reply) dbus_message_unref (reply); return FALSE; }
static dbus_bool_t bus_driver_handle_get_connection_unix_process_id (DBusConnection *connection, BusTransaction *transaction, DBusMessage *message, DBusError *error) { const char *service; DBusString str; BusRegistry *registry; BusService *serv; DBusConnection *conn; DBusMessage *reply; unsigned long pid; dbus_uint32_t pid32; _DBUS_ASSERT_ERROR_IS_CLEAR (error); registry = bus_connection_get_registry (connection); service = NULL; reply = NULL; if (! dbus_message_get_args (message, error, DBUS_TYPE_STRING, &service, DBUS_TYPE_INVALID)) goto failed; _dbus_verbose ("asked for PID of connection %s\n", service); _dbus_string_init_const (&str, service); serv = bus_registry_lookup (registry, &str); if (serv == NULL) { dbus_set_error (error, DBUS_ERROR_NAME_HAS_NO_OWNER, "Could not get PID of name '%s': no such name", service); goto failed; } conn = bus_service_get_primary_owners_connection (serv); reply = dbus_message_new_method_return (message); if (reply == NULL) goto oom; if (!dbus_connection_get_unix_process_id (conn, &pid)) { dbus_set_error (error, DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN, "Could not determine PID for '%s'", service); goto failed; } pid32 = pid; if (! dbus_message_append_args (reply, DBUS_TYPE_UINT32, &pid32, DBUS_TYPE_INVALID)) goto oom; if (! bus_transaction_send_from_driver (transaction, connection, reply)) goto oom; dbus_message_unref (reply); return TRUE; oom: BUS_SET_OOM (error); failed: _DBUS_ASSERT_ERROR_IS_SET (error); if (reply) dbus_message_unref (reply); return FALSE; }