summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2003-04-13 08:33:10 +0000
committerHavoc Pennington <hp@redhat.com>2003-04-13 08:33:10 +0000
commit8aabca8dd28a113712389be51e75ea8c2fd17838 (patch)
treebd16d89beab87b7c20354b47e0698e9be06176fe
parentb09b7ca33cbaa7eae4f56b9cd699c8d0283dd754 (diff)
2003-04-13 Havoc Pennington <hp@pobox.com>
* 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
-rw-r--r--ChangeLog10
-rw-r--r--bus/config-parser.c326
-rw-r--r--bus/policy.c115
-rw-r--r--bus/policy.h33
-rw-r--r--dbus/dbus-sysdeps.c24
-rw-r--r--dbus/dbus-sysdeps.h2
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 <hp@pobox.com>
+
+ * 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 <hp@pobox.com>
* 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
{
@@ -705,6 +723,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 <allow> or <deny>");
+
+ 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,
const char **attribute_names,
@@ -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 <dbus/dbus.h>
#include <dbus/dbus-string.h>
+#include <dbus/dbus-sysdeps.h>
#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
@@ -1478,6 +1478,30 @@ _dbus_credentials_from_username (const DBusString *username,
}
/**
+ * 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.
*
* @param user_id the 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,