diff --git a/bus/connection.c b/bus/connection.c index f0177c6f..178ac015 100644 --- a/bus/connection.c +++ b/bus/connection.c @@ -1490,6 +1490,15 @@ bus_connection_is_queued_owner_by_prefix (DBusConnection *connection, return FALSE; } +const DBusList * +bus_connection_get_owned_services_list (DBusConnection *connection) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + return d->services_owned; +} + void bus_connection_add_owned_service_link (DBusConnection *connection, DBusList *link) diff --git a/bus/connection.h b/bus/connection.h index 0ce60d11..7f6a3050 100644 --- a/bus/connection.h +++ b/bus/connection.h @@ -87,6 +87,7 @@ void bus_connection_request_headers (DBusConnection *connection, /* called by policy.c */ dbus_bool_t bus_connection_is_queued_owner_by_prefix (DBusConnection *connection, const char *name_prefix); +const DBusList *bus_connection_get_owned_services_list (DBusConnection *connection); /* called by signals.c */ dbus_bool_t bus_connection_add_match_rule (DBusConnection *connection, diff --git a/bus/policy.c b/bus/policy.c index 6ef26a29..ab3344cb 100644 --- a/bus/policy.c +++ b/bus/policy.c @@ -32,6 +32,19 @@ #include #include #include +#include + +struct BusClientPolicy +{ + int refcount; + + BusPolicy *policy; + unsigned long *groups; + int n_groups; + dbus_uid_t uid; + dbus_bool_t uid_set; + dbus_bool_t at_console; +}; BusPolicyRule* bus_policy_rule_new (BusPolicyRuleType type, @@ -139,8 +152,18 @@ struct BusPolicy DBusHashTable *rules_by_gid; /**< per-GID policy rules */ DBusList *at_console_true_rules; /**< console user policy rules where at_console="true"*/ DBusList *at_console_false_rules; /**< console user policy rules where at_console="false"*/ + + DBusHashTable *default_rules_by_name; + DBusList *default_prefix_rules; + unsigned int n_default_rules; }; +typedef struct BusPolicyRulesWithScore +{ + DBusList *rules; + int score; +} BusPolicyRulesWithScore; + static void free_rule_func (void *data, void *user_data) @@ -165,6 +188,21 @@ free_rule_list_func (void *data) dbus_free (list); } +static void +free_rule_list_with_score_func (void *data) +{ + BusPolicyRulesWithScore *rules = data; + + if (rules == NULL) + return; + + _dbus_list_foreach (&rules->rules, free_rule_func, NULL); + + _dbus_list_clear (&rules->rules); + + dbus_free (rules); +} + BusPolicy* bus_policy_new (void) { @@ -188,6 +226,12 @@ bus_policy_new (void) if (policy->rules_by_gid == NULL) goto failed; + policy->default_rules_by_name = _dbus_hash_table_new (DBUS_HASH_STRING, + NULL, + free_rule_list_with_score_func); + if (policy->default_rules_by_name == NULL) + goto failed; + return policy; failed: @@ -237,54 +281,26 @@ bus_policy_unref (BusPolicy *policy) _dbus_hash_table_unref (policy->rules_by_gid); policy->rules_by_gid = NULL; } - + + if (policy->default_rules_by_name) + { + _dbus_hash_table_unref (policy->default_rules_by_name); + policy->default_rules_by_name = NULL; + } + + _dbus_list_foreach (&policy->default_prefix_rules, free_rule_func, NULL); + _dbus_list_clear (&policy->default_prefix_rules); + dbus_free (policy); } } -static dbus_bool_t -add_list_to_client (DBusList **list, - BusClientPolicy *client) -{ - DBusList *link; - - link = _dbus_list_get_first_link (list); - while (link != NULL) - { - BusPolicyRule *rule = link->data; - link = _dbus_list_get_next_link (list, link); - - 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_client_policy_append_rule (client, rule)) - return FALSE; - break; - - default: - _dbus_assert_not_reached ("invalid rule"); - } - } - - return TRUE; -} - BusClientPolicy* bus_policy_create_client_policy (BusPolicy *policy, DBusConnection *connection, DBusError *error) { BusClientPolicy *client; - dbus_uid_t uid; - dbus_bool_t at_console; _dbus_assert (dbus_connection_get_is_authenticated (connection)); _DBUS_ASSERT_ERROR_IS_CLEAR (error); @@ -293,85 +309,23 @@ bus_policy_create_client_policy (BusPolicy *policy, if (client == NULL) goto nomem; - if (!add_list_to_client (&policy->default_rules, - client)) - goto nomem; - - /* 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 (policy->rules_by_gid) > 0) { - unsigned long *groups; - int n_groups; - int i; - - if (!bus_connection_get_unix_groups (connection, &groups, &n_groups, error)) + if (!bus_connection_get_unix_groups (connection, &client->groups, &client->n_groups, error)) goto failed; - - i = 0; - while (i < n_groups) - { - DBusList **list; - - list = _dbus_hash_table_lookup_uintptr (policy->rules_by_gid, - groups[i]); - - if (list != NULL) - { - if (!add_list_to_client (list, client)) - { - dbus_free (groups); - goto nomem; - } - } - - ++i; - } - - dbus_free (groups); } - if (dbus_connection_get_unix_user (connection, &uid)) + if (dbus_connection_get_unix_user (connection, &client->uid)) { - if (_dbus_hash_table_get_n_entries (policy->rules_by_uid) > 0) - { - DBusList **list; - - list = _dbus_hash_table_lookup_uintptr (policy->rules_by_uid, - uid); - - if (list != NULL) - { - if (!add_list_to_client (list, client)) - goto nomem; - } - } - - /* Add console rules */ - at_console = _dbus_unix_user_is_at_console (uid, error); + client->uid_set = TRUE; + client->at_console = _dbus_unix_user_is_at_console (client->uid, error); - if (at_console) - { - if (!add_list_to_client (&policy->at_console_true_rules, client)) - goto nomem; - } - else if (dbus_error_is_set (error) == TRUE) - { + if (dbus_error_is_set (error) == TRUE) goto failed; - } - else if (!add_list_to_client (&policy->at_console_false_rules, client)) - { - goto nomem; - } } - if (!add_list_to_client (&policy->mandatory_rules, - client)) - goto nomem; + client->policy = bus_policy_ref (policy); - bus_client_policy_optimize (client); - return client; nomem: @@ -496,12 +450,94 @@ bus_policy_allow_windows_user (BusPolicy *policy, return _dbus_windows_user_is_process_owner (windows_sid); } +static BusPolicyRulesWithScore * +get_rules_by_string (DBusHashTable *hash, + const char *key) +{ + BusPolicyRulesWithScore *rules; + + rules = _dbus_hash_table_lookup_string (hash, key); + if (rules == NULL) + { + rules = dbus_new0 (BusPolicyRulesWithScore, 1); + if (rules == NULL) + return NULL; + + if (!_dbus_hash_table_insert_string (hash, (char *)key, rules)) + { + dbus_free (rules); + return NULL; + } + } + + return rules; +} + +static const char * +get_name_from_rule (BusPolicyRule *rule) +{ + const char *name = NULL; + if (rule->type == BUS_POLICY_RULE_SEND) + name = rule->d.send.destination; + else if (rule->type == BUS_POLICY_RULE_RECEIVE) + name = rule->d.receive.origin; + else if (rule->type == BUS_POLICY_RULE_OWN) + name = rule->d.own.service_name; + + if (name == NULL) + name = ""; + + return name; +} + +static dbus_bool_t +is_prefix_rule (BusPolicyRule *rule) +{ + if (rule->type == BUS_POLICY_RULE_SEND && rule->d.send.destination_is_prefix) + return TRUE; + if (rule->type == BUS_POLICY_RULE_OWN && rule->d.own.prefix) + return TRUE; + + return FALSE; +} + dbus_bool_t bus_policy_append_default_rule (BusPolicy *policy, BusPolicyRule *rule) { - if (!_dbus_list_append (&policy->default_rules, rule)) - return FALSE; + if (rule->type == BUS_POLICY_RULE_USER || rule->type == BUS_POLICY_RULE_GROUP) + { + if (!_dbus_list_append (&policy->default_rules, rule)) + return FALSE; + } + else + { + rule->score = ++policy->n_default_rules; + + if (is_prefix_rule (rule)) + { + if (!_dbus_list_append (&policy->default_prefix_rules, rule)) + return FALSE; + } + else + { + DBusList **list; + BusPolicyRulesWithScore *rules; + + rules = get_rules_by_string (policy->default_rules_by_name, + get_name_from_rule (rule)); + + if (rules == NULL) + return FALSE; + + list = &rules->rules; + + if (!_dbus_list_prepend (list, rule)) + return FALSE; + + rules->score = rule->score; + } + } bus_policy_rule_ref (rule); @@ -663,6 +699,64 @@ merge_id_hash (DBusHashTable *dest, return TRUE; } +static dbus_bool_t +merge_string_hash (unsigned int *n_rules, + unsigned int n_rules_to_absorb, + DBusHashTable *dest, + DBusHashTable *to_absorb) +{ + DBusHashIter iter; +#ifndef DBUS_DISABLE_ASSERT + unsigned cnt_rules = 0; +#endif + + _dbus_hash_iter_init (to_absorb, &iter); + while (_dbus_hash_iter_next (&iter)) + { + const char *id = _dbus_hash_iter_get_string_key (&iter); + BusPolicyRulesWithScore *to_absorb_rules =_dbus_hash_iter_get_value (&iter); + DBusList **list = &to_absorb_rules->rules; + BusPolicyRulesWithScore *target_rules = get_rules_by_string (dest, id); + DBusList **target; + DBusList *list_iter; + DBusList *target_first_link; + + if (target_rules == NULL) + return FALSE; + + target = &target_rules->rules; + target_first_link = _dbus_list_get_first_link (target); + + list_iter = _dbus_list_get_first_link (list); + while (list_iter != NULL) + { + DBusList *new_link; + BusPolicyRule *rule = list_iter->data; + + rule->score += *n_rules; + list_iter = _dbus_list_get_next_link (list, list_iter); +#ifndef DBUS_DISABLE_ASSERT + cnt_rules++; +#endif + new_link = _dbus_list_alloc_link (rule); + if (new_link == NULL) + return FALSE; + + bus_policy_rule_ref (rule); + + _dbus_list_insert_before_link (target, target_first_link, new_link); + } + + target_rules->score = to_absorb_rules->score + *n_rules; + } + + _dbus_assert (n_rules_to_absorb == cnt_rules); + + *n_rules += n_rules_to_absorb; + + return TRUE; +} + dbus_bool_t bus_policy_merge (BusPolicy *policy, BusPolicy *to_absorb) @@ -695,16 +789,19 @@ bus_policy_merge (BusPolicy *policy, to_absorb->rules_by_gid)) return FALSE; + if (!merge_string_hash (&policy->n_default_rules, + to_absorb->n_default_rules, + policy->default_rules_by_name, + to_absorb->default_rules_by_name)) + return FALSE; + + if (!append_copy_of_policy_list (&policy->default_prefix_rules, + &to_absorb->default_prefix_rules)) + return FALSE; + return TRUE; } -struct BusClientPolicy -{ - int refcount; - - DBusList *rules; -}; - BusClientPolicy* bus_client_policy_new (void) { @@ -729,15 +826,6 @@ bus_client_policy_ref (BusClientPolicy *policy) return policy; } -static void -rule_unref_foreach (void *data, - void *user_data) -{ - BusPolicyRule *rule = data; - - bus_policy_rule_unref (rule); -} - void bus_client_policy_unref (BusClientPolicy *policy) { @@ -747,134 +835,750 @@ bus_client_policy_unref (BusClientPolicy *policy) if (policy->refcount == 0) { - _dbus_list_foreach (&policy->rules, - rule_unref_foreach, - NULL); + if (policy->policy) + bus_policy_unref (policy->policy); - _dbus_list_clear (&policy->rules); + dbus_free (policy->groups); dbus_free (policy); } } -static void -remove_rules_by_type_up_to (BusClientPolicy *policy, - BusPolicyRuleType type, - DBusList *up_to) +typedef struct SendReceiveParams { + BusRegistry *registry; + dbus_bool_t requested_reply; + DBusConnection *peer; + DBusMessage *message; + dbus_bool_t eavesdropping; +} SendReceiveParams; + +typedef struct OwnParams { + const DBusString *name; +} OwnParams; + +typedef struct RuleParams { + enum {PARAMS_OWN, PARAMS_SEND, PARAMS_RECEIVE} type; + union { + SendReceiveParams sr; + OwnParams own; + } u; +} RuleParams; + +static dbus_bool_t +check_send_rule (const BusPolicyRule *rule, + const SendReceiveParams *match_params) { - DBusList *link; - - link = _dbus_list_get_first_link (&policy->rules); - while (link != up_to) + /* Rule is skipped if it specifies a different + * message name from the message, or a different + * destination from the message + */ + if (rule->type != BUS_POLICY_RULE_SEND) { - BusPolicyRule *rule = link->data; - DBusList *next = _dbus_list_get_next_link (&policy->rules, link); - - if (rule->type == type) - { - _dbus_list_remove_link (&policy->rules, link); - bus_policy_rule_unref (rule); - } - - link = next; + _dbus_verbose (" (policy) skipping non-send rule\n"); + return FALSE; } + + if (rule->d.send.message_type != DBUS_MESSAGE_TYPE_INVALID) + { + if (dbus_message_get_type (match_params->message) != rule->d.send.message_type) + { + _dbus_verbose (" (policy) skipping rule for different message type\n"); + return FALSE; + } + } + + /* If it's a reply, the requested_reply flag kicks in */ + if (dbus_message_get_reply_serial (match_params->message) != 0) + { + /* for allow, requested_reply=true means the rule applies + * only when reply was requested. requested_reply=false means + * always allow. + */ + if (!match_params->requested_reply && rule->allow && rule->d.send.requested_reply && !rule->d.send.eavesdrop) + { + _dbus_verbose (" (policy) skipping allow rule since it only applies to requested replies and does not allow eavesdropping\n"); + return FALSE; + } + + /* for deny, requested_reply=false means the rule applies only + * when the reply was not requested. requested_reply=true means the + * rule always applies. + */ + if (match_params->requested_reply && !rule->allow && !rule->d.send.requested_reply) + { + _dbus_verbose (" (policy) skipping deny rule since it only applies to unrequested replies\n"); + return FALSE; + } + } + + if (rule->d.send.path != NULL) + { + if (dbus_message_get_path (match_params->message) != NULL && + strcmp (dbus_message_get_path (match_params->message), + rule->d.send.path) != 0) + { + _dbus_verbose (" (policy) skipping rule for different path\n"); + return FALSE; + } + } + + if (rule->d.send.interface != NULL) + { + /* The interface is optional in messages. For allow rules, if the message + * has no interface we want to skip the rule (and thus not allow); + * for deny rules, if the message has no interface we want to use the + * rule (and thus deny). + */ + dbus_bool_t no_interface; + + no_interface = dbus_message_get_interface (match_params->message) == NULL; + + if ((no_interface && rule->allow) || + (!no_interface && + strcmp (dbus_message_get_interface (match_params->message), + rule->d.send.interface) != 0)) + { + _dbus_verbose (" (policy) skipping rule for different interface\n"); + return FALSE; + } + } + + if (rule->d.send.member != NULL) + { + if (dbus_message_get_member (match_params->message) != NULL && + strcmp (dbus_message_get_member (match_params->message), + rule->d.send.member) != 0) + { + _dbus_verbose (" (policy) skipping rule for different member\n"); + return FALSE; + } + } + + if (rule->d.send.error != NULL) + { + if (dbus_message_get_error_name (match_params->message) != NULL && + strcmp (dbus_message_get_error_name (match_params->message), + rule->d.send.error) != 0) + { + _dbus_verbose (" (policy) skipping rule for different error name\n"); + return FALSE; + } + } + + if (rule->d.send.broadcast != BUS_POLICY_TRISTATE_ANY) + { + if (dbus_message_get_destination (match_params->message) == NULL && + dbus_message_get_type (match_params->message) == DBUS_MESSAGE_TYPE_SIGNAL) + { + /* it's a broadcast */ + if (rule->d.send.broadcast == BUS_POLICY_TRISTATE_FALSE) + { + _dbus_verbose (" (policy) skipping rule because message is a broadcast\n"); + return FALSE; + } + } + /* else it isn't a broadcast: there is some destination */ + else if (rule->d.send.broadcast == BUS_POLICY_TRISTATE_TRUE) + { + _dbus_verbose (" (policy) skipping rule because message is not a broadcast\n"); + return FALSE; + } + } + + if (rule->d.send.destination != NULL && !rule->d.send.destination_is_prefix) + { + /* receiver can be NULL for messages that are sent to the + * message bus itself, we check the strings in that case as + * built-in services don't have a DBusConnection but messages + * to them have a destination service name. + * + * Similarly, receiver can be NULL when we're deciding whether + * activation should be allowed; we make the authorization decision + * on the assumption that the activated service will have the + * requested name and no others. + */ + if (match_params->peer == NULL) + { + if (!dbus_message_has_destination (match_params->message, + rule->d.send.destination)) + { + _dbus_verbose (" (policy) skipping rule because message dest is not %s\n", + rule->d.send.destination); + return FALSE; + } + } + else + { + DBusString str; + BusService *service; + + _dbus_string_init_const (&str, rule->d.send.destination); + + service = bus_registry_lookup (match_params->registry, &str); + if (service == NULL) + { + _dbus_verbose (" (policy) skipping rule because dest %s doesn't exist\n", + rule->d.send.destination); + return FALSE; + } + + if (!bus_service_owner_in_queue (service, match_params->peer)) + { + _dbus_verbose (" (policy) skipping rule because receiver isn't primary or queued owner of name %s\n", + rule->d.send.destination); + return FALSE; + } + } + } + + if (rule->d.send.destination != NULL && rule->d.send.destination_is_prefix) + { + /* receiver can be NULL - the same as in !send.destination_is_prefix */ + if (match_params->peer == NULL) + { + const char *destination = dbus_message_get_destination (match_params->message); + DBusString dest_name; + + if (destination == NULL) + { + _dbus_verbose (" (policy) skipping rule because message has no dest\n"); + return FALSE; + } + + _dbus_string_init_const (&dest_name, destination); + + if (!_dbus_string_starts_with_words_c_str (&dest_name, + rule->d.send.destination, + '.')) + { + _dbus_verbose (" (policy) skipping rule because message dest doesn't have prefix %s\n", + rule->d.send.destination); + return FALSE; + } + } + else + { + if (!bus_connection_is_queued_owner_by_prefix (match_params->peer, + rule->d.send.destination)) + { + _dbus_verbose (" (policy) skipping rule because recipient isn't primary or queued owner of any name below %s\n", + rule->d.send.destination); + return FALSE; + } + } + } + + if (rule->d.send.min_fds > 0 || + rule->d.send.max_fds < DBUS_MAXIMUM_MESSAGE_UNIX_FDS) + { + unsigned int n_fds = _dbus_message_get_n_unix_fds (match_params->message); + + if (n_fds < rule->d.send.min_fds || n_fds > rule->d.send.max_fds) + { + _dbus_verbose (" (policy) skipping rule because message has %u fds " + "and that is outside range [%u,%u]", + n_fds, rule->d.send.min_fds, rule->d.send.max_fds); + return FALSE; + } + } + + /* Use this rule */ + return TRUE; } -void -bus_client_policy_optimize (BusClientPolicy *policy) +static dbus_bool_t +check_receive_rule (const BusPolicyRule *rule, + const SendReceiveParams *match_params) { - DBusList *link; + if (rule->type != BUS_POLICY_RULE_RECEIVE) + { + _dbus_verbose (" (policy) skipping non-receive rule\n"); + return FALSE; + } - /* The idea here is that if we have: - * - * - * - * - * (for example) the deny will always override the allow. So we - * delete the allow. Ditto for deny followed by allow, etc. This is - * a dumb thing to put in a config file, but the feature - * of files allows for an "inheritance and override" pattern where - * it could make sense. If an included file wants to "start over" - * with a blanket deny, no point keeping the rules from the parent - * file. + if (rule->d.receive.message_type != DBUS_MESSAGE_TYPE_INVALID) + { + if (dbus_message_get_type (match_params->message) != rule->d.receive.message_type) + { + _dbus_verbose (" (policy) skipping rule for different message type\n"); + return FALSE; + } + } + + /* for allow, eavesdrop=false means the rule doesn't apply when + * eavesdropping. eavesdrop=true means always allow. + */ + if (match_params->eavesdropping && rule->allow && !rule->d.receive.eavesdrop) + { + _dbus_verbose (" (policy) skipping allow rule since it doesn't apply to eavesdropping\n"); + return FALSE; + } + + /* for deny, eavesdrop=true means the rule applies only when + * eavesdropping; eavesdrop=false means always deny. + */ + if (!match_params->eavesdropping && !rule->allow && rule->d.receive.eavesdrop) + { + _dbus_verbose (" (policy) skipping deny rule since it only applies to eavesdropping\n"); + return FALSE; + } + + /* If it's a reply, the requested_reply flag kicks in */ + if (dbus_message_get_reply_serial (match_params->message) != 0) + { + /* for allow, requested_reply=true means the rule applies + * only when reply was requested. requested_reply=false means + * always allow. + */ + if (!match_params->requested_reply && rule->allow && rule->d.receive.requested_reply && !rule->d.receive.eavesdrop) + { + _dbus_verbose (" (policy) skipping allow rule since it only applies to requested replies and does not allow eavesdropping\n"); + return FALSE; + } + + /* for deny, requested_reply=false means the rule applies only + * when the reply was not requested. requested_reply=true means the + * rule always applies. + */ + if (match_params->requested_reply && !rule->allow && !rule->d.receive.requested_reply) + { + _dbus_verbose (" (policy) skipping deny rule since it only applies to unrequested replies\n"); + return FALSE; + } + } + + if (rule->d.receive.path != NULL) + { + if (dbus_message_get_path (match_params->message) != NULL && + strcmp (dbus_message_get_path (match_params->message), + rule->d.receive.path) != 0) + { + _dbus_verbose (" (policy) skipping rule for different path\n"); + return FALSE; + } + } + + if (rule->d.receive.interface != NULL) + { + /* The interface is optional in messages. For allow rules, if the message + * has no interface we want to skip the rule (and thus not allow); + * for deny rules, if the message has no interface we want to use the + * rule (and thus deny). + */ + dbus_bool_t no_interface; + + no_interface = dbus_message_get_interface (match_params->message) == NULL; + + if ((no_interface && rule->allow) || + (!no_interface && + strcmp (dbus_message_get_interface (match_params->message), + rule->d.receive.interface) != 0)) + { + _dbus_verbose (" (policy) skipping rule for different interface\n"); + return FALSE; + } + } + + if (rule->d.receive.member != NULL) + { + if (dbus_message_get_member (match_params->message) != NULL && + strcmp (dbus_message_get_member (match_params->message), + rule->d.receive.member) != 0) + { + _dbus_verbose (" (policy) skipping rule for different member\n"); + return FALSE; + } + } + + if (rule->d.receive.error != NULL) + { + if (dbus_message_get_error_name (match_params->message) != NULL && + strcmp (dbus_message_get_error_name (match_params->message), + rule->d.receive.error) != 0) + { + _dbus_verbose (" (policy) skipping rule for different error name\n"); + return FALSE; + } + } + + if (rule->d.receive.origin != NULL) + { + /* sender can be NULL for messages that originate from the + * message bus itself, we check the strings in that case as + * built-in services don't have a DBusConnection but will + * still set the sender on their messages. + */ + if (match_params->peer == NULL) + { + if (!dbus_message_has_sender (match_params->message, + rule->d.receive.origin)) + { + _dbus_verbose (" (policy) skipping rule because message sender is not %s\n", + rule->d.receive.origin); + return FALSE; + } + } + else + { + BusService *service; + DBusString str; + + _dbus_string_init_const (&str, rule->d.receive.origin); + + service = bus_registry_lookup (match_params->registry, &str); + + if (service == NULL) + { + _dbus_verbose (" (policy) skipping rule because origin %s doesn't exist\n", + rule->d.receive.origin); + return FALSE; + } + + if (!bus_service_owner_in_queue (service, match_params->peer)) + { + _dbus_verbose (" (policy) skipping rule because sender isn't primary or queued owner of %s\n", + rule->d.receive.origin); + return FALSE; + } + } + } + + if (rule->d.receive.min_fds > 0 || + rule->d.receive.max_fds < DBUS_MAXIMUM_MESSAGE_UNIX_FDS) + { + unsigned int n_fds = _dbus_message_get_n_unix_fds (match_params->message); + + if (n_fds < rule->d.receive.min_fds || n_fds > rule->d.receive.max_fds) + { + _dbus_verbose (" (policy) skipping rule because message has %u fds " + "and that is outside range [%u,%u]", + n_fds, rule->d.receive.min_fds, + rule->d.receive.max_fds); + return FALSE; + } + } + + /* Use this rule */ + return TRUE; +} + +static dbus_bool_t +check_own_rule (const BusPolicyRule *rule, + const OwnParams *params) +{ + const DBusString *service_name = params->name; + + /* Rule is skipped if it specifies a different service name from + * the desired one. */ - _dbus_verbose ("Optimizing policy with %d rules\n", - _dbus_list_get_length (&policy->rules)); - - link = _dbus_list_get_first_link (&policy->rules); - while (link != NULL) - { - BusPolicyRule *rule; - DBusList *next; - dbus_bool_t remove_preceding; - - next = _dbus_list_get_next_link (&policy->rules, link); - rule = link->data; - - remove_preceding = FALSE; - - _dbus_assert (rule != NULL); - - switch (rule->type) - { - case BUS_POLICY_RULE_SEND: - remove_preceding = - rule->d.send.message_type == DBUS_MESSAGE_TYPE_INVALID && - rule->d.send.path == NULL && - rule->d.send.interface == NULL && - rule->d.send.member == NULL && - rule->d.send.error == NULL && - rule->d.send.destination == NULL; - break; - case BUS_POLICY_RULE_RECEIVE: - remove_preceding = - rule->d.receive.message_type == DBUS_MESSAGE_TYPE_INVALID && - rule->d.receive.path == NULL && - rule->d.receive.interface == NULL && - rule->d.receive.member == NULL && - rule->d.receive.error == NULL && - rule->d.receive.origin == NULL; - break; - case BUS_POLICY_RULE_OWN: - remove_preceding = - rule->d.own.service_name == NULL; - break; - - /* The other rule types don't appear in this list */ - case BUS_POLICY_RULE_USER: - case BUS_POLICY_RULE_GROUP: - default: - _dbus_assert_not_reached ("invalid rule"); - break; - } - - if (remove_preceding) - remove_rules_by_type_up_to (policy, rule->type, - link); - - link = next; - } - - _dbus_verbose ("After optimization, policy has %d rules\n", - _dbus_list_get_length (&policy->rules)); -} - -dbus_bool_t -bus_client_policy_append_rule (BusClientPolicy *policy, - BusPolicyRule *rule) -{ - _dbus_verbose ("Appending rule %p with type %d to policy %p\n", - rule, rule->type, policy); - - if (!_dbus_list_append (&policy->rules, rule)) + if (rule->type != BUS_POLICY_RULE_OWN) return FALSE; - bus_policy_rule_ref (rule); + if (!rule->d.own.prefix && rule->d.own.service_name != NULL) + { + if (!_dbus_string_equal_c_str (service_name, + rule->d.own.service_name)) + return FALSE; + } + else if (rule->d.own.prefix) + { + if (!_dbus_string_starts_with_words_c_str (service_name, + rule->d.own.service_name, + '.')) + return FALSE; + } + /* Use this rule */ return TRUE; } +static dbus_bool_t +check_rules_list (const DBusList *rules, + dbus_bool_t allowed_current, + const RuleParams *params, + dbus_int32_t *toggles, + dbus_bool_t *log, + const BusPolicyRule **matched_rule, + dbus_bool_t break_on_first_match) +{ + const DBusList *link; + dbus_bool_t allowed; + + allowed = allowed_current; + + link = _dbus_list_get_first_link ((DBusList **)&rules); + while (link != NULL) + { + const BusPolicyRule *rule = link->data; + dbus_bool_t matches; + + link = _dbus_list_get_next_link ((DBusList **)&rules, link); + + switch (params->type) + { + case PARAMS_OWN: + matches = check_own_rule (rule, ¶ms->u.own); + break; + case PARAMS_SEND: + matches = check_send_rule (rule, ¶ms->u.sr); + break; + case PARAMS_RECEIVE: + matches = check_receive_rule (rule, ¶ms->u.sr); + break; + default: + _dbus_assert_not_reached ("wrong type of policy"); + } + + if (matches) + { + if (log) + *log = rule->d.send.log; + if (toggles) + (*toggles)++; + if (matched_rule) + *matched_rule = rule; + allowed = rule->allow; + + _dbus_verbose (" (policy) used rule, allow now = %d\n", + allowed); + + if (break_on_first_match) + break; + } + } + return allowed; +} + +static int +check_rules_list_with_score (DBusList *rules, + int score, + const RuleParams *params, + dbus_int32_t *toggles, + dbus_bool_t *log, + const BusPolicyRule **matched_rule, + dbus_bool_t break_on_first_match) +{ + dbus_int32_t local_toggles; + dbus_bool_t local_log; + const BusPolicyRule *local_matched_rule; + + local_toggles = 0; + + check_rules_list (rules, + FALSE, + params, + &local_toggles, + &local_log, + &local_matched_rule, + break_on_first_match); + + if (local_toggles > 0) + { + _dbus_assert (local_matched_rule != NULL); + + if (local_matched_rule->score > score) + { + if (toggles) + *toggles += local_toggles; + if (log) + *log = local_log; + if (matched_rule) + *matched_rule = local_matched_rule; + return local_matched_rule->score; + } + } + + return score; +} + +static int +check_rules_for_name (DBusHashTable *rules, + const char *name, + int score, + const RuleParams *params, + dbus_int32_t *toggles, + dbus_bool_t *log, + const BusPolicyRule **matched_rule) +{ + const BusPolicyRulesWithScore *rules_list; + + rules_list = _dbus_hash_table_lookup_string (rules, name); + + if (rules_list == NULL || rules_list->score <= score) + return score; + + return check_rules_list_with_score (rules_list->rules, score, params, toggles, log, matched_rule, TRUE); +} + +static int +find_and_check_rules_for_name (DBusHashTable *rules, + DBusList *prefix_rules, + const char *c_str, + int score, + const RuleParams *params, + dbus_int32_t *toggles, + dbus_bool_t *log, + const BusPolicyRule **matched_rule) +{ + score = check_rules_for_name (rules, c_str, + score, params, + toggles, log, + matched_rule); + + score = check_rules_list_with_score (prefix_rules, + score, params, + toggles, log, + matched_rule, FALSE); + + return score; +} + +static dbus_bool_t +find_and_check_rules (DBusHashTable *rules, + DBusList *prefix_rules, + const RuleParams *params, + dbus_int32_t *toggles, + dbus_bool_t *log) +{ + dbus_bool_t allowed; + const DBusList *services = NULL; + const BusPolicyRule *matched_rule = NULL; + int score = 0; + + allowed = FALSE; + + if (params->type == PARAMS_SEND || params->type == PARAMS_RECEIVE) + { + if (params->u.sr.peer != NULL) + { + DBusList *link; + + services = bus_connection_get_owned_services_list (params->u.sr.peer); + + link = _dbus_list_get_first_link ((DBusList **)&services); + while (link != NULL) + { + const char *name = bus_service_get_name (link->data); + + link = _dbus_list_get_next_link ((DBusList **)&services, link); + + /* skip unique id names */ + if (name[0] == ':') + continue; + + score = find_and_check_rules_for_name (rules, prefix_rules, name, score, + params, toggles, log, &matched_rule); + } + } + else + { + /* NULL peer means dbus-daemon or activation */ + const char *rule_target_name; + + if (params->type == PARAMS_SEND) + rule_target_name = dbus_message_get_destination (params->u.sr.message); + else if (params->type == PARAMS_RECEIVE) + rule_target_name = dbus_message_get_sender (params->u.sr.message); + + if (rule_target_name != NULL) + score = find_and_check_rules_for_name (rules, prefix_rules, rule_target_name, score, + params, toggles, log, &matched_rule); + } + } + else + score = find_and_check_rules_for_name (rules, prefix_rules, _dbus_string_get_const_data(params->u.own.name), + score, params, toggles, log, &matched_rule); + + /* check also wildcard rules */ + check_rules_for_name (rules, "", score, params, toggles, log, &matched_rule); + + if (matched_rule) + allowed = matched_rule->allow; + + return allowed; +} + +static dbus_bool_t +check_policy (BusClientPolicy *policy, + const RuleParams *params, + dbus_int32_t *toggles, + dbus_bool_t *log) +{ + dbus_bool_t allowed; + + if (toggles) + *toggles = 0; + + allowed = find_and_check_rules (policy->policy->default_rules_by_name, + policy->policy->default_prefix_rules, + params, + toggles, + log); + + _dbus_verbose("checked, allow now = %d\n", allowed); + + /* 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 (policy->policy->rules_by_gid) > 0) + { + int i; + + for (i = 0; i < policy->n_groups; ++i) + { + const DBusList **list; + + list = _dbus_hash_table_lookup_uintptr (policy->policy->rules_by_gid, + policy->groups[i]); + + if (list != NULL) + allowed = check_rules_list (*list, allowed, params, toggles, log, NULL, FALSE); + } + } + + if (policy->uid_set) + { + if (_dbus_hash_table_get_n_entries (policy->policy->rules_by_uid) > 0) + { + const DBusList **list; + + list = _dbus_hash_table_lookup_uintptr (policy->policy->rules_by_uid, + policy->uid); + + if (list != NULL) + allowed = check_rules_list (*list, allowed, params, toggles, log, NULL, FALSE); + + if (policy->at_console) + allowed = check_rules_list (policy->policy->at_console_true_rules, + allowed, + params, + toggles, + log, + NULL, + FALSE); + else + allowed = check_rules_list (policy->policy->at_console_false_rules, + allowed, + params, + toggles, + log, + NULL, + FALSE); + } + } + + allowed = check_rules_list (policy->policy->mandatory_rules, + allowed, + params, + toggles, + log, + NULL, + FALSE); + + return allowed; +} + dbus_bool_t bus_client_policy_check_can_send (BusClientPolicy *policy, BusRegistry *registry, @@ -884,249 +1588,17 @@ bus_client_policy_check_can_send (BusClientPolicy *policy, dbus_int32_t *toggles, dbus_bool_t *log) { - DBusList *link; - dbus_bool_t allowed; - - /* policy->rules is in the order the rules appeared - * in the config file, i.e. last rule that applies wins - */ + struct RuleParams params; + + params.type = PARAMS_SEND; + params.u.sr.registry = registry; + params.u.sr.requested_reply = requested_reply; + params.u.sr.peer = receiver; + params.u.sr.message = message; _dbus_verbose (" (policy) checking send rules\n"); - *toggles = 0; - - allowed = FALSE; - link = _dbus_list_get_first_link (&policy->rules); - while (link != NULL) - { - BusPolicyRule *rule = link->data; - link = _dbus_list_get_next_link (&policy->rules, link); - - /* Rule is skipped if it specifies a different - * message name from the message, or a different - * destination from the message - */ - - if (rule->type != BUS_POLICY_RULE_SEND) - { - _dbus_verbose (" (policy) skipping non-send rule\n"); - continue; - } - - if (rule->d.send.message_type != DBUS_MESSAGE_TYPE_INVALID) - { - if (dbus_message_get_type (message) != rule->d.send.message_type) - { - _dbus_verbose (" (policy) skipping rule for different message type\n"); - continue; - } - } - - /* If it's a reply, the requested_reply flag kicks in */ - if (dbus_message_get_reply_serial (message) != 0) - { - /* for allow, requested_reply=true means the rule applies - * only when reply was requested. requested_reply=false means - * always allow. - */ - if (!requested_reply && rule->allow && rule->d.send.requested_reply && !rule->d.send.eavesdrop) - { - _dbus_verbose (" (policy) skipping allow rule since it only applies to requested replies and does not allow eavesdropping\n"); - continue; - } - - /* for deny, requested_reply=false means the rule applies only - * when the reply was not requested. requested_reply=true means the - * rule always applies. - */ - if (requested_reply && !rule->allow && !rule->d.send.requested_reply) - { - _dbus_verbose (" (policy) skipping deny rule since it only applies to unrequested replies\n"); - continue; - } - } - - if (rule->d.send.path != NULL) - { - if (dbus_message_get_path (message) != NULL && - strcmp (dbus_message_get_path (message), - rule->d.send.path) != 0) - { - _dbus_verbose (" (policy) skipping rule for different path\n"); - continue; - } - } - - if (rule->d.send.interface != NULL) - { - /* The interface is optional in messages. For allow rules, if the message - * has no interface we want to skip the rule (and thus not allow); - * for deny rules, if the message has no interface we want to use the - * rule (and thus deny). - */ - dbus_bool_t no_interface; - - no_interface = dbus_message_get_interface (message) == NULL; - - if ((no_interface && rule->allow) || - (!no_interface && - strcmp (dbus_message_get_interface (message), - rule->d.send.interface) != 0)) - { - _dbus_verbose (" (policy) skipping rule for different interface\n"); - continue; - } - } - - if (rule->d.send.member != NULL) - { - if (dbus_message_get_member (message) != NULL && - strcmp (dbus_message_get_member (message), - rule->d.send.member) != 0) - { - _dbus_verbose (" (policy) skipping rule for different member\n"); - continue; - } - } - - if (rule->d.send.error != NULL) - { - if (dbus_message_get_error_name (message) != NULL && - strcmp (dbus_message_get_error_name (message), - rule->d.send.error) != 0) - { - _dbus_verbose (" (policy) skipping rule for different error name\n"); - continue; - } - } - - if (rule->d.send.broadcast != BUS_POLICY_TRISTATE_ANY) - { - if (dbus_message_get_destination (message) == NULL && - dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_SIGNAL) - { - /* it's a broadcast */ - if (rule->d.send.broadcast == BUS_POLICY_TRISTATE_FALSE) - { - _dbus_verbose (" (policy) skipping rule because message is a broadcast\n"); - continue; - } - } - /* else it isn't a broadcast: there is some destination */ - else if (rule->d.send.broadcast == BUS_POLICY_TRISTATE_TRUE) - { - _dbus_verbose (" (policy) skipping rule because message is not a broadcast\n"); - continue; - } - } - - if (rule->d.send.destination != NULL && !rule->d.send.destination_is_prefix) - { - /* receiver can be NULL for messages that are sent to the - * message bus itself, we check the strings in that case as - * built-in services don't have a DBusConnection but messages - * to them have a destination service name. - * - * Similarly, receiver can be NULL when we're deciding whether - * activation should be allowed; we make the authorization decision - * on the assumption that the activated service will have the - * requested name and no others. - */ - if (receiver == NULL) - { - if (!dbus_message_has_destination (message, - rule->d.send.destination)) - { - _dbus_verbose (" (policy) skipping rule because message dest is not %s\n", - rule->d.send.destination); - continue; - } - } - else - { - DBusString str; - BusService *service; - - _dbus_string_init_const (&str, rule->d.send.destination); - - service = bus_registry_lookup (registry, &str); - if (service == NULL) - { - _dbus_verbose (" (policy) skipping rule because dest %s doesn't exist\n", - rule->d.send.destination); - continue; - } - - if (!bus_service_owner_in_queue (service, receiver)) - { - _dbus_verbose (" (policy) skipping rule because receiver isn't primary or queued owner of name %s\n", - rule->d.send.destination); - continue; - } - } - } - - if (rule->d.send.destination != NULL && rule->d.send.destination_is_prefix) - { - /* receiver can be NULL - the same as in !send.destination_is_prefix */ - if (receiver == NULL) - { - const char *destination = dbus_message_get_destination (message); - DBusString dest_name; - - if (destination == NULL) - { - _dbus_verbose (" (policy) skipping rule because message has no dest\n"); - continue; - } - - _dbus_string_init_const (&dest_name, destination); - - if (!_dbus_string_starts_with_words_c_str (&dest_name, - rule->d.send.destination, - '.')) - { - _dbus_verbose (" (policy) skipping rule because message dest doesn't have prefix %s\n", - rule->d.send.destination); - continue; - } - } - else - { - if (!bus_connection_is_queued_owner_by_prefix (receiver, - rule->d.send.destination)) - { - _dbus_verbose (" (policy) skipping rule because recipient isn't primary or queued owner of any name below %s\n", - rule->d.send.destination); - continue; - } - } - } - - if (rule->d.send.min_fds > 0 || - rule->d.send.max_fds < DBUS_MAXIMUM_MESSAGE_UNIX_FDS) - { - unsigned int n_fds = _dbus_message_get_n_unix_fds (message); - - if (n_fds < rule->d.send.min_fds || n_fds > rule->d.send.max_fds) - { - _dbus_verbose (" (policy) skipping rule because message has %u fds " - "and that is outside range [%u,%u]", - n_fds, rule->d.send.min_fds, rule->d.send.max_fds); - continue; - } - } - - /* Use this rule */ - allowed = rule->allow; - *log = rule->d.send.log; - (*toggles)++; - - _dbus_verbose (" (policy) used rule, allow now = %d\n", - allowed); - } - - return allowed; + return check_policy (policy, ¶ms, toggles, log); } /* See docs on what the args mean on bus_context_check_security_policy() @@ -1142,262 +1614,31 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy, DBusMessage *message, dbus_int32_t *toggles) { - DBusList *link; - dbus_bool_t allowed; - dbus_bool_t eavesdropping; + struct RuleParams params; - eavesdropping = + params.type = PARAMS_RECEIVE; + params.u.sr.registry = registry; + params.u.sr.requested_reply = requested_reply; + params.u.sr.peer = sender; + params.u.sr.message = message; + params.u.sr.eavesdropping = addressed_recipient != proposed_recipient && dbus_message_get_destination (message) != NULL; - - /* policy->rules is in the order the rules appeared - * in the config file, i.e. last rule that applies wins - */ - _dbus_verbose (" (policy) checking receive rules, eavesdropping = %d\n", eavesdropping); - *toggles = 0; - - allowed = FALSE; - link = _dbus_list_get_first_link (&policy->rules); - while (link != NULL) - { - BusPolicyRule *rule = link->data; + _dbus_verbose (" (policy) checking receive rules, eavesdropping = %d\n", params.u.sr.eavesdropping); - link = _dbus_list_get_next_link (&policy->rules, link); - - if (rule->type != BUS_POLICY_RULE_RECEIVE) - { - _dbus_verbose (" (policy) skipping non-receive rule\n"); - continue; - } - - if (rule->d.receive.message_type != DBUS_MESSAGE_TYPE_INVALID) - { - if (dbus_message_get_type (message) != rule->d.receive.message_type) - { - _dbus_verbose (" (policy) skipping rule for different message type\n"); - continue; - } - } - - /* for allow, eavesdrop=false means the rule doesn't apply when - * eavesdropping. eavesdrop=true means always allow. - */ - if (eavesdropping && rule->allow && !rule->d.receive.eavesdrop) - { - _dbus_verbose (" (policy) skipping allow rule since it doesn't apply to eavesdropping\n"); - continue; - } - - /* for deny, eavesdrop=true means the rule applies only when - * eavesdropping; eavesdrop=false means always deny. - */ - if (!eavesdropping && !rule->allow && rule->d.receive.eavesdrop) - { - _dbus_verbose (" (policy) skipping deny rule since it only applies to eavesdropping\n"); - continue; - } - - /* If it's a reply, the requested_reply flag kicks in */ - if (dbus_message_get_reply_serial (message) != 0) - { - /* for allow, requested_reply=true means the rule applies - * only when reply was requested. requested_reply=false means - * always allow. - */ - if (!requested_reply && rule->allow && rule->d.receive.requested_reply && !rule->d.receive.eavesdrop) - { - _dbus_verbose (" (policy) skipping allow rule since it only applies to requested replies and does not allow eavesdropping\n"); - continue; - } - - /* for deny, requested_reply=false means the rule applies only - * when the reply was not requested. requested_reply=true means the - * rule always applies. - */ - if (requested_reply && !rule->allow && !rule->d.receive.requested_reply) - { - _dbus_verbose (" (policy) skipping deny rule since it only applies to unrequested replies\n"); - continue; - } - } - - if (rule->d.receive.path != NULL) - { - if (dbus_message_get_path (message) != NULL && - strcmp (dbus_message_get_path (message), - rule->d.receive.path) != 0) - { - _dbus_verbose (" (policy) skipping rule for different path\n"); - continue; - } - } - - if (rule->d.receive.interface != NULL) - { - /* The interface is optional in messages. For allow rules, if the message - * has no interface we want to skip the rule (and thus not allow); - * for deny rules, if the message has no interface we want to use the - * rule (and thus deny). - */ - dbus_bool_t no_interface; - - no_interface = dbus_message_get_interface (message) == NULL; - - if ((no_interface && rule->allow) || - (!no_interface && - strcmp (dbus_message_get_interface (message), - rule->d.receive.interface) != 0)) - { - _dbus_verbose (" (policy) skipping rule for different interface\n"); - continue; - } - } - - if (rule->d.receive.member != NULL) - { - if (dbus_message_get_member (message) != NULL && - strcmp (dbus_message_get_member (message), - rule->d.receive.member) != 0) - { - _dbus_verbose (" (policy) skipping rule for different member\n"); - continue; - } - } - - if (rule->d.receive.error != NULL) - { - if (dbus_message_get_error_name (message) != NULL && - strcmp (dbus_message_get_error_name (message), - rule->d.receive.error) != 0) - { - _dbus_verbose (" (policy) skipping rule for different error name\n"); - continue; - } - } - - if (rule->d.receive.origin != NULL) - { - /* sender can be NULL for messages that originate from the - * message bus itself, we check the strings in that case as - * built-in services don't have a DBusConnection but will - * still set the sender on their messages. - */ - if (sender == NULL) - { - if (!dbus_message_has_sender (message, - rule->d.receive.origin)) - { - _dbus_verbose (" (policy) skipping rule because message sender is not %s\n", - rule->d.receive.origin); - continue; - } - } - else - { - BusService *service; - DBusString str; - - _dbus_string_init_const (&str, rule->d.receive.origin); - - service = bus_registry_lookup (registry, &str); - - if (service == NULL) - { - _dbus_verbose (" (policy) skipping rule because origin %s doesn't exist\n", - rule->d.receive.origin); - continue; - } - - if (!bus_service_owner_in_queue (service, sender)) - { - _dbus_verbose (" (policy) skipping rule because sender isn't primary or queued owner of %s\n", - rule->d.receive.origin); - continue; - } - } - } - - if (rule->d.receive.min_fds > 0 || - rule->d.receive.max_fds < DBUS_MAXIMUM_MESSAGE_UNIX_FDS) - { - unsigned int n_fds = _dbus_message_get_n_unix_fds (message); - - if (n_fds < rule->d.receive.min_fds || n_fds > rule->d.receive.max_fds) - { - _dbus_verbose (" (policy) skipping rule because message has %u fds " - "and that is outside range [%u,%u]", - n_fds, rule->d.receive.min_fds, - rule->d.receive.max_fds); - continue; - } - } - - /* Use this rule */ - allowed = rule->allow; - (*toggles)++; - - _dbus_verbose (" (policy) used rule, allow now = %d\n", - allowed); - } - - return allowed; -} - - - -static dbus_bool_t -bus_rules_check_can_own (DBusList *rules, - const DBusString *service_name) -{ - DBusList *link; - dbus_bool_t allowed; - - /* rules is in the order the rules appeared - * in the config file, i.e. last rule that applies wins - */ - - allowed = FALSE; - link = _dbus_list_get_first_link (&rules); - while (link != NULL) - { - BusPolicyRule *rule = link->data; - - link = _dbus_list_get_next_link (&rules, link); - - /* Rule is skipped if it specifies a different service name from - * the desired one. - */ - - if (rule->type != BUS_POLICY_RULE_OWN) - continue; - - if (!rule->d.own.prefix && rule->d.own.service_name != NULL) - { - if (!_dbus_string_equal_c_str (service_name, - rule->d.own.service_name)) - continue; - } - else if (rule->d.own.prefix) - { - if (!_dbus_string_starts_with_words_c_str (service_name, - rule->d.own.service_name, - '.')) - continue; - } - - /* Use this rule */ - allowed = rule->allow; - } - - return allowed; + return check_policy (policy, ¶ms, toggles, NULL); } dbus_bool_t bus_client_policy_check_can_own (BusClientPolicy *policy, const DBusString *service_name) { - return bus_rules_check_can_own (policy->rules, service_name); + RuleParams params; + params.type = PARAMS_OWN; + params.u.own.name = service_name; + + return check_policy (policy, ¶ms, NULL, NULL); } #ifdef DBUS_ENABLE_EMBEDDED_TESTS @@ -1405,6 +1646,14 @@ dbus_bool_t bus_policy_check_can_own (BusPolicy *policy, const DBusString *service_name) { - return bus_rules_check_can_own (policy->default_rules, service_name); + RuleParams params; + params.type = PARAMS_OWN; + params.u.own.name = service_name; + + return find_and_check_rules (policy->default_rules_by_name, + policy->default_prefix_rules, + ¶ms, + NULL, + NULL); } #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ diff --git a/bus/policy.h b/bus/policy.h index 482f5fe4..06c80c34 100644 --- a/bus/policy.h +++ b/bus/policy.h @@ -59,7 +59,8 @@ struct BusPolicyRule BusPolicyRuleType type; unsigned int allow : 1; /**< #TRUE if this allows, #FALSE if it denies */ - + unsigned int score : 20; /**< for keeping the importance of the rule */ + union { struct @@ -172,9 +173,6 @@ dbus_bool_t bus_client_policy_check_can_receive (BusClientPolicy *policy, dbus_int32_t *toggles); dbus_bool_t bus_client_policy_check_can_own (BusClientPolicy *policy, const DBusString *service_name); -dbus_bool_t bus_client_policy_append_rule (BusClientPolicy *policy, - BusPolicyRule *rule); -void bus_client_policy_optimize (BusClientPolicy *policy); #ifdef DBUS_ENABLE_EMBEDDED_TESTS dbus_bool_t bus_policy_check_can_own (BusPolicy *policy,