diff options
author | Brian McGillion <brian.mcgillion@intel.com> | 2012-02-06 18:48:30 +0200 |
---|---|---|
committer | Michael Leibowitz <michael.leibowitz@intel.com> | 2013-07-10 10:31:28 -0700 |
commit | 43a3a39e20f803063cf36c01e2798bf9d90b330f (patch) | |
tree | 9dbd275575ab0c40eefd12316aa10f0e0526463c | |
parent | e6b136cc124d3893c078d28d704da4d3c199248d (diff) |
Enforce smack policy from conf file
-rw-r--r-- | bus/config-parser.c | 38 | ||||
-rw-r--r-- | bus/policy.c | 141 | ||||
-rw-r--r-- | bus/policy.h | 3 | ||||
-rw-r--r-- | bus/smack.c | 111 | ||||
-rw-r--r-- | bus/smack.h | 4 |
5 files changed, 278 insertions, 19 deletions
diff --git a/bus/config-parser.c b/bus/config-parser.c index 07e8fbb6..d7ba5492 100644 --- a/bus/config-parser.c +++ b/bus/config-parser.c @@ -43,6 +43,7 @@ typedef enum POLICY_MANDATORY, POLICY_USER, POLICY_GROUP, + POLICY_SMACK, POLICY_CONSOLE } PolicyType; @@ -64,7 +65,11 @@ typedef struct struct { PolicyType type; - unsigned long gid_uid_or_at_console; + union + { + unsigned long gid_uid_or_at_console; + char *smack_label; + }; } policy; struct @@ -150,6 +155,8 @@ element_free (Element *e) { if (e->type == ELEMENT_LIMIT) dbus_free (e->d.limit.name); + else if (e->type == ELEMENT_POLICY && e->d.policy.type == POLICY_SMACK) + dbus_free (e->d.policy.smack_label); dbus_free (e); } @@ -972,6 +979,7 @@ start_busconfig_child (BusConfigParser *parser, const char *user; const char *group; const char *at_console; + const char *smack; if ((e = push_element (parser, ELEMENT_POLICY)) == NULL) { @@ -988,20 +996,16 @@ start_busconfig_child (BusConfigParser *parser, "context", &context, "user", &user, "group", &group, + "smack", &smack, "at_console", &at_console, NULL)) return FALSE; - if (((context && user) || - (context && group) || - (context && at_console)) || - ((user && group) || - (user && at_console)) || - (group && at_console) || - !(context || user || group || at_console)) + if (((context != NULL) + (user != NULL) + (group != NULL) + + (smack != NULL) + (at_console != NULL)) != 1) { dbus_set_error (error, DBUS_ERROR_FAILED, - "<policy> element must have exactly one of (context|user|group|at_console) attributes"); + "<policy> element must have exactly one of (context|user|group|smack|at_console) attributes"); return FALSE; } @@ -1047,6 +1051,16 @@ start_busconfig_child (BusConfigParser *parser, _dbus_warn ("Unknown group \"%s\" in message bus configuration file\n", group); } + else if (smack != NULL) + { + e->d.policy.type = POLICY_SMACK; + e->d.policy.smack_label = _dbus_strdup (smack); + if (e->d.policy.smack_label == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + } else if (at_console != NULL) { dbus_bool_t t; @@ -1631,8 +1645,10 @@ append_rule_from_element (BusConfigParser *parser, rule)) goto nomem; break; - - + case POLICY_SMACK: + if (!bus_policy_append_smack_rule (parser->policy, pe->d.policy.smack_label, rule)) + goto nomem; + break; case POLICY_CONSOLE: if (!bus_policy_append_console_rule (parser->policy, pe->d.policy.gid_uid_or_at_console, rule)) diff --git a/bus/policy.c b/bus/policy.c index 379cea95..836354a2 100644 --- a/bus/policy.c +++ b/bus/policy.c @@ -26,6 +26,7 @@ #include "services.h" #include "test.h" #include "utils.h" +#include "smack.h" #include <dbus/dbus-list.h> #include <dbus/dbus-hash.h> #include <dbus/dbus-internals.h> @@ -126,12 +127,13 @@ struct BusPolicy { int refcount; - 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 */ - DBusList *at_console_true_rules; /**< console user policy rules where at_console="true"*/ - DBusList *at_console_false_rules; /**< console user policy rules where at_console="false"*/ + 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 */ + DBusHashTable *rules_by_smack_label; /**< per-SMACK label policy rules */ + DBusList *at_console_true_rules; /**< console user policy rules where at_console="true"*/ + DBusList *at_console_false_rules; /**< console user policy rules where at_console="false"*/ }; static void @@ -181,6 +183,14 @@ bus_policy_new (void) if (policy->rules_by_gid == NULL) goto failed; +#ifdef DBUS_ENABLE_SMACK + policy->rules_by_smack_label = _dbus_hash_table_new (DBUS_HASH_STRING, + (DBusFreeFunction) dbus_free, + free_rule_list_func); + if (policy->rules_by_smack_label == NULL) + goto failed; +#endif + return policy; failed: @@ -230,7 +240,13 @@ bus_policy_unref (BusPolicy *policy) _dbus_hash_table_unref (policy->rules_by_gid); policy->rules_by_gid = NULL; } - + + if (policy->rules_by_smack_label) + { + _dbus_hash_table_unref (policy->rules_by_smack_label); + policy->rules_by_smack_label = NULL; + } + dbus_free (policy); } } @@ -356,6 +372,24 @@ bus_policy_create_client_policy (BusPolicy *policy, } } + if (policy->rules_by_smack_label && + _dbus_hash_table_get_n_entries (policy->rules_by_smack_label) > 0) + { + DBusList **list; + dbus_bool_t nomem_err = FALSE; + + list = bus_smack_generate_allowed_list(connection, policy->rules_by_smack_label, &nomem_err); + + if (list != NULL) + { + nomem_err = !add_list_to_client (list, client); + _dbus_list_clear (list); + } + + if (nomem_err) + goto nomem; + } + if (!add_list_to_client (&policy->mandatory_rules, client)) goto nomem; @@ -576,6 +610,66 @@ bus_policy_append_group_rule (BusPolicy *policy, return TRUE; } +#ifdef DBUS_ENABLE_SMACK +static DBusList ** +get_list_string (DBusHashTable *table, + const char *key) +{ + DBusList **list; + + if (key == NULL) + return NULL; + + list = _dbus_hash_table_lookup_string (table, key); + + if (list == NULL) + { + char *new_key; + + list = dbus_new0 (DBusList*, 1); + if (list == NULL) + return NULL; + + new_key = _dbus_strdup (key); + if (new_key == NULL) + { + dbus_free (list); + return NULL; + } + + if (!_dbus_hash_table_insert_string (table, new_key, list)) + { + dbus_free (list); + dbus_free (new_key); + return NULL; + } + } + + return list; +} +#endif + +dbus_bool_t +bus_policy_append_smack_rule (BusPolicy *policy, + const char *label, + BusPolicyRule *rule) +{ +#ifdef DBUS_ENABLE_SMACK + DBusList **list; + + list = get_list_string (policy->rules_by_smack_label, label); + if (list == NULL) + return FALSE; + + if (!_dbus_list_append (list, rule)) + return FALSE; + + bus_policy_rule_ref (rule); +#endif + + return TRUE; +} + dbus_bool_t bus_policy_append_console_rule (BusPolicy *policy, dbus_bool_t at_console, @@ -653,6 +747,31 @@ merge_id_hash (DBusHashTable *dest, return TRUE; } +#ifdef DBUS_ENABLE_SMACK +static dbus_bool_t +merge_string_hash (DBusHashTable *dest, + DBusHashTable *to_absorb) +{ + DBusHashIter iter; + + _dbus_hash_iter_init (to_absorb, &iter); + while (_dbus_hash_iter_next (&iter)) + { + const char *absorb_label = _dbus_hash_iter_get_string_key(&iter); + DBusList **list = _dbus_hash_iter_get_value (&iter); + DBusList **target = get_list_string (dest, absorb_label); + + if (target == NULL) + return FALSE; + + if (!append_copy_of_policy_list (target, list)) + return FALSE; + } + + return TRUE; +} +#endif + dbus_bool_t bus_policy_merge (BusPolicy *policy, BusPolicy *to_absorb) @@ -685,6 +804,12 @@ bus_policy_merge (BusPolicy *policy, to_absorb->rules_by_gid)) return FALSE; +#ifdef DBUS_ENABLE_SMACK + if (!merge_string_hash (policy->rules_by_smack_label, + to_absorb->rules_by_smack_label)) + return FALSE; +#endif + return TRUE; } @@ -873,7 +998,7 @@ bus_client_policy_check_can_send (BusClientPolicy *policy, { 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 */ diff --git a/bus/policy.h b/bus/policy.h index 3ff6f482..20d0a39a 100644 --- a/bus/policy.h +++ b/bus/policy.h @@ -130,6 +130,9 @@ dbus_bool_t bus_policy_append_user_rule (BusPolicy *policy, dbus_bool_t bus_policy_append_group_rule (BusPolicy *policy, dbus_gid_t gid, BusPolicyRule *rule); +dbus_bool_t bus_policy_append_smack_rule (BusPolicy *policy, + const char *label, + BusPolicyRule *rule); dbus_bool_t bus_policy_append_console_rule (BusPolicy *policy, dbus_bool_t at_console, BusPolicyRule *rule); diff --git a/bus/smack.c b/bus/smack.c index b8542c2f..d4546a3a 100644 --- a/bus/smack.c +++ b/bus/smack.c @@ -29,11 +29,17 @@ #include "connection.h" #include "services.h" #include "utils.h" +#include "policy.h" #ifdef DBUS_ENABLE_SMACK #include <sys/smack.h> #endif +#define SMACK_WRITE "W" +#define SMACK_READ "R" +#define SMACK_READ_WRITE "RW" + + #ifdef DBUS_ENABLE_SMACK static char * bus_smack_get_label (DBusConnection *connection) @@ -130,3 +136,108 @@ err: return FALSE; #endif } + +#ifdef DBUS_ENABLE_SMACK +static dbus_bool_t +bus_smack_has_access (const char *subject, const char *object, + const char *access) +{ + return (smack_have_access (subject, object, access) == 1 ? TRUE : FALSE); +} +#endif + + +/** + * Calculate the list of rules that apply to a connection. + * + * @param connection The inbound conenction + * @param rules_by_smack_label The table of object labels -> rules mapping + * @param nomem_err (out) If a nomem situation is encountered this value is set to TRUE. + * @returns the list of permitted rules if it exists and no errors were encountered otherwise NULL. + */ +DBusList** +bus_smack_generate_allowed_list (DBusConnection *connection, + DBusHashTable *rules_by_smack_label, + dbus_bool_t *nomem_err) +{ +#ifdef DBUS_ENABLE_SMACK + char *subject_label; + DBusHashIter iter; + dbus_bool_t is_allowed; + DBusList **allowed_list; + + /* the label of the subject, is the label on the new connection, + either the service itself or one of its clients */ + subject_label = bus_smack_get_label (connection); + if (subject_label == NULL) + return NULL; + + allowed_list = dbus_new0 (DBusList*, 1); + if (allowed_list == NULL) + goto nomem; + + /* Iterate over all the smack labels we have parsed from the .conf files */ + _dbus_hash_iter_init (rules_by_smack_label, &iter); + while (_dbus_hash_iter_next (&iter)) + { + DBusList *link; + const char *object_label = _dbus_hash_iter_get_string_key (&iter); + /* the list here is all the rules that are 'protected' + by the SMACK label named $object_label */ + DBusList **list = _dbus_hash_iter_get_value (&iter); + + link = _dbus_list_get_first_link (list); + while (link != NULL) + { + BusPolicyRule *rule = link->data; + link = _dbus_list_get_next_link (list, link); + is_allowed = FALSE; + + switch (rule->type) + { + case BUS_POLICY_RULE_OWN: + is_allowed = bus_smack_has_access (subject_label, + object_label, + SMACK_READ_WRITE); + break; + case BUS_POLICY_RULE_SEND: + is_allowed = bus_smack_has_access (subject_label, + object_label, + SMACK_WRITE); + break; + case BUS_POLICY_RULE_RECEIVE: + is_allowed = bus_smack_has_access (subject_label, + object_label, + SMACK_READ); + break; + default: + continue; + } + + if (is_allowed) + { + if (!_dbus_list_append (allowed_list, rule)) + goto nomem; + + bus_policy_rule_ref (rule); + } + + _dbus_verbose ("permission request subject (%s) -> object (%s) : %s", subject_label, object_label, (is_allowed ? "GRANTED" : "REJECTED")); + } + } + + dbus_free(subject_label); + return allowed_list; + +nomem: + if (allowed_list != NULL) + _dbus_list_clear (allowed_list); + + dbus_free(subject_label); + *nomem_err = TRUE; + return NULL; + +#else + return NULL; +#endif +} diff --git a/bus/smack.h b/bus/smack.h index 04a4a2a9..6b1dfad6 100644 --- a/bus/smack.h +++ b/bus/smack.h @@ -27,10 +27,14 @@ #define SMACK_H #include "bus.h" +#include <dbus/dbus-hash.h> dbus_bool_t bus_smack_handle_get_connection_context (DBusConnection *connection, BusTransaction *transaction, DBusMessage *message, DBusError *error); +DBusList **bus_smack_generate_allowed_list (DBusConnection *connection, + DBusHashTable *label_rules, + dbus_bool_t *error); #endif // SMACK_H |