summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bus/config-parser.c38
-rw-r--r--bus/policy.c141
-rw-r--r--bus/policy.h3
-rw-r--r--bus/smack.c111
-rw-r--r--bus/smack.h4
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