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

Reply via email to