DA: Skip initializing failed_bssids list when eapol failure case
[platform/upstream/connman.git] / plugins / session_policy_local.c
old mode 100644 (file)
new mode 100755 (executable)
index d9f9aef..32b9c69
@@ -2,7 +2,7 @@
  *
  *  Connection Manager
  *
- *  Copyright (C) 2012  BMW Car IT GbmH. All rights reserved.
+ *  Copyright (C) 2012-2014  BMW Car IT GmbH.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2 as
@@ -42,6 +42,8 @@
 #include <connman/dbus.h>
 #include <connman/inotify.h>
 
+#include "src/shared/util.h"
+
 #define POLICYDIR STORAGEDIR "/session_policy_local"
 
 #define MODE           (S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | \
@@ -64,7 +66,7 @@ static GHashTable *gid_hash;     /* (gid, policy_group) */
 struct policy_file {
        /*
         * A valid file is a keyfile with one ore more groups. All
-        * groups are keept in this list.
+        * groups are kept in this list.
         */
        GSList *groups;
 };
@@ -88,6 +90,7 @@ struct policy_group {
 /* A struct policy_config object is created and owned by a session. */
 struct policy_config {
        char *selinux;
+       char *selinux_context;
        char *uid;
        GSList *gids;
 
@@ -131,7 +134,7 @@ static char *parse_selinux_type(const char *context)
 
        /*
         * SELinux combines Role-Based Access Control (RBAC), Type
-        * Enforcment (TE) and optionally Multi-Level Security (MLS).
+        * Enforcement (TE) and optionally Multi-Level Security (MLS).
         *
         * When SELinux is enabled all processes and files are labeled
         * with a contex that contains information such as user, role
@@ -142,7 +145,7 @@ static char *parse_selinux_type(const char *context)
         *
         * For identifyng application we (ab)using the type
         * information. In the above example the haifux_exec_t type
-        * will be transfered to haifux_t as defined in the domain
+        * will be transferred to haifux_t as defined in the domain
         * transition and thus we are able to identify the application
         * as haifux_t.
         */
@@ -167,29 +170,42 @@ static void finish_create(struct policy_config *policy,
                                connman_session_config_func_t cb,
                                void *user_data)
 {
-       struct policy_group *group;
+       struct policy_group *group = NULL;
        GSList *list;
 
-       group = g_hash_table_lookup(selinux_hash, policy->selinux);
-       if (group != NULL) {
+       if (policy->selinux)
+               group = g_hash_table_lookup(selinux_hash, policy->selinux);
+
+       if (group) {
                set_policy(policy, group);
+
+               policy->config->id_type = CONNMAN_SESSION_ID_TYPE_LSM;
+               policy->config->id = g_strdup(policy->selinux_context);
                goto done;
        }
 
-       group = g_hash_table_lookup(uid_hash, policy->uid);
-       if (group != NULL) {
+       if (policy->uid)
+               group = g_hash_table_lookup(uid_hash, policy->uid);
+
+       if (group) {
                set_policy(policy, group);
+
+               policy->config->id_type = CONNMAN_SESSION_ID_TYPE_UID;
+               policy->config->id = g_strdup(policy->uid);
                goto done;
        }
 
-       for (list = policy->gids; list != NULL; list = list->next) {
+       for (list = policy->gids; list; list = list->next) {
                char *gid = list->data;
 
                group = g_hash_table_lookup(gid_hash, gid);
-               if (group == NULL)
+               if (!group)
                        continue;
 
                set_policy(policy, group);
+
+               policy->config->id_type = CONNMAN_SESSION_ID_TYPE_GID;
+               policy->config->id = g_strdup(gid);
                break;
        }
 done:
@@ -217,15 +233,22 @@ static void selinux_context_reply(const unsigned char *context, void *user_data,
 
        DBG("session %p", policy->session);
 
+       if (err == -EIO) {
+               /* No SELinux support, drop back to UID/GID only mode */
+               finish_create(policy, cb, cbd->user_data);
+               goto done;
+       }
+
        if (err < 0) {
-               failed_create(policy, cb, user_data, err);
+               failed_create(policy, cb, cbd->user_data, err);
                goto done;
        }
 
        DBG("SELinux context %s", context);
 
-       ident = parse_selinux_type((const char*)context);
-       if (ident != NULL)
+       policy->selinux_context = g_strdup((const char *)context);
+       ident = parse_selinux_type(policy->selinux_context);
+       if (ident)
                policy->selinux = g_strdup(ident);
 
        finish_create(policy, cb, cbd->user_data);
@@ -248,13 +271,11 @@ static void get_uid_reply(unsigned int uid, void *user_data, int err)
 
        DBG("session %p uid %d", policy->session, uid);
 
-       if (err < 0) {
-               cleanup_config(policy);
+       if (err < 0)
                goto err;
-       }
 
        pwd = getpwuid((uid_t)uid);
-       if (pwd == NULL) {
+       if (!pwd) {
                if (errno != 0)
                        err = -errno;
                else
@@ -267,7 +288,7 @@ static void get_uid_reply(unsigned int uid, void *user_data, int err)
        nrgroups = 0;
        getgrouplist(pwd->pw_name, pwd->pw_gid, NULL, &nrgroups);
        groups = g_try_new0(gid_t, nrgroups);
-       if (groups == NULL) {
+       if (!groups) {
                err = -ENOMEM;
                goto err;
        }
@@ -278,7 +299,7 @@ static void get_uid_reply(unsigned int uid, void *user_data, int err)
 
        for (i = 0; i < nrgroups; i++) {
                grp = getgrgid(groups[i]);
-               if (grp == NULL) {
+               if (!grp) {
                        if (errno != 0)
                                err = -errno;
                        else
@@ -310,7 +331,7 @@ static void get_uid_reply(unsigned int uid, void *user_data, int err)
        return;
 
 err:
-       failed_create(NULL, cb, user_data, err);
+       failed_create(policy, cb, cbd->user_data, err);
        g_free(cbd);
        g_free(groups);
 }
@@ -353,7 +374,7 @@ static void policy_local_destroy(struct connman_session *session)
        DBG("session %p", session);
 
        policy = g_hash_table_lookup(session_hash, session);
-       if (policy == NULL)
+       if (!policy)
                return;
 
        g_hash_table_remove(session_hash, session);
@@ -373,7 +394,7 @@ static int load_keyfile(const char *pathname, GKeyFile **keyfile)
 
        *keyfile = g_key_file_new();
 
-       if (g_key_file_load_from_file(*keyfile, pathname, 0, &error) == FALSE)
+       if (!g_key_file_load_from_file(*keyfile, pathname, 0, &error))
                goto err;
 
        return 0;
@@ -410,7 +431,7 @@ static int load_policy(GKeyFile *keyfile, const char *groupname,
        group->uid = g_key_file_get_string(keyfile, groupname,
                                                "uid", NULL);
 
-       if (group->selinux == NULL && group->gid == NULL && group->uid == NULL)
+       if (!group->selinux && !group->gid && !group->uid)
                return -EINVAL;
 
        config->priority = g_key_file_get_boolean(keyfile, groupname,
@@ -418,14 +439,14 @@ static int load_policy(GKeyFile *keyfile, const char *groupname,
 
        str = g_key_file_get_string(keyfile, groupname, "RoamingPolicy",
                                NULL);
-       if (str != NULL) {
+       if (str) {
                config->roaming_policy = connman_session_parse_roaming_policy(str);
                g_free(str);
        }
 
        str = g_key_file_get_string(keyfile, groupname, "ConnectionType",
                                NULL);
-       if (str != NULL) {
+       if (str) {
                config->type = connman_session_parse_connection_type(str);
                g_free(str);
        }
@@ -435,10 +456,12 @@ static int load_policy(GKeyFile *keyfile, const char *groupname,
 
        str = g_key_file_get_string(keyfile, groupname, "AllowedBearers",
                                NULL);
-       if (str != NULL) {
+       if (str) {
+               g_slist_free(config->allowed_bearers);
+               config->allowed_bearers = NULL;
                tokens = g_strsplit(str, " ", 0);
 
-               for (i = 0; tokens[i] != NULL; i++) {
+               for (i = 0; tokens[i]; i++) {
                        err = connman_session_parse_bearers(tokens[i],
                                        &config->allowed_bearers);
                        if (err < 0)
@@ -459,7 +482,7 @@ static void update_session(struct policy_config *policy)
 {
        DBG("policy %p session %p", policy, policy->session);
 
-       if (policy->session == NULL)
+       if (!policy->session)
                return;
 
        if (connman_session_config_update(policy->session) < 0)
@@ -481,12 +504,14 @@ static void cleanup_config(gpointer user_data)
 
        DBG("policy %p group %p", policy, policy->group);
 
-       if (policy->group != NULL)
+       if (policy->group)
                policy->group->sessions =
                        g_slist_remove(policy->group->sessions, policy);
 
        g_slist_free(policy->config->allowed_bearers);
+       g_free(policy->config->id);
        g_free(policy->config);
+       g_free(policy->selinux_context);
        g_free(policy->selinux);
        g_free(policy->uid);
        g_slist_free_full(policy->gids, g_free);
@@ -502,12 +527,13 @@ static void cleanup_group(gpointer user_data)
        g_slist_free_full(group->sessions, set_default_config);
 
        g_slist_free(group->config->allowed_bearers);
+       g_free(group->config->id);
        g_free(group->config);
-       if (group->selinux != NULL)
+       if (group->selinux)
                g_hash_table_remove(selinux_hash, group->selinux);
-       if (group->uid != NULL)
+       if (group->uid)
                g_hash_table_remove(uid_hash, group->uid);
-       if (group->gid != NULL)
+       if (group->gid)
                g_hash_table_remove(gid_hash, group->gid);
        g_free(group->selinux);
        g_free(group->uid);
@@ -530,18 +556,48 @@ static void recheck_sessions(void)
        GHashTableIter iter;
        gpointer value, key;
        struct policy_group *group = NULL;
+       GSList *list;
 
        g_hash_table_iter_init(&iter, session_hash);
-       while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
+       while (g_hash_table_iter_next(&iter, &key, &value)) {
                struct policy_config *policy = value;
 
-               if (policy->group != NULL)
+               if (policy->group)
                        continue;
 
-               group = g_hash_table_lookup(selinux_hash, policy->selinux);
-               if (group != NULL) {
+               if (policy->selinux)
+                       group = g_hash_table_lookup(selinux_hash,
+                                                       policy->selinux);
+               if (group) {
+                       policy->config->id_type = CONNMAN_SESSION_ID_TYPE_LSM;
+                       g_free(policy->config->id);
+                       policy->config->id = g_strdup(policy->selinux_context);
+                       update_session(policy);
+                       continue;
+               }
+
+               group = g_hash_table_lookup(uid_hash, policy->uid);
+               if (group) {
                        set_policy(policy, group);
+
+                       policy->config->id_type = CONNMAN_SESSION_ID_TYPE_UID;
+                       g_free(policy->config->id);
+                       policy->config->id = g_strdup(policy->uid);
                        update_session(policy);
+                       continue;
+               }
+
+               for (list = policy->gids; list; list = list->next) {
+                       char *gid = list->data;
+                       group = g_hash_table_lookup(gid_hash, gid);
+                       if (group) {
+                               set_policy(policy, group);
+
+                               policy->config->id_type = CONNMAN_SESSION_ID_TYPE_GID;
+                               g_free(policy->config->id);
+                               policy->config->id = g_strdup(gid);
+                               update_session(policy);
+                       }
                }
        }
 }
@@ -565,9 +621,9 @@ static int load_file(const char *filename, struct policy_file *file)
 
        groupnames = g_key_file_get_groups(keyfile, NULL);
 
-       for (i = 0; groupnames[i] != NULL; i++) {
+       for (i = 0; groupnames[i]; i++) {
                group = g_new0(struct policy_group, 1);
-               group->config = g_new0(struct connman_session_config, 1);
+               group->config = connman_session_create_default_config();
 
                err = load_policy(keyfile, groupnames[i], group);
                if (err < 0) {
@@ -575,13 +631,13 @@ static int load_file(const char *filename, struct policy_file *file)
                        g_free(group);
                        break;
                }
-               if (group->selinux != NULL)
+               if (group->selinux)
                        g_hash_table_replace(selinux_hash, group->selinux, group);
 
-               if (group->uid != NULL)
+               if (group->uid)
                        g_hash_table_replace(uid_hash, group->uid, group);
 
-               if (group->gid != NULL)
+               if (group->gid)
                        g_hash_table_replace(gid_hash, group->gid, group);
 
                file->groups = g_slist_prepend(file->groups, group);
@@ -597,18 +653,18 @@ static int load_file(const char *filename, struct policy_file *file)
        return err;
 }
 
-static connman_bool_t is_filename_valid(const char *filename)
+static bool is_filename_valid(const char *filename)
 {
-       if (filename == NULL)
-               return FALSE;
+       if (!filename)
+               return false;
 
        if (filename[0] == '.')
-               return FALSE;
+               return false;
 
        return g_str_has_suffix(filename, ".policy");
 }
 
-static int read_policies()
+static int read_policies(void)
 {
        GDir *dir;
        const gchar *filename;
@@ -617,11 +673,11 @@ static int read_policies()
        DBG("");
 
        dir = g_dir_open(POLICYDIR, 0, NULL);
-       if (dir == NULL)
+       if (!dir)
                return -EINVAL;
 
-       while ((filename = g_dir_read_name(dir)) != NULL) {
-               if (is_filename_valid(filename) == FALSE)
+       while ((filename = g_dir_read_name(dir))) {
+               if (!is_filename_valid(filename))
                        continue;
 
                file = g_new0(struct policy_file, 1);
@@ -649,7 +705,7 @@ static void notify_handler(struct inotify_event *event,
        if (event->mask & IN_CREATE)
                return;
 
-       if (is_filename_valid(filename) == FALSE)
+       if (!is_filename_valid(filename))
                return;
 
        /*
@@ -683,7 +739,7 @@ static int session_policy_local_init(void)
        DBG("");
 
        /* If the dir doesn't exist, create it */
-       if (g_file_test(POLICYDIR, G_FILE_TEST_IS_DIR) == FALSE) {
+       if (!g_file_test(POLICYDIR, G_FILE_TEST_IS_DIR)) {
                if (mkdir(POLICYDIR, MODE) < 0) {
                        if (errno != EEXIST)
                                return -errno;
@@ -691,7 +747,7 @@ static int session_policy_local_init(void)
        }
 
        connection = connman_dbus_get_connection();
-       if (connection == NULL)
+       if (!connection)
                return -EIO;
 
        file_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
@@ -722,19 +778,19 @@ err_notify:
        connman_inotify_unregister(POLICYDIR, notify_handler);
 
 err:
-       if (file_hash != NULL)
+       if (file_hash)
                g_hash_table_destroy(file_hash);
 
-       if (session_hash != NULL)
+       if (session_hash)
                g_hash_table_destroy(session_hash);
 
-       if (selinux_hash != NULL)
+       if (selinux_hash)
                g_hash_table_destroy(selinux_hash);
 
-       if (uid_hash != NULL)
+       if (uid_hash)
                g_hash_table_destroy(uid_hash);
 
-       if (gid_hash != NULL)
+       if (gid_hash)
                g_hash_table_destroy(gid_hash);
 
        connman_session_policy_unregister(&session_policy_local);