summaryrefslogtreecommitdiffstats
path: root/bus/policy.c
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2003-04-12 18:32:11 +0000
committerHavoc Pennington <hp@redhat.com>2003-04-12 18:32:11 +0000
commitbc983ecf15455f49e7a92d038c93e181ae2cb438 (patch)
treed53948dab970d81f07e195513804945b87a758e8 /bus/policy.c
parent4b773b4a5448ac9bea2cc57486571588fdc14480 (diff)
2003-04-12 Havoc Pennington <hp@pobox.com>
* bus/policy.h: change BusPolicy to be the thing from the config file, and rename old BusPolicy to BusClientPolicy * bus/bus.c, bus/connection.c, bus/config-parser.c: change to match change in how policy works * dbus/dbus-internals.h: mark assert_not_reached as __attribute((noreturn))__
Diffstat (limited to 'bus/policy.c')
-rw-r--r--bus/policy.c313
1 files changed, 294 insertions, 19 deletions
diff --git a/bus/policy.c b/bus/policy.c
index b5187715..cff2509c 100644
--- a/bus/policy.c
+++ b/bus/policy.c
@@ -1,5 +1,5 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
-/* policy.c Policies for what a connection can do
+/* policy.c Bus security policy
*
* Copyright (C) 2003 Red Hat, Inc.
*
@@ -25,6 +25,7 @@
#include "services.h"
#include "test.h"
#include <dbus/dbus-list.h>
+#include <dbus/dbus-hash.h>
#include <dbus/dbus-internals.h>
BusPolicyRule*
@@ -88,9 +89,33 @@ struct BusPolicy
{
int refcount;
- DBusList *rules;
+ DBusList *default_rules; /**< Default policy rules */
+ DBusList *mandatory_rules; /**< Mandatory policy rules */
+ DBusHashTable *rules_by_uid; /**< per-UID policy rules */
+ DBusHashTable *rules_by_gid; /**< per-GID policy rules */
};
+static void
+free_rule_func (void *data,
+ void *user_data)
+{
+ BusPolicyRule *rule = data;
+
+ bus_policy_rule_unref (rule);
+}
+
+static void
+free_rule_list_func (void *data)
+{
+ DBusList **list = data;
+
+ _dbus_list_foreach (list, free_rule_func, NULL);
+
+ _dbus_list_clear (list);
+
+ dbus_free (list);
+}
+
BusPolicy*
bus_policy_new (void)
{
@@ -101,8 +126,24 @@ bus_policy_new (void)
return NULL;
policy->refcount = 1;
-
+
+ policy->rules_by_uid = _dbus_hash_table_new (DBUS_HASH_ULONG,
+ NULL,
+ free_rule_list_func);
+ if (policy->rules_by_uid == NULL)
+ goto failed;
+
+ policy->rules_by_gid = _dbus_hash_table_new (DBUS_HASH_ULONG,
+ NULL,
+ free_rule_list_func);
+ if (policy->rules_by_gid == NULL)
+ goto failed;
+
return policy;
+
+ failed:
+ bus_policy_unref (policy);
+ return NULL;
}
void
@@ -113,6 +154,240 @@ bus_policy_ref (BusPolicy *policy)
policy->refcount += 1;
}
+void
+bus_policy_unref (BusPolicy *policy)
+{
+ _dbus_assert (policy->refcount > 0);
+
+ policy->refcount -= 1;
+
+ if (policy->refcount == 0)
+ {
+ if (policy->rules_by_uid)
+ {
+ _dbus_hash_table_unref (policy->rules_by_uid);
+ policy->rules_by_uid = NULL;
+ }
+
+ if (policy->rules_by_gid)
+ {
+ _dbus_hash_table_unref (policy->rules_by_gid);
+ policy->rules_by_gid = NULL;
+ }
+
+ 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;
+ }
+ }
+
+ return TRUE;
+}
+
+BusClientPolicy*
+bus_policy_create_client_policy (BusPolicy *policy,
+ DBusConnection *connection)
+{
+ BusClientPolicy *client;
+ unsigned long uid;
+ DBusList **list;
+
+ _dbus_assert (dbus_connection_get_is_authenticated (connection));
+
+ client = bus_client_policy_new ();
+ if (client == NULL)
+ return NULL;
+
+ if (!add_list_to_client (&policy->default_rules,
+ client))
+ goto failed;
+
+ /* 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)
+ {
+ const unsigned long *groups;
+ int n_groups;
+ int i;
+
+ if (!bus_connection_get_groups (connection, &groups, &n_groups))
+ goto failed;
+
+ i = 0;
+ while (i < n_groups)
+ {
+ list = _dbus_hash_table_lookup_ulong (policy->rules_by_gid,
+ groups[i]);
+
+ if (list != NULL)
+ {
+ if (!add_list_to_client (list, client))
+ goto failed;
+ }
+
+ ++i;
+ }
+ }
+
+ if (!dbus_connection_get_unix_user (connection, &uid))
+ goto failed;
+
+ list = _dbus_hash_table_lookup_ulong (policy->rules_by_uid,
+ uid);
+
+ if (!add_list_to_client (list, client))
+ goto failed;
+
+ if (!add_list_to_client (&policy->mandatory_rules,
+ client))
+ goto failed;
+
+ bus_client_policy_optimize (client);
+
+ return client;
+
+ failed:
+ bus_client_policy_unref (client);
+ return NULL;
+}
+
+static dbus_bool_t
+list_allows_user (dbus_bool_t def,
+ DBusList **list,
+ unsigned long uid,
+ const unsigned long *group_ids,
+ int n_group_ids)
+{
+ DBusList *link;
+ dbus_bool_t allowed;
+
+ allowed = def;
+
+ link = _dbus_list_get_first_link (list);
+ while (link != NULL)
+ {
+ BusPolicyRule *rule = link->data;
+ link = _dbus_list_get_next_link (list, link);
+
+ if (rule->type == BUS_POLICY_RULE_USER)
+ {
+ if (rule->d.user.uid != uid)
+ continue;
+ }
+ else if (rule->type == BUS_POLICY_RULE_GROUP)
+ {
+ int i;
+
+ i = 0;
+ while (i < n_group_ids)
+ {
+ if (rule->d.group.gid == group_ids[i])
+ break;
+ ++i;
+ }
+
+ if (i == n_group_ids)
+ continue;
+ }
+ else
+ continue;
+
+ allowed = rule->allow;
+ }
+
+ return allowed;
+}
+
+dbus_bool_t
+bus_policy_allow_user (BusPolicy *policy,
+ unsigned long uid)
+{
+ dbus_bool_t allowed;
+ unsigned long *group_ids;
+ int n_group_ids;
+
+ /* On OOM or error we always reject the user */
+ if (!_dbus_get_groups (uid, &group_ids, &n_group_ids))
+ {
+ _dbus_verbose ("Did not get any groups for UID %lu\n",
+ uid);
+ return FALSE;
+ }
+
+ allowed = FALSE;
+
+ allowed = list_allows_user (allowed,
+ &policy->default_rules,
+ uid,
+ group_ids, n_group_ids);
+
+ allowed = list_allows_user (allowed,
+ &policy->mandatory_rules,
+ uid,
+ group_ids, n_group_ids);
+
+ dbus_free (group_ids);
+
+ return allowed;
+}
+
+struct BusClientPolicy
+{
+ int refcount;
+
+ DBusList *rules;
+};
+
+BusClientPolicy*
+bus_client_policy_new (void)
+{
+ BusClientPolicy *policy;
+
+ policy = dbus_new0 (BusClientPolicy, 1);
+ if (policy == NULL)
+ return NULL;
+
+ policy->refcount = 1;
+
+ return policy;
+}
+
+void
+bus_client_policy_ref (BusClientPolicy *policy)
+{
+ _dbus_assert (policy->refcount > 0);
+
+ policy->refcount += 1;
+}
+
static void
rule_unref_foreach (void *data,
void *user_data)
@@ -123,7 +398,7 @@ rule_unref_foreach (void *data,
}
void
-bus_policy_unref (BusPolicy *policy)
+bus_client_policy_unref (BusClientPolicy *policy)
{
_dbus_assert (policy->refcount > 0);
@@ -142,7 +417,7 @@ bus_policy_unref (BusPolicy *policy)
}
static void
-remove_rules_by_type_up_to (BusPolicy *policy,
+remove_rules_by_type_up_to (BusClientPolicy *policy,
BusPolicyRuleType type,
DBusList *up_to)
{
@@ -162,7 +437,7 @@ remove_rules_by_type_up_to (BusPolicy *policy,
}
void
-bus_policy_optimize (BusPolicy *policy)
+bus_client_policy_optimize (BusClientPolicy *policy)
{
DBusList *link;
@@ -226,8 +501,8 @@ bus_policy_optimize (BusPolicy *policy)
}
dbus_bool_t
-bus_policy_append_rule (BusPolicy *policy,
- BusPolicyRule *rule)
+bus_client_policy_append_rule (BusClientPolicy *policy,
+ BusPolicyRule *rule)
{
if (!_dbus_list_append (&policy->rules, rule))
return FALSE;
@@ -238,10 +513,10 @@ bus_policy_append_rule (BusPolicy *policy,
}
dbus_bool_t
-bus_policy_check_can_send (BusPolicy *policy,
- BusRegistry *registry,
- DBusConnection *receiver,
- DBusMessage *message)
+bus_client_policy_check_can_send (BusClientPolicy *policy,
+ BusRegistry *registry,
+ DBusConnection *receiver,
+ DBusMessage *message)
{
DBusList *link;
dbus_bool_t allowed;
@@ -310,10 +585,10 @@ bus_policy_check_can_send (BusPolicy *policy,
}
dbus_bool_t
-bus_policy_check_can_receive (BusPolicy *policy,
- BusRegistry *registry,
- DBusConnection *sender,
- DBusMessage *message)
+bus_client_policy_check_can_receive (BusClientPolicy *policy,
+ BusRegistry *registry,
+ DBusConnection *sender,
+ DBusMessage *message)
{
DBusList *link;
dbus_bool_t allowed;
@@ -383,9 +658,9 @@ bus_policy_check_can_receive (BusPolicy *policy,
}
dbus_bool_t
-bus_policy_check_can_own (BusPolicy *policy,
- DBusConnection *connection,
- const DBusString *service_name)
+bus_client_policy_check_can_own (BusClientPolicy *policy,
+ DBusConnection *connection,
+ const DBusString *service_name)
{
DBusList *link;
dbus_bool_t allowed;