diff options
-rw-r--r-- | ChangeLog | 13 | ||||
-rw-r--r-- | bus/Makefile.am | 2 | ||||
-rw-r--r-- | bus/connection.c | 17 | ||||
-rw-r--r-- | bus/policy.c | 254 | ||||
-rw-r--r-- | bus/policy.h | 31 | ||||
-rw-r--r-- | dbus/dbus-message.c | 61 | ||||
-rw-r--r-- | dbus/dbus-message.h | 4 |
7 files changed, 357 insertions, 25 deletions
@@ -1,3 +1,16 @@ +2003-03-20 Havoc Pennington <hp@pobox.com> + + * bus/connection.c (bus_connection_send_oom_error): assert that + message has a sender + (connection_execute_transaction): ditto + (bus_connection_preallocate_oom_error): fix to set the sender, and + set recipient to the destination service, not the bus driver + + * bus/policy.c: hacking + + * dbus/dbus-message.c (dbus_message_service_is): new function + (dbus_message_sender_is): new + 2003-03-19 Havoc Pennington <hp@redhat.com> * bus/policy.c: start sketching code for policy restrictions on diff --git a/bus/Makefile.am b/bus/Makefile.am index aee6e37a..bc64032c 100644 --- a/bus/Makefile.am +++ b/bus/Makefile.am @@ -21,6 +21,8 @@ BUS_SOURCES= \ driver.h \ loop.c \ loop.h \ + policy.c \ + policy.h \ services.c \ services.h \ test.c \ diff --git a/bus/connection.c b/bus/connection.c index 1b59819f..b01cbde6 100644 --- a/bus/connection.c +++ b/bus/connection.c @@ -504,7 +504,8 @@ bus_connection_preallocate_oom_error (DBusConnection *connection) if (preallocated == NULL) return FALSE; - message = dbus_message_new (DBUS_SERVICE_DBUS, + /* d->name may be NULL, but that should be OK */ + message = dbus_message_new (d->name, DBUS_ERROR_NO_MEMORY); if (message == NULL) { @@ -513,6 +514,14 @@ bus_connection_preallocate_oom_error (DBusConnection *connection) } dbus_message_set_is_error (message, TRUE); + + if (!dbus_message_set_sender (message, + DBUS_SERVICE_DBUS)) + { + dbus_connection_free_preallocated_send (connection, preallocated); + dbus_message_unref (message); + return FALSE; + } /* set reply serial to placeholder value just so space is already allocated * for it. @@ -546,6 +555,8 @@ bus_connection_send_oom_error (DBusConnection *connection, dbus_message_get_serial (in_reply_to))) _dbus_assert_not_reached ("Failed to set reply serial for preallocated oom message"); + _dbus_assert (dbus_message_get_sender (d->oom_message) != NULL); + dbus_connection_send_preallocated (connection, d->oom_preallocated, d->oom_message, NULL); @@ -681,6 +692,8 @@ bus_transaction_send_message (BusTransaction *transaction, dbus_message_get_name (message), dbus_connection_get_is_connected (connection) ? "" : " (disconnected)"); + + _dbus_assert (dbus_message_get_sender (message) != NULL); if (!dbus_connection_get_is_connected (connection)) return TRUE; /* silently ignore disconnected connections */ @@ -811,6 +824,8 @@ connection_execute_transaction (DBusConnection *connection, _dbus_list_remove_link (&d->transaction_messages, link); + _dbus_assert (dbus_message_get_sender (m->message) != NULL); + dbus_connection_send_preallocated (connection, m->preallocated, m->message, diff --git a/bus/policy.c b/bus/policy.c index c94c17e1..f916383c 100644 --- a/bus/policy.c +++ b/bus/policy.c @@ -22,6 +22,9 @@ */ #include "policy.h" +#include "services.h" +#include <dbus/dbus-list.h> +#include <dbus/dbus-internals.h> BusPolicyRule* bus_policy_rule_new (BusPolicyRuleType type, @@ -59,15 +62,15 @@ bus_policy_rule_unref (BusPolicyRule *rule) { switch (rule->type) { - case DBUS_POLICY_RULE_SEND: + case BUS_POLICY_RULE_SEND: dbus_free (rule->d.send.message_name); dbus_free (rule->d.send.destination); break; - case DBUS_POLICY_RULE_RECEIVE: + case BUS_POLICY_RULE_RECEIVE: dbus_free (rule->d.receive.message_name); dbus_free (rule->d.receive.origin); break; - case DBUS_POLICY_RULE_OWN: + case BUS_POLICY_RULE_OWN: dbus_free (rule->d.own.service_name); break; } @@ -133,31 +136,262 @@ bus_policy_unref (BusPolicy *policy) } } +static void +remove_rules_by_type_up_to (BusPolicy *policy, + BusPolicyRuleType type, + DBusList *up_to) +{ + DBusList *link; + + link = _dbus_list_get_first (&policy->rules); + while (link != up_to) + { + BusPolicyRule *rule = link->data; + DBusList *next = _dbus_list_get_next_link (&policy->rules, link); + + bus_policy_rule_unref (rule); + _dbus_list_remove_link (&policy->rules, link); + + link = next; + } +} + +static void +bus_policy_optimize (BusPolicy *policy) +{ + DBusList *link; + + /* The idea here is that if we have: + * + * <allow send="foo"/> + * <deny send="*"/> + * + * (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 <include> 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. + */ + + link = _dbus_list_get_first (&policy->rules); + while (link != NULL) + { + BusPolicyRule *rule = link->data; + DBusList *next = _dbus_list_get_next_link (&policy->rules, link); + dbus_bool_t remove_preceding; + + remove_preceding = FALSE; + + switch (rule->type) + { + case BUS_POLICY_RULE_SEND: + remove_preceding = + rule->d.send.message_name == NULL && + rule->d.send.destination == NULL; + break; + case BUS_POLICY_RULE_RECEIVE: + remove_preceding = + rule->d.receive.message_name == NULL && + rule->d.receive.origin == NULL; + break; + case BUS_POLICY_RULE_OWN: + remove_preceding = + rule->d.own.service_name == NULL; + break; + } + + if (remove_preceding) + remove_rules_by_type_up_to (policy, rule->type, + link); + + link = next; + } +} + dbus_bool_t bus_policy_check_can_send (BusPolicy *policy, - DBusConnection *sender, + BusRegistry *registry, + DBusConnection *receiver, DBusMessage *message) { + 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 + */ + + allowed = FALSE; + link = _dbus_list_get_first (&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) + continue; + + if (rule->d.send.message_name != NULL) + { + if (!dbus_message_name_is (message, + rule->d.send.message_name)) + continue; + } + + if (rule->d.send.destination != NULL) + { + /* 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. + */ + if (receiver == NULL) + { + if (!dbus_message_sender_is (message, + 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) + continue; + + if (!bus_service_has_owner (service, receiver)) + continue; + } + } + + /* Use this rule */ + allowed = rule->allow; + } + return allowed; } dbus_bool_t bus_policy_check_can_receive (BusPolicy *policy, - DBusConnection *receiver, + BusRegistry *registry, + DBusConnection *sender, DBusMessage *message) { + 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 + */ + + allowed = FALSE; + link = _dbus_list_get_first (&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 + * origin from the message + */ + + if (rule->type != BUS_POLICY_RULE_RECEIVE) + continue; + + if (rule->d.receive.message_name != NULL) + { + if (!dbus_message_name_is (message, + rule->d.receive.message_name)) + 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_sender_is (message, + 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) + continue; + + if (!bus_service_has_owner (service, sender)) + continue; + } + } + /* Use this rule */ + allowed = rule->allow; + } + return allowed; } dbus_bool_t -bus_policy_check_can_own (BusPolicy *policy, - DBusConnection *connection, - const char *service_name) +bus_policy_check_can_own (BusPolicy *policy, + DBusConnection *connection, + const DBusString *service_name) { + 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 + */ + allowed = FALSE; + link = _dbus_list_get_first (&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 service name from + * the desired one. + */ + + if (rule->type != BUS_POLICY_RULE_OWN) + continue; + + if (rule->d.own.service_name != NULL) + { + if (!_dbus_string_equal_c_str (service_name, + rule->d.own.service_name)) + continue; + } -#endif /* BUS_POLICY_H */ + /* Use this rule */ + allowed = rule->allow; + } + + return allowed; +} diff --git a/bus/policy.h b/bus/policy.h index f146c528..00d60baa 100644 --- a/bus/policy.h +++ b/bus/policy.h @@ -25,6 +25,7 @@ #define BUS_POLICY_H #include <dbus/dbus.h> +#include <dbus/dbus-string.h> #include "bus.h" typedef struct BusPolicy BusPolicy; @@ -32,9 +33,9 @@ typedef struct BusPolicyRule BusPolicyRule; typedef enum { - DBUS_POLICY_RULE_SEND, - DBUS_POLICY_RULE_RECEIVE, - DBUS_POLICY_RULE_OWN + BUS_POLICY_RULE_SEND, + BUS_POLICY_RULE_RECEIVE, + BUS_POLICY_RULE_OWN } BusPolicyRuleType; struct BusPolicyRule @@ -76,17 +77,19 @@ void bus_policy_rule_ref (BusPolicyRule *rule); void bus_policy_rule_unref (BusPolicyRule *rule); BusPolicy* bus_policy_new (void); -void bus_policy_ref (BusPolicy *policy); -void bus_policy_unref (BusPolicy *policy); -dbus_bool_t bus_policy_check_can_send (BusPolicy *policy, - DBusConnection *sender, - DBusMessage *message); -dbus_bool_t bus_policy_check_can_receive (BusPolicy *policy, - DBusConnection *receiver, - DBusMessage *message); -dbus_bool_t bus_policy_check_can_own (BusPolicy *policy, - DBusConnection *connection, - const char *service_name); +void bus_policy_ref (BusPolicy *policy); +void bus_policy_unref (BusPolicy *policy); +dbus_bool_t bus_policy_check_can_send (BusPolicy *policy, + BusRegistry *registry, + DBusConnection *receiver, + DBusMessage *message); +dbus_bool_t bus_policy_check_can_receive (BusPolicy *policy, + BusRegistry *registry, + DBusConnection *sender, + DBusMessage *message); +dbus_bool_t bus_policy_check_can_own (BusPolicy *policy, + DBusConnection *connection, + const DBusString *service_name); diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index defa0585..6366c54e 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -1018,6 +1018,11 @@ dbus_message_get_name (DBusMessage *message) /** * Gets the destination service of a message. * + * @todo I think if we have set_sender/get_sender, + * this function might be better named set_destination/ + * get_destination for clarity, as the sender + * is also a service name. + * * @param message the message * @returns the message destination service (should not be freed) */ @@ -2326,6 +2331,62 @@ dbus_message_name_is (DBusMessage *message, return FALSE; } +/** + * Checks whether the message was sent to the given service. If the + * message has no service specified or has a different name, returns + * #FALSE. + * + * @param message the message + * @param service the service to check (must not be #NULL) + * + * @returns #TRUE if the message has the given destination service + */ +dbus_bool_t +dbus_message_service_is (DBusMessage *message, + const char *service) +{ + const char *s; + + _dbus_assert (service != NULL); + + s = dbus_message_get_service (message); + + if (s && strcmp (s, service) == 0) + return TRUE; + else + return FALSE; +} + +/** + * Checks whether the message has the given service as its sender. If + * the message has no sender specified or has a different sender, + * returns #FALSE. Note that if a peer application owns multiple + * services, its messages will have only one of those services as the + * sender (usually the base service). So you can't use this + * function to prove the sender didn't own service Foo, you can + * only use it to prove that it did. + * + * @param message the message + * @param service the service to check (must not be #NULL) + * + * @returns #TRUE if the message has the given origin service + */ +dbus_bool_t +dbus_message_sender_is (DBusMessage *message, + const char *service) +{ + const char *s; + + _dbus_assert (service != NULL); + + s = dbus_message_get_sender (message); + + if (s && strcmp (s, service) == 0) + return TRUE; + else + return FALSE; +} + /** @} */ /** diff --git a/dbus/dbus-message.h b/dbus/dbus-message.h index 1d5bbeb8..be752c94 100644 --- a/dbus/dbus-message.h +++ b/dbus/dbus-message.h @@ -58,6 +58,10 @@ void dbus_message_set_is_error (DBusMessage *message, dbus_bool_t dbus_message_get_is_error (DBusMessage *message); dbus_bool_t dbus_message_name_is (DBusMessage *message, const char *name); +dbus_bool_t dbus_message_service_is (DBusMessage *message, + const char *service); +dbus_bool_t dbus_message_sender_is (DBusMessage *message, + const char *service); dbus_int32_t dbus_message_get_serial (DBusMessage *message); dbus_bool_t dbus_message_set_reply_serial (DBusMessage *message, dbus_int32_t reply_serial); |