X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=bus%2Fservices.c;h=90a2f5f18cd556c9e695b06a093ee075c47d8fe7;hb=c1a77d2c58c78abc606f1cb7918704596ebf2bfe;hp=68a7022ac9f1bfb019b4bd147224b6d59a1f1ce4;hpb=818e62f15f30f284f4cfddf5725972975b97ce52;p=platform%2Fupstream%2Fdbus.git diff --git a/bus/services.c b/bus/services.c index 68a7022..90a2f5f 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,7 +28,6 @@ #include #include #include - #include "driver.h" #include "services.h" #include "connection.h" @@ -37,6 +37,18 @@ #include "bus.h" #include "selinux.h" +#ifdef ENABLE_KDBUS_TRANSPORT +#include +#include +#include +#include +#include + +#include "kdbus-d.h" +#include "dbus/kdbus.h" +#include "dbus/kdbus-common.h" +#endif + struct BusService { int refcount; @@ -55,6 +67,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 +187,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 +220,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_NAME) != FALSE; +#endif } static BusOwner * @@ -310,7 +354,7 @@ bus_registry_ensure (BusRegistry *registry, BUS_SET_OOM (error); return NULL; } - + return service; } @@ -368,7 +412,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,164 +481,310 @@ 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; - } - - if (!bus_client_policy_check_can_own (policy, connection, - 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 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; - } - + 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; + const char* conn_unique_name; + DBusConnection* phantom; + unsigned long int uid; + + 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", 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"); + + return FALSE; } - 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\"", name); + + _dbus_verbose ("Attempt to acquire invalid base service name \"%s\"", name); + + return FALSE; } - else + + conn_unique_name = dbus_message_get_sender(message); + + 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", + conn_unique_name, DBUS_SERVICE_DBUS); + return FALSE; + } - /* 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; + sender_id = sender_name_to_id(conn_unique_name, error); + if(dbus_error_is_set(error)) + return FALSE; + + phantom = bus_connections_find_conn_by_name(bus_connection_get_connections(connection), conn_unique_name); + if(phantom == NULL) + { + phantom = create_phantom_connection(connection, conn_unique_name, error); + if(phantom == NULL) + return FALSE; + } + + if (!bus_client_policy_check_can_own (bus_connection_get_policy (phantom), 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", conn_unique_name, name); + goto failed; + } + + if (!kdbus_connection_get_unix_user(phantom, conn_unique_name, &uid, NULL)) + goto failed; + +#ifdef POLICY_TO_KDBUS + if (!register_kdbus_policy(name, dbus_connection_get_transport(phantom), uid)) + { + dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, + "Kdbus error when setting policy for connection \"%s\" and service name \"%s\"", + conn_unique_name, name); + goto failed; + } +#endif + + *result = kdbus_request_name(connection, service_name, flags, sender_id); + if(*result == -EPERM) + { + dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, + "Kdbus not allowed %s to own the service \"%s\"", + conn_unique_name, _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 (primary_owner->do_not_queue) + if((*result == DBUS_REQUEST_NAME_REPLY_IN_QUEUE) || (*result == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)) + { + service = bus_registry_lookup (registry, service_name); + if (service == NULL) { - if (!bus_service_remove_owner (service, old_owner_conn, - transaction, error)) - goto out; + service = bus_registry_ensure (registry, service_name, phantom, flags, + transaction, error); + if (service == NULL) + goto failed2; } else { - if (!bus_service_swap_owner (service, old_owner_conn, - transaction, error)) - goto out; + if (!bus_service_add_owner (service, phantom, flags, transaction, error)) + goto failed2; } - - - _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); } + else + retval = TRUE; - activation = bus_context_get_activation (registry->context); - retval = bus_activation_send_pending_auto_activation_messages (activation, - service, - transaction, - error); - - out: return retval; + +failed2: + kdbus_release_name(phantom, service_name, sender_id); +failed: + bus_connection_disconnected(phantom); + + return FALSE; } +#endif dbus_bool_t bus_registry_release_service (BusRegistry *registry, @@ -673,6 +863,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) @@ -801,7 +1080,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; } @@ -1221,13 +1500,29 @@ DBusConnection * bus_service_get_primary_owners_connection (BusService *service) { BusOwner *owner; +#ifdef ENABLE_KDBUS_TRANSPORT + char unique_name[(unsigned int)(snprintf((char*)NULL, 0, "%llu", ULLONG_MAX) + sizeof(":1."))]; +#endif owner = bus_service_get_primary_owner (service); +#ifdef ENABLE_KDBUS_TRANSPORT + if(!owner) + return NULL; + if(bus_context_is_kdbus(service->registry->context)) + { + if(kdbus_get_name_owner(owner->conn, bus_service_get_name(service), unique_name) < 0) + return NULL; + return _bus_service_find_owner_connection(service, unique_name); //bus_connections_find_conn_by_name would be safer? but slower + } + else + return owner->conn; +#else if (owner != NULL) return owner->conn; else return NULL; +#endif } BusOwner* @@ -1256,6 +1551,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) @@ -1290,8 +1601,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); }