summaryrefslogtreecommitdiff
path: root/bus/policy.c
diff options
context:
space:
mode:
Diffstat (limited to 'bus/policy.c')
-rw-r--r--bus/policy.c929
1 files changed, 485 insertions, 444 deletions
diff --git a/bus/policy.c b/bus/policy.c
index 6f27d1ce..1f3cee8d 100644
--- a/bus/policy.c
+++ b/bus/policy.c
@@ -866,281 +866,296 @@ bus_policy_rule_to_string (BusPolicyRule *rule,
return TRUE;
}
-BusResult
-bus_client_policy_check_can_send (DBusConnection *sender,
- BusClientPolicy *policy,
- BusRegistry *registry,
- dbus_bool_t requested_reply,
- DBusConnection *addressed_recipient,
- DBusConnection *receiver,
- DBusMessage *message,
- dbus_int32_t *toggles,
- dbus_bool_t *log,
- const char **privilege_param,
- BusDeferredMessage **deferred_message,
- char **out_rule)
+static dbus_bool_t
+check_send_rule (const BusPolicyRule *rule,
+ BusRegistry *registry,
+ dbus_bool_t requested_reply,
+ DBusConnection *receiver,
+ DBusMessage *message,
+ BusResult *result,
+ const char **privilege)
{
- DBusList *link;
- BusResult result;
- const char *privilege;
- BusPolicyRule *matched_rule = NULL;
-
- /* policy->rules is in the order the rules appeared
- * in the config file, i.e. last rule that applies wins
+ /* 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");
+ return FALSE;
+ }
- _dbus_verbose (" (policy) checking send rules\n");
- *toggles = 0;
-
- result = BUS_RESULT_FALSE;
- link = _dbus_list_get_first_link (&policy->rules);
- while (link != NULL)
+ if (rule->d.send.message_type != DBUS_MESSAGE_TYPE_INVALID)
{
- BusPolicyRule *rule = link->data;
+ if (dbus_message_get_type (message) != rule->d.send.message_type)
+ {
+ _dbus_verbose (" (policy) skipping rule for different message type\n");
+ return FALSE;
+ }
+ }
- 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 it's a reply, the requested_reply flag kicks in */
+ if (dbus_message_get_reply_serial (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 (rule->type != BUS_POLICY_RULE_SEND)
+ if (!requested_reply && rule->access != BUS_POLICY_RULE_ACCESS_DENY && rule->d.send.requested_reply && !rule->d.send.eavesdrop)
{
- _dbus_verbose (" (policy) skipping non-send rule\n");
- continue;
+ _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");
+ return FALSE;
}
- if (rule->d.send.message_type != DBUS_MESSAGE_TYPE_INVALID)
+ /* 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->access == BUS_POLICY_RULE_ACCESS_DENY && !rule->d.send.requested_reply)
{
- if (dbus_message_get_type (message) != rule->d.send.message_type)
- {
- _dbus_verbose (" (policy) skipping rule for different message type\n");
- continue;
- }
+ _dbus_verbose (" (policy) skipping deny rule since it only applies to unrequested replies\n");
+ return FALSE;
}
+ }
- /* If it's a reply, the requested_reply flag kicks in */
- if (dbus_message_get_reply_serial (message) != 0)
+ if (rule->d.send.path != NULL)
+ {
+ if (dbus_message_get_path (message) != NULL &&
+ strcmp (dbus_message_get_path (message),
+ rule->d.send.path) != 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 (!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");
- 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->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");
- continue;
- }
+ _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). Check rules are meant to be used like allow
+ * rules (they can grant access, but not remove it), so we treat it like
+ * allow here.
+ */
+ dbus_bool_t no_interface;
+
+ no_interface = dbus_message_get_interface (message) == NULL;
- if (rule->d.send.path != NULL)
+ if ((no_interface && rule->access != BUS_POLICY_RULE_ACCESS_DENY) ||
+ (!no_interface &&
+ strcmp (dbus_message_get_interface (message),
+ rule->d.send.interface) != 0))
{
- 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;
- }
+ _dbus_verbose (" (policy) skipping rule for different interface\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). Check rules are meant to be used like allow
- * rules (they can grant access, but not remove it), so we treat it like
- * allow here.
- */
- dbus_bool_t no_interface;
+ }
- no_interface = dbus_message_get_interface (message) == NULL;
-
- if ((no_interface && rule->access != BUS_POLICY_RULE_ACCESS_DENY) ||
- (!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");
+ return FALSE;
}
+ }
- if (rule->d.send.member != NULL)
+ 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)
{
- 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;
- }
+ _dbus_verbose (" (policy) skipping rule for different error name\n");
+ return FALSE;
}
+ }
- if (rule->d.send.error != NULL)
+ 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)
{
- if (dbus_message_get_error_name (message) != NULL &&
- strcmp (dbus_message_get_error_name (message),
- rule->d.send.error) != 0)
+ /* it's a broadcast */
+ if (rule->d.send.broadcast == BUS_POLICY_TRISTATE_FALSE)
{
- _dbus_verbose (" (policy) skipping rule for different error name\n");
- continue;
+ _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.broadcast != BUS_POLICY_TRISTATE_ANY)
+ if (rule->d.send.destination != NULL)
+ {
+ if (!rule->d.send.destination_prefix)
{
- if (dbus_message_get_destination (message) == NULL &&
- dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_SIGNAL)
+ /* 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)
{
- /* it's a broadcast */
- if (rule->d.send.broadcast == BUS_POLICY_TRISTATE_FALSE)
+ if (!dbus_message_has_destination (message,
+ rule->d.send.destination))
{
- _dbus_verbose (" (policy) skipping rule because message is a broadcast\n");
- continue;
+ _dbus_verbose (" (policy) skipping rule because message dest is not %s\n",
+ rule->d.send.destination);
+ return FALSE;
}
}
- /* else it isn't a broadcast: there is some destination */
- else if (rule->d.send.broadcast == BUS_POLICY_TRISTATE_TRUE)
+ else
{
- _dbus_verbose (" (policy) skipping rule because message is not a broadcast\n");
- continue;
- }
- }
+ DBusString str;
+ BusService *service;
- if (rule->d.send.destination != NULL)
- {
- if (!rule->d.send.destination_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)
+ _dbus_string_init_const (&str, rule->d.send.destination);
+
+ service = bus_registry_lookup (registry, &str);
+ if (service == 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;
- }
+ _dbus_verbose (" (policy) skipping rule because dest %s doesn't exist\n",
+ rule->d.send.destination);
+ return FALSE;
}
- else
+
+ if (!bus_service_has_owner (service, receiver))
{
- 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_has_owner (service, receiver))
- {
- _dbus_verbose (" (policy) skipping rule because dest %s isn't owned by receiver\n",
- rule->d.send.destination);
- continue;
- }
+ _dbus_verbose (" (policy) skipping rule because dest %s isn't owned by receiver\n",
+ rule->d.send.destination);
+ return FALSE;
}
}
- else if (rule->d.send.destination_prefix)
+ }
+ else if (rule->d.send.destination_prefix)
+ {
+ /* receiver can be NULL - the same as in !send.destination_prefix */
+ if (receiver == NULL)
{
- /* receiver can be NULL - the same as in !send.destination_prefix */
- if (receiver == NULL)
+ const char *destination = dbus_message_get_destination (message);
+ DBusString dest_name;
+
+ if (destination == 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 start with %s\n",
- rule->d.send.destination);
- continue;
- }
+ _dbus_verbose (" (policy) skipping rule because message has no dest\n");
+ return FALSE;
}
- else
+
+ _dbus_string_init_const (&dest_name, destination);
+
+ if (!_dbus_string_starts_with_words_c_str (&dest_name,
+ rule->d.send.destination,
+ '.'))
{
- if (!bus_connection_is_service_owner_by_prefix (receiver,
- rule->d.send.destination))
- {
- _dbus_verbose (" (policy) skipping rule because no dest with prefix %s is owned by receiver\n",
- rule->d.send.destination);
- continue;
- }
+ _dbus_verbose (" (policy) skipping rule because message dest doesn't start with %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 (message);
-
- if (n_fds < rule->d.send.min_fds || n_fds > rule->d.send.max_fds)
+ else
{
- _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;
+ if (!bus_connection_is_service_owner_by_prefix (receiver,
+ rule->d.send.destination))
+ {
+ _dbus_verbose (" (policy) skipping rule because no dest with prefix %s is owned by receiver\n",
+ rule->d.send.destination);
+ return FALSE;
+ }
}
}
+ }
- /* Use this rule */
- switch (rule->access)
+ 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)
{
- case BUS_POLICY_RULE_ACCESS_ALLOW:
- result = BUS_RESULT_TRUE;
- break;
- case BUS_POLICY_RULE_ACCESS_DENY:
- result = BUS_RESULT_FALSE;
- break;
- case BUS_POLICY_RULE_ACCESS_CHECK:
- result = BUS_RESULT_LATER;
- privilege = rule->privilege;
- break;
+ _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 */
+ switch (rule->access)
+ {
+ case BUS_POLICY_RULE_ACCESS_ALLOW:
+ *result = BUS_RESULT_TRUE;
+ break;
+ case BUS_POLICY_RULE_ACCESS_DENY:
+ *result = BUS_RESULT_FALSE;
+ break;
+ case BUS_POLICY_RULE_ACCESS_CHECK:
+ *result = BUS_RESULT_LATER;
+ *privilege = rule->privilege;
+ break;
+ }
+
+ return TRUE;
+}
+
+BusResult
+bus_client_policy_check_can_send (DBusConnection *sender,
+ BusClientPolicy *policy,
+ BusRegistry *registry,
+ dbus_bool_t requested_reply,
+ DBusConnection *addressed_recipient,
+ DBusConnection *receiver,
+ DBusMessage *message,
+ dbus_int32_t *toggles,
+ dbus_bool_t *log,
+ const char **privilege_param,
+ BusDeferredMessage **deferred_message,
+ char **out_rule)
+{
+ DBusList *link;
+ BusResult result;
+ const char *privilege;
+ BusPolicyRule *matched_rule = 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 send rules\n");
+ *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);
- *log = rule->d.send.log;
- (*toggles)++;
- matched_rule = rule;
+ if (check_send_rule (rule, registry, requested_reply, receiver, message,
+ &result, &privilege))
+ {
+ *log = rule->d.send.log;
+ (*toggles)++;
+ matched_rule = (BusPolicyRule *)rule;
- _dbus_verbose (" (policy) used rule, result now = %d\n",
- result);
+ _dbus_verbose (" (policy) used rule, result now = %d\n",
+ result);
+ }
}
if (result == BUS_RESULT_LATER)
@@ -1169,238 +1184,255 @@ bus_client_policy_check_can_send (DBusConnection *sender,
return result;
}
-/* See docs on what the args mean on bus_context_check_security_policy()
- * comment
- */
-BusResult
-bus_client_policy_check_can_receive (BusClientPolicy *policy,
- BusRegistry *registry,
- dbus_bool_t requested_reply,
- DBusConnection *sender,
- DBusConnection *addressed_recipient,
- DBusConnection *proposed_recipient,
- DBusMessage *message,
- dbus_int32_t *toggles,
- const char **privilege_param,
- BusDeferredMessage **deferred_message,
- char **out_rule)
+static dbus_bool_t
+check_receive_rule (const BusPolicyRule *rule,
+ BusRegistry *registry,
+ dbus_bool_t requested_reply,
+ DBusConnection *sender,
+ DBusMessage *message,
+ dbus_bool_t eavesdropping,
+ BusResult *result,
+ const char **privilege)
{
- DBusList *link;
- dbus_bool_t eavesdropping;
- BusResult result;
- const char *privilege;
- BusPolicyRule *matched_rule = NULL;
+ if (rule->type != BUS_POLICY_RULE_RECEIVE)
+ {
+ _dbus_verbose (" (policy) skipping non-receive rule\n");
+ return FALSE;
+ }
- 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
+ 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");
+ return FALSE;
+ }
+ }
+
+
+ /* for allow or check, eavesdrop=false means the rule doesn't apply when
+ * eavesdropping. eavesdrop=true means the rule always applies
*/
+ if (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");
+ return FALSE;
+ }
- _dbus_verbose (" (policy) checking receive rules, eavesdropping = %d\n", eavesdropping);
- *toggles = 0;
-
- result = BUS_RESULT_FALSE;
- link = _dbus_list_get_first_link (&policy->rules);
- while (link != NULL)
+ /* for deny, eavesdrop=true means the rule applies only when
+ * eavesdropping; eavesdrop=false means always deny.
+ */
+ if (!eavesdropping && rule->access == BUS_POLICY_RULE_ACCESS_DENY && rule->d.receive.eavesdrop)
{
- BusPolicyRule *rule = link->data;
+ _dbus_verbose (" (policy) skipping deny rule since it only applies to eavesdropping\n");
+ return FALSE;
+ }
- link = _dbus_list_get_next_link (&policy->rules, link);
-
- if (rule->type != BUS_POLICY_RULE_RECEIVE)
+ /* If it's a reply, the requested_reply flag kicks in */
+ if (dbus_message_get_reply_serial (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 (!requested_reply && rule->access != BUS_POLICY_RULE_ACCESS_DENY && rule->d.send.requested_reply && !rule->d.send.eavesdrop)
{
- _dbus_verbose (" (policy) skipping non-receive rule\n");
- continue;
+ _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");
+ return FALSE;
}
- if (rule->d.receive.message_type != DBUS_MESSAGE_TYPE_INVALID)
+ /* 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->access == BUS_POLICY_RULE_ACCESS_DENY && !rule->d.receive.requested_reply)
{
- if (dbus_message_get_type (message) != rule->d.receive.message_type)
- {
- _dbus_verbose (" (policy) skipping rule for different message type\n");
- continue;
- }
+ _dbus_verbose (" (policy) skipping deny rule since it only applies to unrequested replies\n");
+ return FALSE;
}
+ }
-
- /* for allow or check, eavesdrop=false means the rule doesn't apply when
- * eavesdropping. eavesdrop=true means the rule always applies
- */
- if (eavesdropping && rule->access != BUS_POLICY_RULE_ACCESS_DENY && !rule->d.receive.eavesdrop)
+ 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 %s rule since it doesn't apply to eavesdropping\n",
- rule->access == BUS_POLICY_RULE_ACCESS_ALLOW ? "allow" : "check");
- continue;
+ _dbus_verbose (" (policy) skipping rule for different path\n");
+ return FALSE;
}
+ }
- /* for deny, eavesdrop=true means the rule applies only when
- * eavesdropping; eavesdrop=false means always deny.
+ 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). Check rules are treated like allow rules.
*/
- if (!eavesdropping && rule->access == BUS_POLICY_RULE_ACCESS_DENY && rule->d.receive.eavesdrop)
+ dbus_bool_t no_interface;
+
+ no_interface = dbus_message_get_interface (message) == NULL;
+
+ if ((no_interface && rule->access != BUS_POLICY_RULE_ACCESS_DENY) ||
+ (!no_interface &&
+ strcmp (dbus_message_get_interface (message),
+ rule->d.receive.interface) != 0))
{
- _dbus_verbose (" (policy) skipping deny rule since it only applies to eavesdropping\n");
- continue;
+ _dbus_verbose (" (policy) skipping rule for different interface\n");
+ return FALSE;
}
+ }
- /* If it's a reply, the requested_reply flag kicks in */
- if (dbus_message_get_reply_serial (message) != 0)
+ if (rule->d.receive.member != NULL)
+ {
+ if (dbus_message_get_member (message) != NULL &&
+ strcmp (dbus_message_get_member (message),
+ rule->d.receive.member) != 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 (!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");
- continue;
- }
+ _dbus_verbose (" (policy) skipping rule for different member\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 (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");
- 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");
+ return FALSE;
}
-
- if (rule->d.receive.path != NULL)
+ }
+
+ 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_get_path (message) != NULL &&
- strcmp (dbus_message_get_path (message),
- rule->d.receive.path) != 0)
+ if (!dbus_message_has_sender (message,
+ rule->d.receive.origin))
{
- _dbus_verbose (" (policy) skipping rule for different path\n");
- continue;
+ _dbus_verbose (" (policy) skipping rule because message sender is not %s\n",
+ rule->d.receive.origin);
+ return FALSE;
}
}
-
- if (rule->d.receive.interface != NULL)
+ else
{
- /* 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). Check rules are treated like allow rules.
- */
- dbus_bool_t no_interface;
+ BusService *service;
+ DBusString str;
- no_interface = dbus_message_get_interface (message) == NULL;
+ _dbus_string_init_const (&str, rule->d.receive.origin);
+
+ service = bus_registry_lookup (registry, &str);
- if ((no_interface && rule->access != BUS_POLICY_RULE_ACCESS_DENY) ||
- (!no_interface &&
- strcmp (dbus_message_get_interface (message),
- rule->d.receive.interface) != 0))
+ if (service == NULL)
{
- _dbus_verbose (" (policy) skipping rule for different interface\n");
- continue;
+ _dbus_verbose (" (policy) skipping rule because origin %s doesn't exist\n",
+ rule->d.receive.origin);
+ return FALSE;
}
- }
- if (rule->d.receive.member != NULL)
- {
- if (dbus_message_get_member (message) != NULL &&
- strcmp (dbus_message_get_member (message),
- rule->d.receive.member) != 0)
+ if (!bus_service_has_owner (service, sender))
{
- _dbus_verbose (" (policy) skipping rule for different member\n");
- continue;
+ _dbus_verbose (" (policy) skipping rule because origin %s isn't owned by sender\n",
+ rule->d.receive.origin);
+ return FALSE;
}
}
+ }
- if (rule->d.receive.error != NULL)
+ 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)
{
- 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;
- }
+ _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;
}
-
- 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;
- }
+ /* Use this rule */
+ switch (rule->access)
+ {
+ case BUS_POLICY_RULE_ACCESS_ALLOW:
+ *result = BUS_RESULT_TRUE;
+ break;
+ case BUS_POLICY_RULE_ACCESS_DENY:
+ *result = BUS_RESULT_FALSE;
+ break;
+ case BUS_POLICY_RULE_ACCESS_CHECK:
+ *result = BUS_RESULT_LATER;
+ *privilege = rule->privilege;
+ break;
+ }
- if (!bus_service_has_owner (service, sender))
- {
- _dbus_verbose (" (policy) skipping rule because origin %s isn't owned by sender\n",
- rule->d.receive.origin);
- continue;
- }
- }
- }
+ return TRUE;
+}
- 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);
+/* See docs on what the args mean on bus_context_check_security_policy()
+ * comment
+ */
+BusResult
+bus_client_policy_check_can_receive (BusClientPolicy *policy,
+ BusRegistry *registry,
+ dbus_bool_t requested_reply,
+ DBusConnection *sender,
+ DBusConnection *addressed_recipient,
+ DBusConnection *proposed_recipient,
+ DBusMessage *message,
+ dbus_int32_t *toggles,
+ const char **privilege_param,
+ BusDeferredMessage **deferred_message,
+ char **out_rule)
+{
+ DBusList *link;
+ dbus_bool_t eavesdropping;
+ BusResult result;
+ const char *privilege;
+ BusPolicyRule *matched_rule = NULL;
- 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;
- }
- }
+ eavesdropping =
+ addressed_recipient != proposed_recipient &&
+ dbus_message_get_destination (message) != NULL;
- /* Use this rule */
- switch (rule->access)
- {
- case BUS_POLICY_RULE_ACCESS_ALLOW:
- result = BUS_RESULT_TRUE;
- break;
- case BUS_POLICY_RULE_ACCESS_DENY:
- result = BUS_RESULT_FALSE;
- break;
- case BUS_POLICY_RULE_ACCESS_CHECK:
- result = BUS_RESULT_LATER;
- privilege = rule->privilege;
- break;
- }
+ /* 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;
- (*toggles)++;
- matched_rule = rule;
+ result = BUS_RESULT_FALSE;
+ link = _dbus_list_get_first_link (&policy->rules);
+ while (link != NULL)
+ {
+ const BusPolicyRule *rule = link->data;
- _dbus_verbose (" (policy) used rule, result now = %d\n",
- result);
+ link = _dbus_list_get_next_link (&policy->rules, link);
+
+ if (check_receive_rule (rule, registry, requested_reply, sender,
+ message, eavesdropping, &result, &privilege))
+ {
+ (*toggles)++;
+ matched_rule = (BusPolicyRule *)rule;
+
+ _dbus_verbose (" (policy) used rule, result now = %d\n",
+ result);
+ }
}
@@ -1430,7 +1462,50 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
return result;
}
+static dbus_bool_t
+check_own_rule (const BusPolicyRule *rule,
+ const DBusString *service_name,
+ BusResult *result,
+ const char **privilege)
+{
+ /* Rule is skipped if it specifies a different service name from
+ * the desired one.
+ */
+
+ if (rule->type != BUS_POLICY_RULE_OWN)
+ return FALSE;
+
+ 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 */
+ switch (rule->access)
+ {
+ case BUS_POLICY_RULE_ACCESS_ALLOW:
+ *result = BUS_RESULT_TRUE;
+ break;
+ case BUS_POLICY_RULE_ACCESS_DENY:
+ *result = BUS_RESULT_FALSE;
+ break;
+ case BUS_POLICY_RULE_ACCESS_CHECK:
+ *result = BUS_RESULT_LATER;
+ *privilege = rule->privilege;
+ break;
+ }
+
+ return TRUE;
+}
static BusResult
bus_rules_check_can_own (DBusList *rules,
@@ -1450,45 +1525,11 @@ bus_rules_check_can_own (DBusList *rules,
link = _dbus_list_get_first_link (&rules);
while (link != NULL)
{
- BusPolicyRule *rule = link->data;
+ const 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 */
- switch (rule->access)
- {
- case BUS_POLICY_RULE_ACCESS_ALLOW:
- result = BUS_RESULT_TRUE;
- break;
- case BUS_POLICY_RULE_ACCESS_DENY:
- result = BUS_RESULT_FALSE;
- break;
- case BUS_POLICY_RULE_ACCESS_CHECK:
- result = BUS_RESULT_LATER;
- privilege = rule->privilege;
- break;
- }
+ check_own_rule (rule, service_name, &result, &privilege);
}
if (result == BUS_RESULT_LATER)