X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=bus%2Fservices.c;h=8a186273fb2c443fd3d2a53e5d44c6af920998b3;hb=05902801b49789f37426754fc6b77f3665afe3b0;hp=6f380fac7de56c8097280fe2ccbc710c31c8e543;hpb=e48de6be84f89636f11159b9e7ea56b6dc49d577;p=platform%2Fupstream%2Fdbus.git diff --git a/bus/services.c b/bus/services.c index 6f380fa..8a18627 100644 --- a/bus/services.c +++ b/bus/services.c @@ -3,6 +3,7 @@ * * Copyright (C) 2003 Red Hat, Inc. * Copyright (C) 2003 CodeFactory AB + * Copyright (C) 2013 Samsung Electronics * * Licensed under the Academic Free License version 2.1 * @@ -27,6 +28,11 @@ #include #include #include +#ifdef ENABLE_KDBUS_TRANSPORT +#include +#include +#include +#endif #include "driver.h" #include "services.h" @@ -36,6 +42,10 @@ #include "policy.h" #include "bus.h" #include "selinux.h" +#ifdef ENABLE_KDBUS_TRANSPORT +#include "kdbus-d.h" +#include "dbus/kdbus.h" +#endif struct BusService { @@ -55,6 +65,9 @@ struct BusOwner unsigned int allow_replacement : 1; unsigned int do_not_queue : 1; +#ifdef ENABLE_KDBUS_TRANSPORT + unsigned int is_kdbus_starter : 1; +#endif }; struct BusRegistry @@ -172,6 +185,30 @@ _bus_service_find_owner_link (BusService *service, return link; } +#ifdef ENABLE_KDBUS_TRANSPORT +static DBusConnection * +_bus_service_find_owner_connection (BusService *service, + const char* unique_name) +{ + DBusList *link; + + link = _dbus_list_get_first_link (&service->owners); + + while (link != NULL) + { + BusOwner *bus_owner; + + bus_owner = (BusOwner *) link->data; + if(!strcmp(bus_connection_get_name(bus_owner->conn), unique_name)) + return bus_owner->conn; + + link = _dbus_list_get_next_link (&service->owners, link); + } + + return NULL; +} +#endif + static void bus_owner_set_flags (BusOwner *owner, dbus_uint32_t flags) @@ -181,6 +218,11 @@ bus_owner_set_flags (BusOwner *owner, owner->do_not_queue = (flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) != FALSE; + +#ifdef ENABLE_KDBUS_TRANSPORT + owner->is_kdbus_starter = + (flags & KDBUS_NAME_STARTER) != FALSE; +#endif } static BusOwner * @@ -310,7 +352,7 @@ bus_registry_ensure (BusRegistry *registry, BUS_SET_OOM (error); return NULL; } - + return service; } @@ -368,7 +410,7 @@ bus_registry_list_services (BusRegistry *registry, error: for (j = 0; j < i; j++) - dbus_free (retval[i]); + dbus_free (retval[j]); dbus_free (retval); return FALSE; @@ -437,163 +479,321 @@ bus_registry_acquire_service (BusRegistry *registry, * in bus_connection_selinux_allows_acquire_service() */ sid = bus_selinux_id_table_lookup (registry->service_sid_table, - service_name); + service_name); if (!bus_selinux_allows_acquire_service (connection, sid, _dbus_string_get_const_data (service_name), error)) - { + { - if (dbus_error_is_set (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; - } - + 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; - } + { + 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; - } - + 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; - } + { + 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; - + old_owner_conn = NULL; + if (service == NULL) - { - service = bus_registry_ensure (registry, - service_name, connection, flags, - transaction, error); - if (service == NULL) - goto out; - } + { + 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; + goto out; if (old_owner_conn == NULL) - { - _dbus_assert (primary_owner->conn == connection); + { + _dbus_assert (primary_owner->conn == connection); - *result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER; - } + *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; - } + { + 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))) || + !(bus_service_get_allow_replacement (service))) || ((flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) && - !(flags & DBUS_NAME_FLAG_REPLACE_EXISTING))) + !(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, + error); + + out: + return retval; +} + +#ifdef ENABLE_KDBUS_TRANSPORT +dbus_bool_t +bus_registry_acquire_kdbus_service (BusRegistry *registry, + DBusConnection *connection, + DBusMessage *message, + dbus_uint32_t *result, + BusTransaction *transaction, + DBusError *error) +{ + dbus_bool_t retval; + BusService *service; + BusActivation *activation; + + DBusString service_name_real; + const DBusString *service_name = &service_name_real; + char* name; + dbus_uint32_t flags; + __u64 sender_id; + dbus_bool_t rm_owner_daemon = FALSE; + + if (!dbus_message_get_args (message, error, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_UINT32, &flags, + DBUS_TYPE_INVALID)) + return FALSE; + + retval = FALSE; + + _dbus_string_init_const (&service_name_real, name); + + if (!_dbus_validate_bus_name (service_name, 0, + _dbus_string_get_length (service_name))) { - DBusList *link; - BusOwner *temp_owner; - /* Since we can't be queued if we are already in the queue - remove us */ + dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, + "Requested bus name \"%s\" is not valid", + _dbus_string_get_const_data (service_name)); - 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; + _dbus_verbose ("Attempt to acquire invalid service name\n"); + + goto out; } - else if (!(flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) && - (!(flags & DBUS_NAME_FLAG_REPLACE_EXISTING) || - !(bus_service_get_allow_replacement (service)))) + + if (_dbus_string_get_byte (service_name, 0) == ':') { - /* Queue the connection */ - if (!bus_service_add_owner (service, connection, - flags, - transaction, error)) - goto out; - - *result = DBUS_REQUEST_NAME_REPLY_IN_QUEUE; + /* 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; } - else + + if (_dbus_string_equal_c_str (service_name, DBUS_SERVICE_DBUS)) { - /* Replace the current owner */ + 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; + } - /* 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; + service = bus_registry_lookup (registry, service_name); + if (service == NULL) + { + service = bus_registry_ensure (registry, service_name, connection, flags, + transaction, error); //adds daemon to service owners list - must be removed after right owner is set + if (service == NULL) + goto out; + + rm_owner_daemon = TRUE; + if(!kdbus_register_policy(service_name, connection)) + { + dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, + "Connection is not allowed to own the service \"%s\" due to security policies in the configuration file", + _dbus_string_get_const_data (service_name)); + goto failed; + } + } - 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; - } + sender_id = sender_name_to_id(dbus_message_get_sender(message), error); + if(dbus_error_is_set(error)) + goto failed; + + *result = kdbus_request_name(connection, service_name, flags, sender_id); + if(*result == -EPERM) + { + dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, + "Connection is not allowed to own the service \"%s\" due to security policies in the configuration file", + _dbus_string_get_const_data (service_name)); + goto failed; + } + else if(*result < 0) + { + dbus_set_error (error, DBUS_ERROR_FAILED , "Name \"%s\" could not be acquired", name); + goto failed; + } + + if((*result == DBUS_REQUEST_NAME_REPLY_IN_QUEUE) || (*result == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)) + { + DBusConnection* phantom; + const char* name; +// DBusList *link; + + name = dbus_message_get_sender(message); + phantom = bus_connections_find_conn_by_name(bus_connection_get_connections(connection), name); + if(phantom == NULL) + phantom = create_phantom_connection(connection, name, error); + if(phantom == NULL) + goto failed2; + if (!bus_service_add_owner (service, phantom, flags, transaction, error)) + goto failed2; + if((*result == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) && rm_owner_daemon) + { + /* Here we are removing DBus daemon as an owner of the service, + * which is set by bus_registry_ensure. + * If bus_service_remove_owner fail, we ignore it, because it has + * almost none impact on the usage + */ + if(_bus_service_find_owner_link (service, connection)) + bus_service_remove_owner (service, connection, transaction, NULL); + } + /*if(bus_service_get_is_kdbus_starter(service)) + { + if (!bus_service_swap_owner (service, bus_service_get_primary_owners_connection(service), + transaction, error)) + goto failed2; + }*/ + /*if((link = _bus_service_find_owner_link (service, connection))) //if daemon is a starter + { + _dbus_list_unlink (&service->owners, link); + _dbus_list_append_link (&service->owners, link); //it must be moved at the end of the queue + }*/ + } activation = bus_context_get_activation (registry->context); retval = bus_activation_send_pending_auto_activation_messages (activation, service, transaction, error); - out: - return retval; + return retval; + +failed2: + kdbus_release_name(connection, service_name, sender_id); +failed: + if(_bus_service_find_owner_link (service, connection)) + bus_service_remove_owner (service, connection, transaction, NULL); + + return FALSE; } +#endif dbus_bool_t bus_registry_release_service (BusRegistry *registry, @@ -672,6 +872,95 @@ bus_registry_release_service (BusRegistry *registry, return retval; } +#ifdef ENABLE_KDBUS_TRANSPORT +dbus_bool_t +bus_registry_release_service_kdbus (const char* sender_name, + DBusConnection *connection, + const DBusString *service_name, + dbus_uint32_t *result, + BusTransaction *transaction, + DBusError *error) +{ + dbus_bool_t retval = FALSE; + __u64 sender_id; + + 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; + } + + sender_id = sender_name_to_id(sender_name, error); + if(dbus_error_is_set(error)) + return FALSE; + + *result = kdbus_release_name(connection, service_name, sender_id); + + if(*result == DBUS_RELEASE_NAME_REPLY_RELEASED) + { + BusRegistry* registry; + BusService *service; + + registry = bus_connection_get_registry (connection); + service = bus_registry_lookup (registry, service_name); + if(service) + { + DBusConnection* phantom; + + phantom = _bus_service_find_owner_connection(service, sender_name); + if(phantom) + { + bus_service_remove_owner (service, phantom, transaction, NULL); + /* todo we could remove phantom if he doesn't own any name + * to do this we should write function in connection.c to check if + * _dbus_list_get_last (&d->services_owned) returns not NULL + * or we can leave phantom - he will be removed when he disconnects from the bus + */ + } + else + _dbus_verbose ("Didn't find phantom connection for released name!\n"); + } + } + + retval = TRUE; + + out: + return retval; +} +#endif + dbus_bool_t bus_registry_set_service_context_table (BusRegistry *registry, DBusHashTable *table) @@ -800,7 +1089,7 @@ add_cancel_ownership_to_transaction (BusTransaction *transaction, bus_service_ref (d->service); bus_owner_ref (owner); dbus_connection_ref (d->owner->conn); - + return TRUE; } @@ -1255,6 +1544,22 @@ bus_service_get_allow_replacement (BusService *service) return owner->allow_replacement; } +#ifdef ENABLE_KDBUS_TRANSPORT +dbus_bool_t +bus_service_get_is_kdbus_starter (BusService *service) +{ + BusOwner *owner; + DBusList *link; + + _dbus_assert (service->owners != NULL); + + link = _dbus_list_get_first_link (&service->owners); + owner = (BusOwner *) link->data; + + return owner->is_kdbus_starter; +} +#endif + dbus_bool_t bus_service_has_owner (BusService *service, DBusConnection *connection) @@ -1289,8 +1594,11 @@ bus_service_list_queued_owners (BusService *service, owner = (BusOwner *) link->data; uname = bus_connection_get_name (owner->conn); - if (!_dbus_list_append (return_list, (char *)uname)) - goto oom; +#ifdef ENABLE_KDBUS_TRANSPORT + if(!owner->is_kdbus_starter) +#endif + if (!_dbus_list_append (return_list, (char *)uname)) + goto oom; link = _dbus_list_get_next_link (&service->owners, link); }