]> git.ipfire.org Git - thirdparty/dbus.git/commitdiff
2003-04-13 Havoc Pennington <hp@pobox.com>
authorHavoc Pennington <hp@redhat.com>
Sun, 13 Apr 2003 08:33:10 +0000 (08:33 +0000)
committerHavoc Pennington <hp@redhat.com>
Sun, 13 Apr 2003 08:33:10 +0000 (08:33 +0000)
* 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
bus/config-parser.c
bus/policy.c
bus/policy.h
dbus/dbus-sysdeps.c
dbus/dbus-sysdeps.h

index 60cff002a8fe4dfac530879b74264678e3eb53f4..1cb38e2cbbf997afd6d09f492aee8823875e705c 100644 (file)
--- 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
index da5b23f8716db747f63b8cb485aa284103b0c613..85c367b3cde925ffdc16e1fd5de36de1ba557b5b 100644 (file)
@@ -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 <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,
@@ -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);
index cff2509c7b2b9a006da0fb5f0485e517e3628359..81894b8bb85e79f028c32d5bdf6e450999504f83 100644 (file)
@@ -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;
index 194bd0014fbd76a741d7bae55266ee231c4d90e0..986cfe07c96587734aa5837b8158229a2fc21822 100644 (file)
@@ -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);
index b941c19ea3fff98c8f98ad4c092ec36ddf55c153..f706d08a0328625f38aa3e1674be71f04a033de5 100644 (file)
@@ -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.
  *
index 74e0cb612dd0a53f84f9fcc5da1310908fe5f0e5..4edfe94a0fb7f6a25e34d6267b254f8a9e8efd14 100644 (file)
@@ -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,