From 22eb17b827ad3de1b2d53e5ca17675edabf44a75 Mon Sep 17 00:00:00 2001 From: Adrian Szyndela Date: Wed, 20 May 2020 15:01:22 +0200 Subject: [PATCH] bus/policy: generalized policy checking process Change-Id: I573ddbc7e64bef38ed7517644bd842728e14679b --- bus/policy.c | 270 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 135 insertions(+), 135 deletions(-) diff --git a/bus/policy.c b/bus/policy.c index 6eb52f2..272adcf 100644 --- a/bus/policy.c +++ b/bus/policy.c @@ -868,18 +868,30 @@ bus_policy_rule_to_string (BusPolicyRule *rule, return TRUE; } -struct MatchSendRuleParams { - BusRegistry *registry; - dbus_bool_t requested_reply; - DBusConnection *receiver; - DBusMessage *message; -}; +typedef struct RuleParams { + enum {PARAM_SR, PARAM_OWN} type; + union { + struct { + BusRegistry *registry; + dbus_bool_t requested_reply; + DBusConnection *peer; + DBusMessage *message; + dbus_bool_t eavesdropping; + } sr; + const DBusString *name; + } u; +} RuleParams; + +typedef dbus_bool_t (*CheckRuleFunc) (const BusPolicyRule *, + const RuleParams *, + BusResult *, + const char **); static dbus_bool_t -check_send_rule (const BusPolicyRule *rule, - const struct MatchSendRuleParams *match_params, - BusResult *result, - const char **privilege) +check_send_rule (const BusPolicyRule *rule, + const RuleParams *match_params, + BusResult *result, + const char **privilege) { /* Rule is skipped if it specifies a different * message name from the message, or a different @@ -893,7 +905,7 @@ check_send_rule (const BusPolicyRule *rule, if (rule->d.send.message_type != DBUS_MESSAGE_TYPE_INVALID) { - if (dbus_message_get_type (match_params->message) != rule->d.send.message_type) + if (dbus_message_get_type (match_params->u.sr.message) != rule->d.send.message_type) { _dbus_verbose (" (policy) skipping rule for different message type\n"); return FALSE; @@ -901,13 +913,13 @@ check_send_rule (const BusPolicyRule *rule, } /* If it's a reply, the requested_reply flag kicks in */ - if (dbus_message_get_reply_serial (match_params->message) != 0) + if (dbus_message_get_reply_serial (match_params->u.sr.message) != 0) { /* for allow or check requested_reply=true means the rule applies * only when reply was requested. requested_reply=false means the * rule always applies */ - if (!match_params->requested_reply && rule->access != BUS_POLICY_RULE_ACCESS_DENY && rule->d.send.requested_reply && !rule->d.send.eavesdrop) + if (!match_params->u.sr.requested_reply && rule->access != BUS_POLICY_RULE_ACCESS_DENY && rule->d.send.requested_reply && !rule->d.send.eavesdrop) { _dbus_verbose (" (policy) skipping %s rule since it only applies to requested replies and does not allow eavesdropping\n", rule->access == BUS_POLICY_RULE_ACCESS_ALLOW ? "allow" : "check"); @@ -918,7 +930,7 @@ check_send_rule (const BusPolicyRule *rule, * when the reply was not requested. requested_reply=true means the * rule always applies. */ - if (match_params->requested_reply && rule->access == BUS_POLICY_RULE_ACCESS_DENY && !rule->d.send.requested_reply) + if (match_params->u.sr.requested_reply && rule->access == BUS_POLICY_RULE_ACCESS_DENY && !rule->d.send.requested_reply) { _dbus_verbose (" (policy) skipping deny rule since it only applies to unrequested replies\n"); return FALSE; @@ -927,8 +939,8 @@ check_send_rule (const BusPolicyRule *rule, if (rule->d.send.path != NULL) { - if (dbus_message_get_path (match_params->message) != NULL && - strcmp (dbus_message_get_path (match_params->message), + if (dbus_message_get_path (match_params->u.sr.message) != NULL && + strcmp (dbus_message_get_path (match_params->u.sr.message), rule->d.send.path) != 0) { _dbus_verbose (" (policy) skipping rule for different path\n"); @@ -947,11 +959,11 @@ check_send_rule (const BusPolicyRule *rule, */ dbus_bool_t no_interface; - no_interface = dbus_message_get_interface (match_params->message) == NULL; - + no_interface = dbus_message_get_interface (match_params->u.sr.message) == NULL; + if ((no_interface && rule->access != BUS_POLICY_RULE_ACCESS_DENY) || (!no_interface && - strcmp (dbus_message_get_interface (match_params->message), + strcmp (dbus_message_get_interface (match_params->u.sr.message), rule->d.send.interface) != 0)) { _dbus_verbose (" (policy) skipping rule for different interface\n"); @@ -961,8 +973,8 @@ check_send_rule (const BusPolicyRule *rule, if (rule->d.send.member != NULL) { - if (dbus_message_get_member (match_params->message) != NULL && - strcmp (dbus_message_get_member (match_params->message), + if (dbus_message_get_member (match_params->u.sr.message) != NULL && + strcmp (dbus_message_get_member (match_params->u.sr.message), rule->d.send.member) != 0) { _dbus_verbose (" (policy) skipping rule for different member\n"); @@ -972,8 +984,8 @@ check_send_rule (const BusPolicyRule *rule, 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), + if (dbus_message_get_error_name (match_params->u.sr.message) != NULL && + strcmp (dbus_message_get_error_name (match_params->u.sr.message), rule->d.send.error) != 0) { _dbus_verbose (" (policy) skipping rule for different error name\n"); @@ -983,8 +995,8 @@ check_send_rule (const BusPolicyRule *rule, 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) + if (dbus_message_get_destination (match_params->u.sr.message) == NULL && + dbus_message_get_type (match_params->u.sr.message) == DBUS_MESSAGE_TYPE_SIGNAL) { /* it's a broadcast */ if (rule->d.send.broadcast == BUS_POLICY_TRISTATE_FALSE) @@ -1015,9 +1027,9 @@ check_send_rule (const BusPolicyRule *rule, * on the assumption that the activated service will have the * requested name and no others. */ - if (match_params->receiver == NULL) + if (match_params->u.sr.peer == NULL) { - if (!dbus_message_has_destination (match_params->message, + if (!dbus_message_has_destination (match_params->u.sr.message, rule->d.send.destination)) { _dbus_verbose (" (policy) skipping rule because message dest is not %s\n", @@ -1032,7 +1044,7 @@ check_send_rule (const BusPolicyRule *rule, _dbus_string_init_const (&str, rule->d.send.destination); - service = bus_registry_lookup (match_params->registry, &str); + service = bus_registry_lookup (match_params->u.sr.registry, &str); if (service == NULL) { _dbus_verbose (" (policy) skipping rule because dest %s doesn't exist\n", @@ -1040,7 +1052,7 @@ check_send_rule (const BusPolicyRule *rule, return FALSE; } - if (!bus_service_has_owner (service, match_params->receiver)) + if (!bus_service_has_owner (service, match_params->u.sr.peer)) { _dbus_verbose (" (policy) skipping rule because dest %s isn't owned by receiver\n", rule->d.send.destination); @@ -1051,9 +1063,9 @@ check_send_rule (const BusPolicyRule *rule, else if (rule->d.send.destination_prefix) { /* receiver can be NULL - the same as in !send.destination_prefix */ - if (match_params->receiver == NULL) + if (match_params->u.sr.peer == NULL) { - const char *destination = dbus_message_get_destination (match_params->message); + const char *destination = dbus_message_get_destination (match_params->u.sr.message); DBusString dest_name; if (destination == NULL) @@ -1075,7 +1087,7 @@ check_send_rule (const BusPolicyRule *rule, } else { - if (!bus_connection_is_service_owner_by_prefix (match_params->receiver, + if (!bus_connection_is_service_owner_by_prefix (match_params->u.sr.peer, rule->d.send.destination)) { _dbus_verbose (" (policy) skipping rule because no dest with prefix %s is owned by receiver\n", @@ -1089,7 +1101,7 @@ check_send_rule (const BusPolicyRule *rule, 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); + unsigned int n_fds = _dbus_message_get_n_unix_fds (match_params->u.sr.message); if (n_fds < rule->d.send.min_fds || n_fds > rule->d.send.max_fds) { @@ -1120,6 +1132,40 @@ check_send_rule (const BusPolicyRule *rule, return TRUE; } +static void +check_rules_list (const DBusList *rules, + CheckRuleFunc check_func, + const RuleParams *params, + dbus_int32_t *toggles, + dbus_bool_t *log, + BusResult *result, + const char **privilege, + BusPolicyRule **matched_rule) +{ + const DBusList *link; + + link = _dbus_list_get_first_link ((DBusList **)&rules); + while (link != NULL) + { + const BusPolicyRule *rule = link->data; + + link = _dbus_list_get_next_link ((DBusList **)&rules, link); + + if (check_func (rule, params, result, privilege)) + { + if (log) + *log = rule->d.send.log; + if (toggles) + (*toggles)++; + if (matched_rule) + *matched_rule = (BusPolicyRule *)rule; + + _dbus_verbose (" (policy) used rule, result now = %d\n", + result); + } + } +} + BusResult bus_client_policy_check_can_send (DBusConnection *sender, BusClientPolicy *policy, @@ -1134,16 +1180,16 @@ bus_client_policy_check_can_send (DBusConnection *sender, BusDeferredMessage **deferred_message, char **out_rule) { - DBusList *link; BusResult result; const char *privilege; BusPolicyRule *matched_rule = NULL; - struct MatchSendRuleParams params; + struct RuleParams params; - params.registry = registry; - params.requested_reply = requested_reply; - params.receiver = receiver; - params.message = message; + params.type = PARAM_SR; + params.u.sr.registry = registry; + params.u.sr.requested_reply = requested_reply; + params.u.sr.peer = receiver; + params.u.sr.message = message; /* policy->rules is in the order the rules appeared * in the config file, i.e. last rule that applies wins @@ -1153,23 +1199,9 @@ bus_client_policy_check_can_send (DBusConnection *sender, *toggles = 0; result = BUS_RESULT_FALSE; - link = _dbus_list_get_first_link (&policy->rules); - while (link != NULL) - { - const BusPolicyRule *rule = link->data; - - link = _dbus_list_get_next_link (&policy->rules, link); - if (check_send_rule (rule, ¶ms, &result, &privilege)) - { - *log = rule->d.send.log; - (*toggles)++; - matched_rule = (BusPolicyRule *)rule; - - _dbus_verbose (" (policy) used rule, result now = %d\n", - result); - } - } + check_rules_list (policy->rules, check_send_rule, ¶ms, + toggles, log, &result, &privilege, &matched_rule); if (result == BUS_RESULT_LATER) { @@ -1197,19 +1229,11 @@ bus_client_policy_check_can_send (DBusConnection *sender, return result; } -struct MatchReceiveRuleParams { - BusRegistry *registry; - dbus_bool_t requested_reply; - DBusConnection *sender; - DBusMessage *message; - dbus_bool_t eavesdropping; -}; - static dbus_bool_t -check_receive_rule (const BusPolicyRule *rule, - const struct MatchReceiveRuleParams *match_params, - BusResult *result, - const char **privilege) +check_receive_rule (const BusPolicyRule *rule, + const RuleParams *match_params, + BusResult *result, + const char **privilege) { if (rule->type != BUS_POLICY_RULE_RECEIVE) { @@ -1219,7 +1243,7 @@ check_receive_rule (const BusPolicyRule *rule, if (rule->d.receive.message_type != DBUS_MESSAGE_TYPE_INVALID) { - if (dbus_message_get_type (match_params->message) != rule->d.receive.message_type) + if (dbus_message_get_type (match_params->u.sr.message) != rule->d.receive.message_type) { _dbus_verbose (" (policy) skipping rule for different message type\n"); return FALSE; @@ -1230,7 +1254,7 @@ check_receive_rule (const BusPolicyRule *rule, /* for allow or check, eavesdrop=false means the rule doesn't apply when * eavesdropping. eavesdrop=true means the rule always applies */ - if (match_params->eavesdropping && rule->access != BUS_POLICY_RULE_ACCESS_DENY && !rule->d.receive.eavesdrop) + if (match_params->u.sr.eavesdropping && rule->access != BUS_POLICY_RULE_ACCESS_DENY && !rule->d.receive.eavesdrop) { _dbus_verbose (" (policy) skipping %s rule since it doesn't apply to eavesdropping\n", rule->access == BUS_POLICY_RULE_ACCESS_ALLOW ? "allow" : "check"); @@ -1240,20 +1264,20 @@ check_receive_rule (const BusPolicyRule *rule, /* for deny, eavesdrop=true means the rule applies only when * eavesdropping; eavesdrop=false means always deny. */ - if (!match_params->eavesdropping && rule->access == BUS_POLICY_RULE_ACCESS_DENY && rule->d.receive.eavesdrop) + if (!match_params->u.sr.eavesdropping && rule->access == BUS_POLICY_RULE_ACCESS_DENY && 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) + if (dbus_message_get_reply_serial (match_params->u.sr.message) != 0) { /* for allow or check requested_reply=true means the rule applies * only when reply was requested. requested_reply=false means the * rule always applies */ - if (!match_params->requested_reply && rule->access != BUS_POLICY_RULE_ACCESS_DENY && rule->d.send.requested_reply && !rule->d.send.eavesdrop) + if (!match_params->u.sr.requested_reply && rule->access != BUS_POLICY_RULE_ACCESS_DENY && rule->d.send.requested_reply && !rule->d.send.eavesdrop) { _dbus_verbose (" (policy) skipping %s rule since it only applies to requested replies and does not allow eavesdropping\n", rule->access == BUS_POLICY_RULE_ACCESS_DENY ? "allow" : "deny"); @@ -1264,7 +1288,7 @@ check_receive_rule (const BusPolicyRule *rule, * when the reply was not requested. requested_reply=true means the * rule always applies. */ - if (match_params->requested_reply && rule->access == BUS_POLICY_RULE_ACCESS_DENY && !rule->d.receive.requested_reply) + if (match_params->u.sr.requested_reply && rule->access == BUS_POLICY_RULE_ACCESS_DENY && !rule->d.receive.requested_reply) { _dbus_verbose (" (policy) skipping deny rule since it only applies to unrequested replies\n"); return FALSE; @@ -1273,8 +1297,8 @@ check_receive_rule (const BusPolicyRule *rule, if (rule->d.receive.path != NULL) { - if (dbus_message_get_path (match_params->message) != NULL && - strcmp (dbus_message_get_path (match_params->message), + if (dbus_message_get_path (match_params->u.sr.message) != NULL && + strcmp (dbus_message_get_path (match_params->u.sr.message), rule->d.receive.path) != 0) { _dbus_verbose (" (policy) skipping rule for different path\n"); @@ -1291,11 +1315,11 @@ check_receive_rule (const BusPolicyRule *rule, */ dbus_bool_t no_interface; - no_interface = dbus_message_get_interface (match_params->message) == NULL; + no_interface = dbus_message_get_interface (match_params->u.sr.message) == NULL; if ((no_interface && rule->access != BUS_POLICY_RULE_ACCESS_DENY) || (!no_interface && - strcmp (dbus_message_get_interface (match_params->message), + strcmp (dbus_message_get_interface (match_params->u.sr.message), rule->d.receive.interface) != 0)) { _dbus_verbose (" (policy) skipping rule for different interface\n"); @@ -1305,8 +1329,8 @@ check_receive_rule (const BusPolicyRule *rule, if (rule->d.receive.member != NULL) { - if (dbus_message_get_member (match_params->message) != NULL && - strcmp (dbus_message_get_member (match_params->message), + if (dbus_message_get_member (match_params->u.sr.message) != NULL && + strcmp (dbus_message_get_member (match_params->u.sr.message), rule->d.receive.member) != 0) { _dbus_verbose (" (policy) skipping rule for different member\n"); @@ -1316,8 +1340,8 @@ check_receive_rule (const BusPolicyRule *rule, 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), + if (dbus_message_get_error_name (match_params->u.sr.message) != NULL && + strcmp (dbus_message_get_error_name (match_params->u.sr.message), rule->d.receive.error) != 0) { _dbus_verbose (" (policy) skipping rule for different error name\n"); @@ -1332,9 +1356,9 @@ check_receive_rule (const BusPolicyRule *rule, * built-in services don't have a DBusConnection but will * still set the sender on their messages. */ - if (match_params->sender == NULL) + if (match_params->u.sr.peer == NULL) { - if (!dbus_message_has_sender (match_params->message, + if (!dbus_message_has_sender (match_params->u.sr.message, rule->d.receive.origin)) { _dbus_verbose (" (policy) skipping rule because message sender is not %s\n", @@ -1349,7 +1373,7 @@ check_receive_rule (const BusPolicyRule *rule, _dbus_string_init_const (&str, rule->d.receive.origin); - service = bus_registry_lookup (match_params->registry, &str); + service = bus_registry_lookup (match_params->u.sr.registry, &str); if (service == NULL) { @@ -1358,7 +1382,7 @@ check_receive_rule (const BusPolicyRule *rule, return FALSE; } - if (!bus_service_has_owner (service, match_params->sender)) + if (!bus_service_has_owner (service, match_params->u.sr.peer)) { _dbus_verbose (" (policy) skipping rule because origin %s isn't owned by sender\n", rule->d.receive.origin); @@ -1370,7 +1394,7 @@ check_receive_rule (const BusPolicyRule *rule, 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); + unsigned int n_fds = _dbus_message_get_n_unix_fds (match_params->u.sr.message); if (n_fds < rule->d.receive.min_fds || n_fds > rule->d.receive.max_fds) { @@ -1418,19 +1442,19 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy, BusDeferredMessage **deferred_message, char **out_rule) { - DBusList *link; BusResult result; const char *privilege; BusPolicyRule *matched_rule = NULL; - struct MatchReceiveRuleParams params; - - params.eavesdropping = + struct RuleParams params; + + params.type = PARAM_SR; + 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; - params.registry = registry; - params.requested_reply = requested_reply; - params.sender = sender; - params.message = message; /* policy->rules is in the order the rules appeared * in the config file, i.e. last rule that applies wins @@ -1440,23 +1464,9 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy, *toggles = 0; result = BUS_RESULT_FALSE; - link = _dbus_list_get_first_link (&policy->rules); - while (link != NULL) - { - const BusPolicyRule *rule = link->data; - - link = _dbus_list_get_next_link (&policy->rules, link); - - if (check_receive_rule (rule, ¶ms, &result, &privilege)) - { - (*toggles)++; - matched_rule = (BusPolicyRule *)rule; - - _dbus_verbose (" (policy) used rule, result now = %d\n", - result); - } - } + check_rules_list (policy->rules, check_receive_rule, ¶ms, + toggles, NULL, &result, &privilege, &matched_rule); if (result == BUS_RESULT_LATER) { @@ -1486,10 +1496,12 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy, static dbus_bool_t check_own_rule (const BusPolicyRule *rule, - const DBusString *service_name, + const RuleParams *params, BusResult *result, const char **privilege) { + const DBusString *service_name = params->u.name; + /* Rule is skipped if it specifies a different service name from * the desired one. */ @@ -1531,30 +1543,27 @@ check_own_rule (const BusPolicyRule *rule, return TRUE; } -static BusResult -bus_rules_check_can_own (DBusList *rules, - const DBusString *service_name, - DBusConnection *connection, - DBusMessage *message) +BusResult +bus_client_policy_check_can_own (BusClientPolicy *policy, + const DBusString *service_name, + DBusConnection *connection, + DBusMessage *message) { - DBusList *link; BusResult result; const char *privilege; + RuleParams params; + + params.type = PARAM_OWN; + params.u.name = service_name; - /* rules is in the order the rules appeared + /* policy->rules is in the order the rules appeared * in the config file, i.e. last rule that applies wins */ result = BUS_RESULT_FALSE; - link = _dbus_list_get_first_link (&rules); - while (link != NULL) - { - const BusPolicyRule *rule = link->data; - link = _dbus_list_get_next_link (&rules, link); - - check_own_rule (rule, service_name, &result, &privilege); - } + check_rules_list (policy->rules, check_own_rule, ¶ms, + NULL, NULL, &result, &privilege, NULL); if (result == BUS_RESULT_LATER) { @@ -1573,15 +1582,6 @@ bus_rules_check_can_own (DBusList *rules, return result; } -BusResult -bus_client_policy_check_can_own (BusClientPolicy *policy, - const DBusString *service_name, - DBusConnection *connection, - DBusMessage *message) -{ - return bus_rules_check_can_own (policy->rules, service_name, connection, message); -} - #ifdef DBUS_ENABLE_EMBEDDED_TESTS dbus_bool_t bus_policy_check_can_own (BusPolicy *policy, -- 2.7.4