X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=bus%2Fbus.c;h=e0f664890c14e5a4b16f932526ce69fe48869fc3;hb=e8d396efef695b9868b0112c4a6266c97678fa8a;hp=3b2ffc0c6328f61c7d220ccda1a82d6c15e74b31;hpb=fff4709be676718a54e280fd3b4ac4b742554982;p=platform%2Fupstream%2Fdbus.git diff --git a/bus/bus.c b/bus/bus.c index 3b2ffc0..e0f6648 100644 --- a/bus/bus.c +++ b/bus/bus.c @@ -43,15 +43,9 @@ struct BusContext BusConnections *connections; BusActivation *activation; BusRegistry *registry; - DBusList *default_rules; /**< Default policy rules */ - DBusList *mandatory_rules; /**< Mandatory policy rules */ - DBusHashTable *rules_by_uid; /**< per-UID policy rules */ - DBusHashTable *rules_by_gid; /**< per-GID policy rules */ - int activation_timeout; /**< How long to wait for an activation to time out */ - int auth_timeout; /**< How long to wait for an authentication to time out */ - int max_completed_connections; /**< Max number of authorized connections */ - int max_incomplete_connections; /**< Max number of incomplete connections */ - int max_connections_per_user; /**< Max number of connections auth'd as same user */ + BusPolicy *policy; + DBusUserDatabase *user_database; + BusLimits limits; }; static int server_data_slot = -1; @@ -124,9 +118,12 @@ server_watch_callback (DBusWatch *watch, unsigned int condition, void *data) { - DBusServer *server = data; - - return dbus_server_handle_watch (server, watch, condition); + /* FIXME this can be done in dbus-mainloop.c + * if the code in activation.c for the babysitter + * watch handler is fixed. + */ + + return dbus_watch_handle (watch, condition); } static dbus_bool_t @@ -209,29 +206,14 @@ new_connection_callback (DBusServer *server, */ dbus_connection_disconnect (new_connection); } - - /* on OOM, we won't have ref'd the connection so it will die. */ -} -static void -free_rule_func (void *data, - void *user_data) -{ - BusPolicyRule *rule = data; + dbus_connection_set_max_received_size (new_connection, + context->limits.max_incoming_bytes); - bus_policy_rule_unref (rule); -} - -static void -free_rule_list_func (void *data) -{ - DBusList **list = data; - - _dbus_list_foreach (list, free_rule_func, NULL); + dbus_connection_set_max_message_size (new_connection, + context->limits.max_message_size); - _dbus_list_clear (list); - - dbus_free (list); + /* on OOM, we won't have ref'd the connection so it will die. */ } static void @@ -368,33 +350,21 @@ bus_context_new (const DBusString *config_file, context->refcount = 1; + /* get our limits and timeout lengths */ + bus_config_parser_get_limits (parser, &context->limits); + /* we need another ref of the server data slot for the context * to own */ if (!server_data_slot_ref ()) _dbus_assert_not_reached ("second ref of server data slot failed"); -#ifdef DBUS_BUILD_TESTS - context->activation_timeout = 6000; /* 6 seconds */ -#else - context->activation_timeout = 15000; /* 15 seconds */ -#endif - - /* Making this long risks making a DOS attack easier, but too short - * and legitimate auth will fail. If interactive auth (ask user for - * password) is allowed, then potentially it has to be quite long. - * Ultimately it needs to come from the configuration file. - */ - context->auth_timeout = 3000; /* 3 seconds */ - - context->max_incomplete_connections = 32; - context->max_connections_per_user = 128; - - /* Note that max_completed_connections / max_connections_per_user - * is the number of users that would have to work together to - * DOS all the other users. - */ - context->max_completed_connections = 1024; + context->user_database = _dbus_user_database_new (); + if (context->user_database == NULL) + { + BUS_SET_OOM (error); + goto failed; + } context->loop = _dbus_loop_new (); if (context->loop == NULL) @@ -565,25 +535,10 @@ bus_context_new (const DBusString *config_file, BUS_SET_OOM (error); goto failed; } - - context->rules_by_uid = _dbus_hash_table_new (DBUS_HASH_ULONG, - NULL, - free_rule_list_func); - if (context->rules_by_uid == NULL) - { - BUS_SET_OOM (error); - goto failed; - } - - context->rules_by_gid = _dbus_hash_table_new (DBUS_HASH_ULONG, - NULL, - free_rule_list_func); - if (context->rules_by_gid == NULL) - { - BUS_SET_OOM (error); - goto failed; - } + context->policy = bus_config_parser_steal_policy (parser); + _dbus_assert (context->policy != NULL); + /* Now become a daemon if appropriate */ if (bus_config_parser_get_fork (parser)) { @@ -744,18 +699,12 @@ bus_context_unref (BusContext *context) } _dbus_list_clear (&context->servers); - if (context->rules_by_uid) - { - _dbus_hash_table_unref (context->rules_by_uid); - context->rules_by_uid = NULL; - } - - if (context->rules_by_gid) + if (context->policy) { - _dbus_hash_table_unref (context->rules_by_gid); - context->rules_by_gid = NULL; + bus_policy_unref (context->policy); + context->policy = NULL; } - + if (context->loop) { _dbus_loop_unref (context->loop); @@ -778,6 +727,8 @@ bus_context_unref (BusContext *context) dbus_free (context->pidfile); } + _dbus_user_database_unref (context->user_database); + dbus_free (context); server_data_slot_unref (); @@ -821,189 +772,196 @@ bus_context_get_loop (BusContext *context) return context->loop; } -static dbus_bool_t -list_allows_user (dbus_bool_t def, - DBusList **list, - unsigned long uid, - const unsigned long *group_ids, - int n_group_ids) +DBusUserDatabase* +bus_context_get_user_database (BusContext *context) { - DBusList *link; - dbus_bool_t allowed; - - allowed = def; - - link = _dbus_list_get_first_link (list); - while (link != NULL) - { - BusPolicyRule *rule = link->data; - link = _dbus_list_get_next_link (list, link); - - if (rule->type == BUS_POLICY_RULE_USER) - { - if (rule->d.user.uid != uid) - continue; - } - else if (rule->type == BUS_POLICY_RULE_GROUP) - { - int i; - - i = 0; - while (i < n_group_ids) - { - if (rule->d.group.gid == group_ids[i]) - break; - ++i; - } - - if (i == n_group_ids) - continue; - } - else - continue; - - allowed = rule->allow; - } - - return allowed; + return context->user_database; } dbus_bool_t bus_context_allow_user (BusContext *context, unsigned long uid) { - dbus_bool_t allowed; - unsigned long *group_ids; - int n_group_ids; - - /* On OOM or error we always reject the user */ - if (!_dbus_get_groups (uid, &group_ids, &n_group_ids)) - { - _dbus_verbose ("Did not get any groups for UID %lu\n", - uid); - return FALSE; - } - - allowed = FALSE; + return bus_policy_allow_user (context->policy, + context->user_database, + uid); +} - allowed = list_allows_user (allowed, - &context->default_rules, - uid, - group_ids, n_group_ids); +BusClientPolicy* +bus_context_create_client_policy (BusContext *context, + DBusConnection *connection, + DBusError *error) +{ + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + return bus_policy_create_client_policy (context->policy, connection, + error); +} - allowed = list_allows_user (allowed, - &context->mandatory_rules, - uid, - group_ids, n_group_ids); +int +bus_context_get_activation_timeout (BusContext *context) +{ + + return context->limits.activation_timeout; +} - dbus_free (group_ids); +int +bus_context_get_auth_timeout (BusContext *context) +{ + return context->limits.auth_timeout; +} - return allowed; +int +bus_context_get_max_completed_connections (BusContext *context) +{ + return context->limits.max_completed_connections; } -static dbus_bool_t -add_list_to_policy (DBusList **list, - BusPolicy *policy) +int +bus_context_get_max_incomplete_connections (BusContext *context) { - DBusList *link; + return context->limits.max_incomplete_connections; +} - link = _dbus_list_get_first_link (list); - while (link != NULL) - { - BusPolicyRule *rule = link->data; - link = _dbus_list_get_next_link (list, link); +int +bus_context_get_max_connections_per_user (BusContext *context) +{ + return context->limits.max_connections_per_user; +} - switch (rule->type) - { - case BUS_POLICY_RULE_USER: - case BUS_POLICY_RULE_GROUP: - /* These aren't per-connection policies */ - break; - - case BUS_POLICY_RULE_OWN: - case BUS_POLICY_RULE_SEND: - case BUS_POLICY_RULE_RECEIVE: - /* These are per-connection */ - if (!bus_policy_append_rule (policy, rule)) - return FALSE; - break; - } - } - - return TRUE; +int +bus_context_get_max_pending_activations (BusContext *context) +{ + return context->limits.max_pending_activations; } -BusPolicy* -bus_context_create_connection_policy (BusContext *context, - DBusConnection *connection) +int +bus_context_get_max_services_per_connection (BusContext *context) { - BusPolicy *policy; - unsigned long uid; - DBusList **list; + return context->limits.max_services_per_connection; +} - _dbus_assert (dbus_connection_get_is_authenticated (connection)); - - policy = bus_policy_new (); - if (policy == NULL) - return NULL; +dbus_bool_t +bus_context_check_security_policy (BusContext *context, + DBusConnection *sender, + DBusConnection *recipient, + DBusMessage *message, + DBusError *error) +{ + BusClientPolicy *sender_policy; + BusClientPolicy *recipient_policy; - if (!add_list_to_policy (&context->default_rules, - policy)) - goto failed; + /* NULL sender/receiver means the bus driver */ - /* we avoid the overhead of looking up user's groups - * if we don't have any group rules anyway - */ - if (_dbus_hash_table_get_n_entries (context->rules_by_gid) > 0) + if (sender != NULL) { - const unsigned long *groups; - int n_groups; - int i; - - if (!bus_connection_get_groups (connection, &groups, &n_groups)) - goto failed; - - i = 0; - while (i < n_groups) + if (bus_connection_is_active (sender)) { - list = _dbus_hash_table_lookup_ulong (context->rules_by_gid, - groups[i]); - - if (list != NULL) + sender_policy = bus_connection_get_policy (sender); + _dbus_assert (sender_policy != NULL); + } + else + { + /* Policy for inactive connections is that they can only send + * the hello message to the bus driver + */ + if (recipient == NULL && + dbus_message_has_name (message, DBUS_MESSAGE_HELLO)) { - if (!add_list_to_policy (list, policy)) - goto failed; + _dbus_verbose ("security check allowing %s message\n", + DBUS_MESSAGE_HELLO); + return TRUE; + } + else + { + _dbus_verbose ("security check disallowing non-%s message\n", + DBUS_MESSAGE_HELLO); + + dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, + "Client tried to send a message other than %s without being registered", + DBUS_MESSAGE_HELLO); + + return FALSE; } - - ++i; } } + else + sender_policy = NULL; - if (!dbus_connection_get_unix_user (connection, &uid)) - goto failed; - - list = _dbus_hash_table_lookup_ulong (context->rules_by_uid, - uid); - - if (!add_list_to_policy (list, policy)) - goto failed; + _dbus_assert ((sender != NULL && sender_policy != NULL) || + (sender == NULL && sender_policy == NULL)); - if (!add_list_to_policy (&context->mandatory_rules, - policy)) - goto failed; + if (recipient != NULL) + { + /* only the bus driver can send to an inactive recipient (as it + * owns no services, so other apps can't address it). Inactive + * recipients can receive any message. + */ + if (bus_connection_is_active (recipient)) + { + recipient_policy = bus_connection_get_policy (recipient); + _dbus_assert (recipient_policy != NULL); + } + else if (sender == NULL) + { + _dbus_verbose ("security check using NULL recipient policy for message from bus\n"); + recipient_policy = NULL; + } + else + { + _dbus_assert_not_reached ("a message was somehow sent to an inactive recipient from a source other than the message bus\n"); + recipient_policy = NULL; + } + } + else + recipient_policy = NULL; + + _dbus_assert ((recipient != NULL && recipient_policy != NULL) || + (recipient != NULL && sender == NULL && recipient_policy == NULL) || + (recipient == NULL && recipient_policy == NULL)); + + if (sender_policy && + !bus_client_policy_check_can_send (sender_policy, + context->registry, recipient, + message)) + { + const char *dest = dbus_message_get_destination (message); + dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, + "A security policy in place prevents this sender " + "from sending this message to this recipient, " + "see message bus configuration file (rejected message " + "had name \"%s\" destination \"%s\")", + dbus_message_get_name (message), + dest ? dest : DBUS_SERVICE_DBUS); + return FALSE; + } - bus_policy_optimize (policy); - - return policy; - - failed: - bus_policy_unref (policy); - return NULL; -} + if (recipient_policy && + !bus_client_policy_check_can_receive (recipient_policy, + context->registry, sender, + message)) + { + const char *dest = dbus_message_get_destination (message); + dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, + "A security policy in place prevents this recipient " + "from receiving this message from this sender, " + "see message bus configuration file (rejected message " + "had name \"%s\" destination \"%s\")", + dbus_message_get_name (message), + dest ? dest : DBUS_SERVICE_DBUS); + return FALSE; + } -int -bus_context_get_activation_timeout (BusContext *context) -{ + /* See if limits on size have been exceeded */ + if (recipient && + dbus_connection_get_outgoing_size (recipient) > + context->limits.max_outgoing_bytes) + { + const char *dest = dbus_message_get_destination (message); + dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, + "The destination service \"%s\" has a full message queue", + dest ? dest : DBUS_SERVICE_DBUS); + return FALSE; + } - return context->activation_timeout; + return TRUE; }