Hi, On Tue, 2013-05-07 at 10:27 +0200, Daniel Wagner wrote: > From: Daniel Wagner <daniel.wag...@bmw-carit.de> > > The old assumption was that a config file is associtated > with one session only. With introducing UID/GID support a policy > might be used for several sessions. Furthermore, it was assumed > that the file name is the key/ident to identify a session and > a file containts exactly one policy. > > Here are the new rules for writing a policy file. > > - A valid file name contains letters or numbers and must have a '.policy' > suffix. > - The file name has not semantical meaning > - A policy file may contain contain more than 1 policy > - Each policy entry starts with 'policy_' > - Each policy entry shall have one and exactly one valid key (e.g. selinux) > > And now some comments on the implementation. We have two main hash > tables, file_hash and session_hash which own 'the file' respectively > the session config. Additionally we have a hash table which connects a > policy with a session (selinux_hash). > --- > plugins/session_policy_local.c | 402 > ++++++++++++++++++++++++++--------------- > 1 file changed, 258 insertions(+), 144 deletions(-) > > diff --git a/plugins/session_policy_local.c b/plugins/session_policy_local.c > index 6cd876c..f0e4ff4 100644 > --- a/plugins/session_policy_local.c > +++ b/plugins/session_policy_local.c > @@ -46,33 +46,78 @@ > > static DBusConnection *connection; > > -static GHashTable *policy_hash; > -static GHashTable *session_hash; > +static GHashTable *file_hash; /* (filename, policy_file) */ > +static GHashTable *session_hash; /* (connman_session, policy_config) */ > + > +/* Global lookup table for mapping sessions to policies */ > +static GHashTable *selinux_hash; /* (lsm context, policy_group) */ > > struct create_data { > struct connman_session *session; > }; > > -struct policy_data { > - int refcount; > - char *ident; > +/* > + * A instance of struct policy_file is created per file in > + * POLICYDIR. > + */ > +struct policy_file { > + /* > + * A valid file is a keyfile with one ore more groups. All > + * groups are keept in this list. > + */ > + GSList *groups; > +}; > > - struct connman_session *session; > +struct policy_group { > + char *selinux; > + > + /* > + * Each policy_group owns a config and is not shared with > + * sessions. Instead each session copies the valued from this > + * object. > + */ > struct connman_session_config *config; > + > + /* All 'users' of this policy. */ > + GSList *sessions; > +}; > + > +/* A struct policy_config object is created and owned by a session. */ > +struct policy_config { > + char *selinux; > + > + /* The policy config owned by the session */ > + struct connman_session_config *config; > + > + /* To which policy belongs this policy_config */ > + struct connman_session *session; > + /* > + * Points to the policy_group when a config has been applied > + * from a file. > + */ > + struct policy_group *group; > }; > > -static void cleanup_policy(gpointer user_data) > +static void copy_session_config(struct connman_session_config *dst, > + struct connman_session_config *src) > { > - struct policy_data *policy = user_data; > + g_slist_free(dst->allowed_bearers); > + dst->allowed_bearers = g_slist_copy(src->allowed_bearers); > + dst->ecall = src->ecall; > + dst->type = src->type; > + dst->roaming_policy = src->roaming_policy; > + dst->priority = src->priority; > +} > > - DBG("policy %p", policy); > +static void set_policy(struct policy_config *policy, > + struct policy_group *group) > +{ > + DBG("policy %p group %p", policy, group); > > - if (policy->config != NULL) > - g_slist_free(policy->config->allowed_bearers); > + group->sessions = g_slist_prepend(group->sessions, policy); > + policy->group = group; > > - g_free(policy->ident); > - g_free(policy->config); > - g_free(policy); > + copy_session_config(policy->config, group->config); > } > > static char *parse_selinux_type(const char *context) > @@ -111,51 +156,27 @@ static char *parse_selinux_type(const char *context) > return ident; > } > > -static struct policy_data *create_policy(const char *ident) > +static struct policy_config *create_policy(void) > { > - struct policy_data *policy; > + struct policy_config *policy; > > - DBG("ident %s", ident); > - > - policy = g_new0(struct policy_data, 1); > - policy->refcount = 1; > + policy = g_new0(struct policy_config, 1); > > DBG("policy %p", policy); > > policy->config = connman_session_create_default_config(); > - policy->ident = g_strdup(ident); > - > - g_hash_table_replace(policy_hash, policy->ident, policy); > > return policy; > } > > -static struct policy_data *policy_ref(struct policy_data *policy) > -{ > - DBG("%p %s ref %d", policy, policy->ident, policy->refcount + 1); > - > - __sync_fetch_and_add(&policy->refcount, 1); > - > - return policy; > -} > - > -static void policy_unref(struct policy_data *policy) > -{ > - DBG(" %p %s ref %d", policy, policy->ident, policy->refcount - 1); > - > - if (__sync_fetch_and_sub(&policy->refcount, 1) != 1) > - return; > - > - g_hash_table_remove(policy_hash, policy->ident); > -}; > - > static void selinux_context_reply(const unsigned char *context, void > *user_data, > int err) > { > struct cb_data *cbd = user_data; > connman_session_config_func_t cb = cbd->cb; > struct create_data *data = cbd->data; > - struct policy_data *policy; > + struct policy_config *policy; > + struct policy_group *group; > struct connman_session_config *config = NULL; > char *ident = NULL; > > @@ -172,12 +193,13 @@ static void selinux_context_reply(const unsigned char > *context, void *user_data, > goto done; > } > > - policy = g_hash_table_lookup(policy_hash, ident); > - if (policy != NULL) { > - policy_ref(policy); > - policy->session = data->session; > - } else > - policy = create_policy(ident); > + policy = create_policy(); > + policy->selinux = g_strdup(ident); > + policy->session = data->session; > + > + group = g_hash_table_lookup(selinux_hash, policy->selinux); > + if (group != NULL) > + set_policy(policy, group); > > g_hash_table_replace(session_hash, data->session, policy); > config = policy->config; > @@ -232,8 +254,6 @@ static void policy_local_destroy(struct connman_session > *session) > return; > > g_hash_table_remove(session_hash, session); > - policy->session = NULL; > - policy_unref(policy); > } > > static struct connman_session_policy session_policy_local = { > @@ -248,8 +268,6 @@ static int load_keyfile(const char *pathname, GKeyFile > **keyfile) > GError *error = NULL; > int err; > > - DBG("Loading %s", pathname); > - > *keyfile = g_key_file_new(); > > if (g_key_file_load_from_file(*keyfile, pathname, 0, &error) == FALSE) > @@ -273,57 +291,41 @@ err: > return err; > } > > -static int load_policy(struct policy_data *policy) > +static int load_policy(GKeyFile *keyfile, const char *groupname, > + struct policy_group *group) > { > - struct connman_session_config *config = policy->config; > - GKeyFile *keyfile; > - char *pathname; > + struct connman_session_config *config = group->config; > char *str, **tokens; > int i, err = 0; > > - connman_session_set_default_config(config); > - > - pathname = g_strdup_printf("%s/%s", POLICYDIR, policy->ident); > + group->selinux = g_key_file_get_string(keyfile, groupname, > + "selinux", NULL); > + if (group->selinux == NULL) > + return -EINVAL; > > - err = load_keyfile(pathname, &keyfile); > - if (err < 0) { > - g_free(pathname); > - > - if (err == -ENOENT) { > - /* Ignore empty files */ > - return 0; > - } > - > - return err; > - } > - > - config->priority = g_key_file_get_boolean(keyfile, "Default", > + config->priority = g_key_file_get_boolean(keyfile, groupname, > "Priority", NULL); > > - str = g_key_file_get_string(keyfile, "Default", "RoamingPolicy", > + str = g_key_file_get_string(keyfile, groupname, "RoamingPolicy", > NULL); > if (str != NULL) { > config->roaming_policy = > connman_session_parse_roaming_policy(str); > g_free(str); > } > > - str = g_key_file_get_string(keyfile, "Default", "ConnectionType", > + str = g_key_file_get_string(keyfile, groupname, "ConnectionType", > NULL); > if (str != NULL) { > config->type = connman_session_parse_connection_type(str); > g_free(str); > } > > - config->ecall = g_key_file_get_boolean(keyfile, "Default", > + config->ecall = g_key_file_get_boolean(keyfile, groupname, > "EmergencyCall", NULL); > > - str = g_key_file_get_string(keyfile, "Default", "AllowedBearers", > + str = g_key_file_get_string(keyfile, groupname, "AllowedBearers", > NULL); > - > if (str != NULL) { > - g_slist_free(config->allowed_bearers); > - config->allowed_bearers = NULL; > - > tokens = g_strsplit(str, " ", 0); > > for (i = 0; tokens[i] != NULL; i++) { > @@ -337,13 +339,11 @@ static int load_policy(struct policy_data *policy) > g_strfreev(tokens); > } > > - g_key_file_free(keyfile); > - g_free(pathname); > + DBG("group %p selinux %s", group, group->selinux); > > return err; > } > - > -static void update_session(struct policy_data *policy) > +static void update_session(struct policy_config *policy) > { > DBG("policy %p session %p", policy, policy->session); > > @@ -354,90 +354,199 @@ static void update_session(struct policy_data *policy) > connman_session_destroy(policy->session); > } > > -static void remove_policy(struct policy_data *policy) > +static void set_default_config(gpointer user_data) > { > - if (policy->session != NULL) > - connman_session_set_default_config(policy->config); > + struct policy_config *policy = user_data; > + > + connman_session_set_default_config(policy->config); > + policy->group = NULL; > update_session(policy); > +} > + > +static void cleanup_config(gpointer user_data) > +{ > + struct policy_config *policy = user_data; > + > + DBG("policy %p group %p", policy, policy->group); > > - policy_unref(policy); > + if (policy->group != NULL) > + policy->group->sessions = > + g_slist_remove(policy->group->sessions, policy); > + > + g_slist_free(policy->config->allowed_bearers); > + g_free(policy->config); > + g_free(policy->selinux); > + g_free(policy); > } > > -static void notify_handler(struct inotify_event *event, > - const char *ident) > +static void cleanup_group(gpointer user_data) > { > - struct policy_data *policy; > - int err; > + struct policy_group *group = user_data; > > - if (ident == NULL) > - return; > + DBG("group %p", group); > > - policy = g_hash_table_lookup(policy_hash, ident); > + g_slist_free_full(group->sessions, set_default_config); > > - if (event->mask & (IN_CREATE | IN_MOVED_TO)) { > - connman_info("Policy added for '%s'", ident); > + g_slist_free(group->config->allowed_bearers); > + g_free(group->config); > + if (group->selinux != NULL) > + g_hash_table_remove(selinux_hash, group->selinux); > + g_free(group->selinux); > + g_free(group); > +} > > - if (policy != NULL) > - policy_ref(policy); > - else > - policy = create_policy(ident); > +static void cleanup_file(gpointer user_data) > +{ > + struct policy_file *file = user_data; > > - err = load_policy(policy); > - if (err < 0) { > - connman_warn("Loading policy file '%s' failed with %s", > - ident, strerror(-err)); > - return; > - } > + DBG("file %p", file); > + > + g_slist_free_full(file->groups, cleanup_group); > + g_free(file); > +} > + > +static void recheck_sessions(void) > +{ > + GHashTableIter iter; > + gpointer value, key; > + struct policy_group *group = NULL; > + > + g_hash_table_iter_init(&iter, session_hash); > + while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) { > + struct policy_config *policy = value; > + > + if (policy->group != NULL) > + continue; > + > + group = g_hash_table_lookup(selinux_hash, policy->selinux); > + if (group != NULL) > + set_policy(policy, group); > + > + update_session(policy);
If group == NULL after the hash table lookup, do we need to update_session(policy) even though nothing has changed or is it an error? Cheers, Patrik _______________________________________________ connman mailing list connman@connman.net https://lists.connman.net/mailman/listinfo/connman