From 8aabca8dd28a113712389be51e75ea8c2fd17838 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sun, 13 Apr 2003 08:33:10 +0000 Subject: 2003-04-13 Havoc Pennington * bus/config-parser.c: Load up the BusPolicy and BusPolicyRules * dbus/dbus-sysdeps.c (_dbus_get_user_id): new function * bus/policy.c (bus_policy_append_mandatory_rule) (bus_policy_append_default_rule, bus_policy_append_user_rule) (bus_policy_append_group_rule): new functions --- ChangeLog | 10 ++ bus/config-parser.c | 326 +++++++++++++++++++++++++++++++++++++++++++++++++--- bus/policy.c | 115 +++++++++++++++++- bus/policy.h | 33 ++++-- dbus/dbus-sysdeps.c | 24 ++++ dbus/dbus-sysdeps.h | 2 + 6 files changed, 484 insertions(+), 26 deletions(-) diff --git a/ChangeLog b/ChangeLog index 60cff002..1cb38e2c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2003-04-13 Havoc Pennington + + * bus/config-parser.c: Load up the BusPolicy and BusPolicyRules + + * dbus/dbus-sysdeps.c (_dbus_get_user_id): new function + + * bus/policy.c (bus_policy_append_mandatory_rule) + (bus_policy_append_default_rule, bus_policy_append_user_rule) + (bus_policy_append_group_rule): new functions + 2003-04-12 Havoc Pennington * bus/config-parser.c (bus_config_parser_new): fix a memleak diff --git a/bus/config-parser.c b/bus/config-parser.c index da5b23f8..85c367b3 100644 --- a/bus/config-parser.c +++ b/bus/config-parser.c @@ -47,6 +47,18 @@ typedef enum ELEMENT_TYPE } ElementType; +typedef enum +{ + /* we ignore policies for unknown groups/users */ + POLICY_IGNORED, + + /* non-ignored */ + POLICY_DEFAULT, + POLICY_MANDATORY, + POLICY_USER, + POLICY_GROUP +} PolicyType; + typedef struct { ElementType type; @@ -62,17 +74,10 @@ typedef struct struct { - char *context; - char *user; - char *group; - DBusList *rules; + PolicyType type; + unsigned long gid_or_uid; } policy; - struct - { - int foo; - } limit; - } d; } Element; @@ -637,6 +642,8 @@ start_busconfig_child (BusConfigParser *parser, return FALSE; } + e->d.policy.type = POLICY_IGNORED; + if (!locate_attributes (parser, "policy", attribute_names, attribute_values, @@ -661,11 +668,11 @@ start_busconfig_child (BusConfigParser *parser, { if (strcmp (context, "default") == 0) { - + e->d.policy.type = POLICY_DEFAULT; } else if (strcmp (context, "mandatory") == 0) { - + e->d.policy.type = POLICY_MANDATORY; } else { @@ -674,19 +681,30 @@ start_busconfig_child (BusConfigParser *parser, context); return FALSE; } - - /* FIXME */ - } else if (user != NULL) { - /* FIXME */ + DBusString username; + _dbus_string_init_const (&username, user); + if (_dbus_get_user_id (&username, + &e->d.policy.gid_or_uid)) + e->d.policy.type = POLICY_USER; + else + _dbus_warn ("Unknown username \"%s\" in message bus configuration file\n", + user); } else if (group != NULL) { - /* FIXME */ + DBusString group_name; + _dbus_string_init_const (&group_name, group); + if (_dbus_get_group_id (&group_name, + &e->d.policy.gid_or_uid)) + e->d.policy.type = POLICY_GROUP; + else + _dbus_warn ("Unknown group \"%s\" in message bus configuration file\n", + group); } else { @@ -704,6 +722,272 @@ start_busconfig_child (BusConfigParser *parser, } } +static dbus_bool_t +append_rule_from_element (BusConfigParser *parser, + const char *element_name, + const char **attribute_names, + const char **attribute_values, + dbus_bool_t allow, + DBusError *error) +{ + const char *send; + const char *receive; + const char *own; + const char *send_to; + const char *receive_from; + const char *user; + const char *group; + BusPolicyRule *rule; + + if (!locate_attributes (parser, element_name, + attribute_names, + attribute_values, + error, + "send", &send, + "receive", &receive, + "own", &own, + "send_to", &send_to, + "receive_from", &receive_from, + "user", &user, + "group", &group, + NULL)) + return FALSE; + + if (!(send || receive || own || send_to || receive_from || + user || group)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Element <%s> must have one or more attributes", + element_name); + return FALSE; + } + + if (((send && own) || + (send && receive) || + (send && receive_from) || + (send && user) || + (send && group)) || + + ((receive && own) || + (receive && send_to) || + (receive && user) || + (receive && group)) || + + ((own && send_to) || + (own && receive_from) || + (own && user) || + (own && group)) || + + ((send_to && receive_from) || + (send_to && user) || + (send_to && group)) || + + ((receive_from && user) || + (receive_from && group)) || + + (user && group)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Invalid combination of attributes on element <%s>, " + "only send/send_to or receive/receive_from may be paired", + element_name); + return FALSE; + } + + rule = NULL; + + /* In BusPolicyRule, NULL represents wildcard. + * In the config file, '*' represents it. + */ +#define IS_WILDCARD(str) ((str) && ((str)[0]) == '*' && ((str)[1]) == '\0') + + if (send || send_to) + { + rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, allow); + if (rule == NULL) + goto nomem; + + if (IS_WILDCARD (send)) + send = NULL; + if (IS_WILDCARD (send_to)) + send_to = NULL; + + rule->d.send.message_name = _dbus_strdup (send); + rule->d.send.destination = _dbus_strdup (send_to); + if (send && rule->d.send.message_name == NULL) + goto nomem; + if (send_to && rule->d.send.destination == NULL) + goto nomem; + } + else if (receive || receive_from) + { + rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, allow); + if (rule == NULL) + goto nomem; + + if (IS_WILDCARD (receive)) + receive = NULL; + + if (IS_WILDCARD (receive_from)) + receive_from = NULL; + + rule->d.receive.message_name = _dbus_strdup (receive); + rule->d.receive.origin = _dbus_strdup (receive_from); + if (receive && rule->d.receive.message_name == NULL) + goto nomem; + if (receive_from && rule->d.receive.origin == NULL) + goto nomem; + } + else if (own) + { + rule = bus_policy_rule_new (BUS_POLICY_RULE_OWN, allow); + if (rule == NULL) + goto nomem; + + if (IS_WILDCARD (own)) + own = NULL; + + rule->d.own.service_name = _dbus_strdup (own); + if (own && rule->d.own.service_name == NULL) + goto nomem; + } + else if (user) + { + if (IS_WILDCARD (user)) + { + rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow); + if (rule == NULL) + goto nomem; + + /* FIXME the wildcard needs storing in the rule somehow */ + } + else + { + DBusString username; + dbus_uid_t uid; + + _dbus_string_init_const (&username, user); + + if (_dbus_get_user_id (&username, &uid)) + { + rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow); + if (rule == NULL) + goto nomem; + + rule->d.user.user = _dbus_strdup (user); + if (rule->d.user.user == NULL) + goto nomem; + rule->d.user.uid = uid; + } + else + { + _dbus_warn ("Unknown username \"%s\" on element <%s>\n", + user, element_name); + } + } + } + else if (group) + { + if (IS_WILDCARD (group)) + { + rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow); + if (rule == NULL) + goto nomem; + + /* FIXME the wildcard needs storing in the rule somehow */ + } + else + { + DBusString groupname; + dbus_gid_t gid; + + _dbus_string_init_const (&groupname, group); + + if (_dbus_get_user_id (&groupname, &gid)) + { + rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow); + if (rule == NULL) + goto nomem; + + rule->d.group.group = _dbus_strdup (group); + if (rule->d.group.group == NULL) + goto nomem; + rule->d.group.gid = gid; + } + else + { + _dbus_warn ("Unknown group \"%s\" on element <%s>\n", + group, element_name); + } + } + } + else + _dbus_assert_not_reached ("Did not handle some combination of attributes on or "); + + if (rule != NULL) + { + Element *pe; + + pe = peek_element (parser); + _dbus_assert (pe != NULL); + _dbus_assert (pe->type == ELEMENT_POLICY); + + switch (pe->d.policy.type) + { + case POLICY_IGNORED: + /* drop the rule on the floor */ + break; + + case POLICY_DEFAULT: + if (!bus_policy_append_default_rule (parser->policy, rule)) + goto nomem; + break; + case POLICY_MANDATORY: + if (!bus_policy_append_mandatory_rule (parser->policy, rule)) + goto nomem; + break; + case POLICY_USER: + if (!BUS_POLICY_RULE_IS_PER_CLIENT (rule)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "<%s> rule cannot be per-user because it has bus-global semantics", + element_name); + goto failed; + } + + if (!bus_policy_append_user_rule (parser->policy, pe->d.policy.gid_or_uid, + rule)) + goto nomem; + break; + case POLICY_GROUP: + if (!BUS_POLICY_RULE_IS_PER_CLIENT (rule)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "<%s> rule cannot be per-group because it has bus-global semantics", + element_name); + goto failed; + } + + if (!bus_policy_append_group_rule (parser->policy, pe->d.policy.gid_or_uid, + rule)) + goto nomem; + break; + } + + bus_policy_rule_unref (rule); + rule = NULL; + } + + return TRUE; + + nomem: + BUS_SET_OOM (error); + failed: + if (rule) + bus_policy_rule_unref (rule); + return FALSE; +} + static dbus_bool_t start_policy_child (BusConfigParser *parser, const char *element_name, @@ -713,6 +997,11 @@ start_policy_child (BusConfigParser *parser, { if (strcmp (element_name, "allow") == 0) { + if (!append_rule_from_element (parser, element_name, + attribute_names, attribute_values, + TRUE, error)) + return FALSE; + if (push_element (parser, ELEMENT_ALLOW) == NULL) { BUS_SET_OOM (error); @@ -723,6 +1012,11 @@ start_policy_child (BusConfigParser *parser, } else if (strcmp (element_name, "deny") == 0) { + if (!append_rule_from_element (parser, element_name, + attribute_names, attribute_values, + FALSE, error)) + return FALSE; + if (push_element (parser, ELEMENT_DENY) == NULL) { BUS_SET_OOM (error); diff --git a/bus/policy.c b/bus/policy.c index cff2509c..81894b8b 100644 --- a/bus/policy.c +++ b/bus/policy.c @@ -42,6 +42,20 @@ bus_policy_rule_new (BusPolicyRuleType type, rule->refcount = 1; rule->allow = allow; + switch (rule->type) + { + case BUS_POLICY_RULE_USER: + rule->d.user.uid = DBUS_UID_UNSET; + break; + case BUS_POLICY_RULE_GROUP: + rule->d.group.gid = DBUS_GID_UNSET; + break; + case BUS_POLICY_RULE_SEND: + case BUS_POLICY_RULE_RECEIVE: + case BUS_POLICY_RULE_OWN: + break; + } + return rule; } @@ -76,8 +90,10 @@ bus_policy_rule_unref (BusPolicyRule *rule) dbus_free (rule->d.own.service_name); break; case BUS_POLICY_RULE_USER: + dbus_free (rule->d.user.user); + break; case BUS_POLICY_RULE_GROUP: - _dbus_assert_not_reached ("invalid rule"); + dbus_free (rule->d.group.group); break; } @@ -163,6 +179,12 @@ bus_policy_unref (BusPolicy *policy) if (policy->refcount == 0) { + _dbus_list_foreach (&policy->default_rules, free_rule_func, NULL); + _dbus_list_clear (&policy->default_rules); + + _dbus_list_foreach (&policy->mandatory_rules, free_rule_func, NULL); + _dbus_list_clear (&policy->mandatory_rules); + if (policy->rules_by_uid) { _dbus_hash_table_unref (policy->rules_by_uid); @@ -288,6 +310,9 @@ list_allows_user (dbus_bool_t def, { DBusList *link; dbus_bool_t allowed; + + /* FIXME there's currently no handling of wildcard user/group rules. + */ allowed = def; @@ -359,6 +384,94 @@ bus_policy_allow_user (BusPolicy *policy, return allowed; } +dbus_bool_t +bus_policy_append_default_rule (BusPolicy *policy, + BusPolicyRule *rule) +{ + if (!_dbus_list_append (&policy->default_rules, rule)) + return FALSE; + + bus_policy_rule_ref (rule); + + return TRUE; +} + +dbus_bool_t +bus_policy_append_mandatory_rule (BusPolicy *policy, + BusPolicyRule *rule) +{ + if (!_dbus_list_append (&policy->mandatory_rules, rule)) + return FALSE; + + bus_policy_rule_ref (rule); + + return TRUE; +} + +static DBusList** +get_list (DBusHashTable *hash, + unsigned long key) +{ + DBusList **list; + + list = _dbus_hash_table_lookup_ulong (hash, key); + + if (list == NULL) + { + list = dbus_new0 (DBusList*, 1); + if (list == NULL) + return NULL; + + if (!_dbus_hash_table_insert_ulong (hash, key, list)) + { + dbus_free (list); + return NULL; + } + } + + return list; +} + +dbus_bool_t +bus_policy_append_user_rule (BusPolicy *policy, + dbus_uid_t uid, + BusPolicyRule *rule) +{ + DBusList **list; + + list = get_list (policy->rules_by_uid, uid); + + if (list == NULL) + return FALSE; + + if (!_dbus_list_append (list, rule)) + return FALSE; + + bus_policy_rule_ref (rule); + + return TRUE; +} + +dbus_bool_t +bus_policy_append_group_rule (BusPolicy *policy, + dbus_gid_t gid, + BusPolicyRule *rule) +{ + DBusList **list; + + list = get_list (policy->rules_by_gid, gid); + + if (list == NULL) + return FALSE; + + if (!_dbus_list_append (list, rule)) + return FALSE; + + bus_policy_rule_ref (rule); + + return TRUE; +} + struct BusClientPolicy { int refcount; diff --git a/bus/policy.h b/bus/policy.h index 194bd001..986cfe07 100644 --- a/bus/policy.h +++ b/bus/policy.h @@ -26,6 +26,7 @@ #include #include +#include #include "bus.h" typedef enum @@ -37,6 +38,10 @@ typedef enum BUS_POLICY_RULE_GROUP } BusPolicyRuleType; +/** determines whether the rule affects a connection, or some global item */ +#define BUS_POLICY_RULE_IS_PER_CLIENT(rule) (!((rule)->type == BUS_POLICY_RULE_USER || \ + (rule)->type == BUS_POLICY_RULE_GROUP)) + struct BusPolicyRule { int refcount; @@ -70,13 +75,13 @@ struct BusPolicyRule struct { char *user; - unsigned long uid; + dbus_uid_t uid; } user; struct { char *group; - unsigned long gid; + dbus_gid_t gid; } group; } d; @@ -87,13 +92,23 @@ BusPolicyRule* bus_policy_rule_new (BusPolicyRuleType type, 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); -BusClientPolicy* bus_policy_create_client_policy (BusPolicy *policy, - DBusConnection *connection); -dbus_bool_t bus_policy_allow_user (BusPolicy *policy, - unsigned long uid); +BusPolicy* bus_policy_new (void); +void bus_policy_ref (BusPolicy *policy); +void bus_policy_unref (BusPolicy *policy); +BusClientPolicy* bus_policy_create_client_policy (BusPolicy *policy, + DBusConnection *connection); +dbus_bool_t bus_policy_allow_user (BusPolicy *policy, + unsigned long uid); +dbus_bool_t bus_policy_append_default_rule (BusPolicy *policy, + BusPolicyRule *rule); +dbus_bool_t bus_policy_append_mandatory_rule (BusPolicy *policy, + BusPolicyRule *rule); +dbus_bool_t bus_policy_append_user_rule (BusPolicy *policy, + dbus_uid_t uid, + BusPolicyRule *rule); +dbus_bool_t bus_policy_append_group_rule (BusPolicy *policy, + dbus_gid_t gid, + BusPolicyRule *rule); BusClientPolicy* bus_client_policy_new (void); void bus_client_policy_ref (BusClientPolicy *policy); diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c index b941c19e..f706d08a 100644 --- a/dbus/dbus-sysdeps.c +++ b/dbus/dbus-sysdeps.c @@ -1477,6 +1477,30 @@ _dbus_credentials_from_username (const DBusString *username, return get_user_info (username, -1, credentials, NULL, NULL); } +/** + * Gets user ID given username + * + * @param username the username + * @param uid return location for UID + * @returns #TRUE if username existed and we got the UID + */ +dbus_bool_t +_dbus_get_user_id (const DBusString *username, + dbus_uid_t *uid) +{ + DBusCredentials creds; + + if (!_dbus_credentials_from_username (username, &creds)) + return FALSE; + + if (creds.uid == DBUS_UID_UNSET) + return FALSE; + + *uid = creds.uid; + + return TRUE; +} + /** * Gets the credentials corresponding to the given user ID. * diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h index 74e0cb61..4edfe94a 100644 --- a/dbus/dbus-sysdeps.h +++ b/dbus/dbus-sysdeps.h @@ -134,6 +134,8 @@ void _dbus_credentials_from_current_process (DBusCredentials *crede dbus_bool_t _dbus_credentials_match (const DBusCredentials *expected_credentials, const DBusCredentials *provided_credentials); +dbus_bool_t _dbus_get_user_id (const DBusString *username, + dbus_uid_t *uid); dbus_bool_t _dbus_string_append_our_uid (DBusString *str); dbus_bool_t _dbus_homedir_from_username (const DBusString *username, -- cgit