*
* 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
#include <string.h>
#include <sys/inotify.h>
#include <sys/stat.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
#include <glib.h>
#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 | \
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) */
-struct create_data {
- struct connman_session *session;
- connman_session_config_cb callback;
- void *user_data;
+/* Global lookup tables for mapping sessions to policies */
+static GHashTable *selinux_hash; /* (lsm context, policy_group) */
+static GHashTable *uid_hash; /* (uid, policy_group) */
+static GHashTable *gid_hash; /* (gid, policy_group) */
+
+/*
+ * 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 policy_data {
- int refcount;
- char *ident;
+struct policy_group {
+ char *selinux;
+ char *uid;
+ char *gid;
- struct connman_session *session;
+ /*
+ * 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;
};
-static void cleanup_policy(gpointer user_data)
+/* A struct policy_config object is created and owned by a session. */
+struct policy_config {
+ char *selinux;
+ char *selinux_context;
+ char *uid;
+ GSList *gids;
+
+ /* 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 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;
+}
- if (policy->config != NULL)
- g_slist_free(policy->config->allowed_bearers);
+static void set_policy(struct policy_config *policy,
+ struct policy_group *group)
+{
+ DBG("policy %p group %p", policy, group);
- g_free(policy->ident);
- g_free(policy->config);
- g_free(policy);
+ group->sessions = g_slist_prepend(group->sessions, policy);
+ policy->group = group;
+
+ copy_session_config(policy->config, group->config);
}
-static char *parse_ident(const unsigned char *context)
+static char *parse_selinux_type(const char *context)
{
- char *str, *ident, **tokens;
+ char *ident, **tokens;
/*
* SELinux combines Role-Based Access Control (RBAC), Type
* as haifux_t.
*/
- str = g_strdup((const gchar*)context);
- if (str == NULL)
- return NULL;
-
- DBG("SELinux context %s", str);
-
- tokens = g_strsplit(str, ":", 0);
- if (tokens == NULL) {
- g_free(str);
+ tokens = g_strsplit(context, ":", 0);
+ if (g_strv_length(tokens) < 2) {
+ g_strfreev(tokens);
return NULL;
}
ident = g_strdup(tokens[2]);
g_strfreev(tokens);
- g_free(str);
return ident;
}
-static struct policy_data *create_policy(const char *ident)
+static void cleanup_config(gpointer user_data);
+
+static void finish_create(struct policy_config *policy,
+ connman_session_config_func_t cb,
+ void *user_data)
{
- struct policy_data *policy;
+ struct policy_group *group = NULL;
+ GSList *list;
- DBG("ident %s", ident);
+ if (policy->selinux)
+ group = g_hash_table_lookup(selinux_hash, policy->selinux);
- policy = g_try_new0(struct policy_data, 1);
- if (policy == NULL)
- return NULL;
+ if (group) {
+ set_policy(policy, group);
- policy->config = connman_session_create_default_config();
- if (policy->config == NULL) {
- g_free(policy);
- return NULL;
+ policy->config->id_type = CONNMAN_SESSION_ID_TYPE_LSM;
+ policy->config->id = g_strdup(policy->selinux_context);
+ goto done;
}
- policy->refcount = 1;
- policy->ident = g_strdup(ident);
+ if (policy->uid)
+ group = g_hash_table_lookup(uid_hash, policy->uid);
- g_hash_table_replace(policy_hash, policy->ident, policy);
+ if (group) {
+ set_policy(policy, group);
- return policy;
-}
+ policy->config->id_type = CONNMAN_SESSION_ID_TYPE_UID;
+ policy->config->id = g_strdup(policy->uid);
+ goto done;
+ }
-static struct policy_data *policy_ref(struct policy_data *policy)
-{
- DBG("%p %s ref %d", policy, policy->ident, policy->refcount + 1);
+ for (list = policy->gids; list; list = list->next) {
+ char *gid = list->data;
- __sync_fetch_and_add(&policy->refcount, 1);
+ group = g_hash_table_lookup(gid_hash, gid);
+ if (!group)
+ continue;
- return policy;
+ set_policy(policy, group);
+
+ policy->config->id_type = CONNMAN_SESSION_ID_TYPE_GID;
+ policy->config->id = g_strdup(gid);
+ break;
+ }
+done:
+ g_hash_table_replace(session_hash, policy->session, policy);
+
+ (*cb)(policy->session, policy->config, user_data, 0);
}
-static void policy_unref(struct policy_data *policy)
+static void failed_create(struct policy_config *policy,
+ connman_session_config_func_t cb,
+ void *user_data, int err)
{
- DBG(" %p %s ref %d", policy, policy->ident, policy->refcount - 1);
+ (*cb)(policy->session, NULL, user_data, err);
- if (__sync_fetch_and_sub(&policy->refcount, 1) != 1)
- return;
-
- g_hash_table_remove(policy_hash, policy->ident);
-};
+ cleanup_config(policy);
+}
static void selinux_context_reply(const unsigned char *context, void *user_data,
int err)
{
- struct create_data *data = user_data;
- struct policy_data *policy;
- struct connman_session_config *config = NULL;
+ struct cb_data *cbd = user_data;
+ connman_session_config_func_t cb = cbd->cb;
+ struct policy_config *policy = cbd->data;
char *ident = NULL;
- DBG("session %p", data->session);
+ DBG("session %p", policy->session);
- if (err < 0)
+ if (err == -EIO) {
+ /* No SELinux support, drop back to UID/GID only mode */
+ finish_create(policy, cb, cbd->user_data);
goto done;
+ }
- ident = parse_ident(context);
- if (ident == NULL) {
- err = -EINVAL;
+ if (err < 0) {
+ failed_create(policy, cb, cbd->user_data, err);
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);
- if (policy == NULL) {
- err = -ENOMEM;
- goto done;
+ DBG("SELinux context %s", context);
+
+ 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);
+
+done:
+ g_free(cbd);
+ g_free(ident);
+}
+
+static void get_uid_reply(unsigned int uid, void *user_data, int err)
+{
+ struct cb_data *cbd = user_data;
+ connman_session_config_func_t cb = cbd->cb;
+ struct policy_config *policy = cbd->data;
+ const char *owner;
+ struct passwd *pwd;
+ struct group *grp;
+ gid_t *groups = NULL;
+ int nrgroups, i;
+
+ DBG("session %p uid %d", policy->session, uid);
+
+ if (err < 0) {
+ cleanup_config(policy);
+ goto err;
+ }
+
+ pwd = getpwuid((uid_t)uid);
+ if (!pwd) {
+ if (errno != 0)
+ err = -errno;
+ else
+ err = -EINVAL;
+ goto err;
+ }
+
+ policy->uid = g_strdup(pwd->pw_name);
+
+ nrgroups = 0;
+ getgrouplist(pwd->pw_name, pwd->pw_gid, NULL, &nrgroups);
+ groups = g_try_new0(gid_t, nrgroups);
+ if (!groups) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ err = getgrouplist(pwd->pw_name, pwd->pw_gid, groups, &nrgroups);
+ if (err < 0)
+ goto err;
+
+ for (i = 0; i < nrgroups; i++) {
+ grp = getgrgid(groups[i]);
+ if (!grp) {
+ if (errno != 0)
+ err = -errno;
+ else
+ err = -EINVAL;
+ goto err;
}
+
+ policy->gids = g_slist_prepend(policy->gids,
+ g_strdup(grp->gr_name));
}
+ g_free(groups);
- g_hash_table_replace(session_hash, data->session, policy);
- config = policy->config;
+ owner = connman_session_get_owner(policy->session);
-done:
- (*data->callback)(data->session, config, data->user_data, err);
+ err = connman_dbus_get_selinux_context(connection, owner,
+ selinux_context_reply, cbd);
+ if (err == 0) {
+ /*
+ * We are able to ask for a SELinux context. Let's defer the
+ * creation of the session config until we get the answer
+ * from D-Bus.
+ */
+ return;
+ }
- g_free(data);
- g_free(ident);
+ finish_create(policy, cb, cbd->user_data);
+ g_free(cbd);
+
+ return;
+
+err:
+ failed_create(NULL, cb, cbd->user_data, err);
+ g_free(cbd);
+ g_free(groups);
}
static int policy_local_create(struct connman_session *session,
- connman_session_config_cb callback,
+ connman_session_config_func_t cb,
void *user_data)
{
- struct create_data *data;
+ struct cb_data *cbd = cb_data_new(cb, user_data);
+ struct policy_config *policy;
const char *owner;
int err;
DBG("session %p", session);
- data = g_try_new0(struct create_data, 1);
- if (data == NULL)
- return -ENOMEM;
+ policy = g_new0(struct policy_config, 1);
+ policy->config = connman_session_create_default_config();
+ policy->session = session;
- data->session = session;
- data->callback = callback;
- data->user_data = user_data;
+ cbd->data = policy;
owner = connman_session_get_owner(session);
- err = connman_dbus_get_selinux_context(connection, owner,
- selinux_context_reply,
- data);
+ err = connman_dbus_get_connection_unix_user(connection, owner,
+ get_uid_reply, cbd);
if (err < 0) {
- connman_error("Could not get SELinux context");
- g_free(data);
+ connman_error("Could not get UID");
+ cleanup_config(policy);
+ g_free(cbd);
return err;
}
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);
- policy->session = NULL;
- policy_unref(policy);
}
static struct connman_session_policy session_policy_local = {
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)
+ if (!g_key_file_load_from_file(*keyfile, pathname, 0, &error))
goto err;
return 0;
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);
+ group->selinux = g_key_file_get_string(keyfile, groupname,
+ "selinux", NULL);
- pathname = g_strdup_printf("%s/%s", POLICYDIR, policy->ident);
- if(pathname == NULL)
- return -ENOMEM;
+ group->gid = g_key_file_get_string(keyfile, groupname,
+ "gid", NULL);
- err = load_keyfile(pathname, &keyfile);
- if (err < 0) {
- g_free(pathname);
+ group->uid = g_key_file_get_string(keyfile, groupname,
+ "uid", NULL);
- if (err == -ENOENT) {
- /* Ignore empty files */
- return 0;
- }
-
- return err;
- }
+ if (!group->selinux && !group->gid && !group->uid)
+ return -EINVAL;
- 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) {
+ if (str) {
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) {
+ if (str) {
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;
-
+ if (str) {
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)
g_strfreev(tokens);
}
- g_key_file_free(keyfile);
- g_free(pathname);
+ DBG("group %p selinux %s uid %s gid %s", group, group->selinux,
+ group->uid, group->gid);
return err;
}
-static void update_session(struct connman_session *session)
+static void update_session(struct policy_config *policy)
{
- if (connman_session_config_update(session) < 0)
- connman_session_destroy(session);
+ DBG("policy %p session %p", policy, policy->session);
+
+ if (!policy->session)
+ return;
+
+ if (connman_session_config_update(policy->session) < 0)
+ connman_session_destroy(policy->session);
}
-static void remove_policy(struct policy_data *policy)
+static void set_default_config(gpointer user_data)
{
- connman_bool_t update = FALSE;
- int err;
+ struct policy_config *policy = user_data;
- if (policy->session != NULL)
- update = TRUE;
+ connman_session_set_default_config(policy->config);
+ policy->group = NULL;
+ update_session(policy);
+}
- policy_unref(policy);
+static void cleanup_config(gpointer user_data)
+{
+ struct policy_config *policy = user_data;
- if (update == FALSE)
- return;
+ DBG("policy %p group %p", policy, policy->group);
- err = connman_session_set_default_config(policy->config);
- if (err < 0) {
- connman_session_destroy(policy->session);
- return;
- }
+ if (policy->group)
+ policy->group->sessions =
+ g_slist_remove(policy->group->sessions, policy);
- update_session(policy->session);
+ 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);
+ 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;
+
+ DBG("group %p", group);
+
+ 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)
+ g_hash_table_remove(selinux_hash, group->selinux);
+ if (group->uid)
+ g_hash_table_remove(uid_hash, group->uid);
+ if (group->gid)
+ g_hash_table_remove(gid_hash, group->gid);
+ g_free(group->selinux);
+ g_free(group->uid);
+ g_free(group->gid);
+ g_free(group);
+}
- if (ident == NULL)
- return;
+static void cleanup_file(gpointer user_data)
+{
+ struct policy_file *file = user_data;
- policy = g_hash_table_lookup(policy_hash, ident);
+ DBG("file %p", file);
- if (event->mask & (IN_CREATE | IN_MOVED_TO)) {
- connman_info("Policy added for '%s'", ident);
+ g_slist_free_full(file->groups, cleanup_group);
+ g_free(file);
+}
- if (policy != NULL)
- policy_ref(policy);
- else
- policy = create_policy(ident);
+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)) {
+ struct policy_config *policy = value;
+
+ if (policy->group)
+ continue;
+
+ 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;
+ }
- err = load_policy(policy);
- if (err < 0) {
- connman_warn("Loading policy file '%s' failed with %s",
- ident, strerror(-err));
- return;
+ 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);
+ }
}
}
+}
- if (policy == NULL)
- return;
+static int load_file(const char *filename, struct policy_file *file)
+{
+ GKeyFile *keyfile;
+ struct policy_group *group;
+ char **groupnames;
+ char *pathname;
+ int err = 0, i;
+
+ DBG("%s", filename);
+
+ pathname = g_strdup_printf("%s/%s", POLICYDIR, filename);
+ err = load_keyfile(pathname, &keyfile);
+ g_free(pathname);
+
+ if (err < 0)
+ return err;
+
+ groupnames = g_key_file_get_groups(keyfile, NULL);
- if (event->mask & IN_MODIFY) {
- connman_info("Policy modifed for '%s'", ident);
+ for (i = 0; groupnames[i]; i++) {
+ group = g_new0(struct policy_group, 1);
+ group->config = g_new0(struct connman_session_config, 1);
- err = load_policy(policy);
+ err = load_policy(keyfile, groupnames[i], group);
if (err < 0) {
- connman_warn("Loading policy file '%s' failed with %s",
- ident, strerror(-err));
- return;
+ g_free(group->config);
+ g_free(group);
+ break;
}
- }
+ if (group->selinux)
+ g_hash_table_replace(selinux_hash, group->selinux, group);
- if (event->mask & (IN_DELETE | IN_MOVED_FROM)) {
- connman_info("Policy deleted for '%s'", ident);
+ if (group->uid)
+ g_hash_table_replace(uid_hash, group->uid, group);
- remove_policy(policy);
- return;
+ if (group->gid)
+ g_hash_table_replace(gid_hash, group->gid, group);
+
+ file->groups = g_slist_prepend(file->groups, group);
}
- if (policy->session != NULL)
- update_session(policy->session);
+ g_strfreev(groupnames);
+
+ if (err < 0)
+ g_slist_free_full(file->groups, cleanup_group);
+
+ g_key_file_free(keyfile);
+
+ return err;
+}
+
+static bool is_filename_valid(const char *filename)
+{
+ if (!filename)
+ return false;
+
+ if (filename[0] == '.')
+ return false;
+
+ return g_str_has_suffix(filename, ".policy");
}
static int read_policies(void)
{
GDir *dir;
- int err = 0;
+ const gchar *filename;
+ struct policy_file *file;
DBG("");
dir = g_dir_open(POLICYDIR, 0, NULL);
- if (dir != NULL) {
- const gchar *file;
+ if (!dir)
+ return -EINVAL;
- while ((file = g_dir_read_name(dir)) != NULL) {
- struct policy_data *policy;
-
- policy = create_policy(file);
- if (policy == NULL) {
- err = -ENOMEM;
- break;
- }
+ while ((filename = g_dir_read_name(dir))) {
+ if (!is_filename_valid(filename))
+ continue;
- err = load_policy(policy);
- if (err < 0)
- break;
+ file = g_new0(struct policy_file, 1);
+ if (load_file(filename, file) < 0) {
+ g_free(file);
+ continue;
}
- g_dir_close(dir);
+ g_hash_table_replace(file_hash, g_strdup(filename), file);
}
- return err;
+ g_dir_close(dir);
+
+ return 0;
+}
+
+
+static void notify_handler(struct inotify_event *event,
+ const char *filename)
+{
+ struct policy_file *file;
+
+ DBG("event %x file %s", event->mask, filename);
+
+ if (event->mask & IN_CREATE)
+ return;
+
+ if (!is_filename_valid(filename))
+ return;
+
+ /*
+ * load_file() will modify the global selinux/uid/gid hash
+ * tables. We need to remove the old entries first before
+ * else the table points to the wrong entries.
+ */
+ g_hash_table_remove(file_hash, filename);
+
+ if (event->mask & (IN_DELETE | IN_MOVED_FROM))
+ return;
+
+ if (event->mask & (IN_MOVED_TO | IN_MODIFY)) {
+ connman_info("Policy update for '%s'", filename);
+
+ file = g_new0(struct policy_file, 1);
+ if (load_file(filename, file) < 0) {
+ g_free(file);
+ return;
+ }
+
+ g_hash_table_replace(file_hash, g_strdup(filename), file);
+ recheck_sessions();
+ }
}
static int session_policy_local_init(void)
{
int err;
+ 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;
}
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,
+ g_free, cleanup_file);
session_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
- NULL, NULL);
- if (session_hash == NULL) {
- err = -ENOMEM;
- goto err;
- }
-
- policy_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
- NULL, cleanup_policy);
- if (policy_hash == NULL) {
- err = -ENOMEM;
- goto err;
- }
+ NULL, cleanup_config);
+ selinux_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
+ NULL, NULL);
+ uid_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
+ NULL, NULL);
+ gid_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
+ NULL, NULL);
err = connman_inotify_register(POLICYDIR, notify_handler);
if (err < 0)
goto err;
- err = read_policies();
- if (err < 0)
- goto err_notify;
-
err = connman_session_policy_register(&session_policy_local);
if (err < 0)
goto err_notify;
+ read_policies();
+
return 0;
err_notify:
connman_inotify_unregister(POLICYDIR, notify_handler);
err:
- if (session_hash != NULL)
+ if (file_hash)
+ g_hash_table_destroy(file_hash);
+
+ if (session_hash)
g_hash_table_destroy(session_hash);
- if (policy_hash != NULL)
- g_hash_table_destroy(policy_hash);
+
+ if (selinux_hash)
+ g_hash_table_destroy(selinux_hash);
+
+ if (uid_hash)
+ g_hash_table_destroy(uid_hash);
+
+ if (gid_hash)
+ g_hash_table_destroy(gid_hash);
connman_session_policy_unregister(&session_policy_local);
static void session_policy_local_exit(void)
{
+ DBG("");
+
+ g_hash_table_destroy(file_hash);
g_hash_table_destroy(session_hash);
- g_hash_table_destroy(policy_hash);
+ g_hash_table_destroy(selinux_hash);
+ g_hash_table_destroy(uid_hash);
+ g_hash_table_destroy(gid_hash);
connman_session_policy_unregister(&session_policy_local);