summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2003-03-20 07:57:39 +0000
committerHavoc Pennington <hp@redhat.com>2003-03-20 07:57:39 +0000
commit056d76d809dc341b0dce160d3f79062604565c77 (patch)
tree1c0518c56526b71f8c4e77b97bb1b6e504339b55
parenta284a148e40551a2e6e5d0e54c2e04d2b679aaad (diff)
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
-rw-r--r--ChangeLog13
-rw-r--r--bus/Makefile.am2
-rw-r--r--bus/connection.c17
-rw-r--r--bus/policy.c254
-rw-r--r--bus/policy.h31
-rw-r--r--dbus/dbus-message.c61
-rw-r--r--dbus/dbus-message.h4
7 files changed, 357 insertions, 25 deletions
diff --git a/ChangeLog b/ChangeLog
index 4c6fe3e2..4688cdb7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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);