From: Daniel Wagner <daniel.wag...@bmw-carit.de>

When the session core ask to create a configuration, then we
first ask the D-Bus server which UID/GID the session belongs to.
If possible we also ask for the SELinux context. Then we try
to figure out which file containts the configuration for
SElinux, UID or GID identification.

The order of matching preference is SELinux, UID and finally GID.
It is possible to run a mixed configuration but not really recommended.
There might be dragons.
---
 plugins/session_policy_local.c | 173 ++++++++++++++++++++++++++++++++++++-----
 1 file changed, 152 insertions(+), 21 deletions(-)

diff --git a/plugins/session_policy_local.c b/plugins/session_policy_local.c
index 11ae2c6..4b79f46 100644
--- a/plugins/session_policy_local.c
+++ b/plugins/session_policy_local.c
@@ -27,6 +27,9 @@
 #include <string.h>
 #include <sys/inotify.h>
 #include <sys/stat.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
 
 #include <glib.h>
 
@@ -51,6 +54,8 @@ static GHashTable *session_hash;
 struct policy_data {
        char *filename;
        char *lsm_filename;
+       char *uid_filename;
+       GSList *gid_filenames;
 
        struct connman_session *session;
        struct connman_session_config *config;
@@ -67,6 +72,8 @@ static void cleanup_policy(gpointer user_data)
 
        g_free(policy->filename);
        g_free(policy->lsm_filename);
+       g_free(policy->uid_filename);
+       g_slist_free_full(policy->gid_filenames, g_free);
        g_free(policy->config);
        g_free(policy);
 }
@@ -205,43 +212,149 @@ static int load_policy(struct policy_data *policy, const 
char *filename)
        return err;
 }
 
+static void finish_create(struct policy_data *policy,
+                               connman_session_config_func_t cb,
+                               void *user_data)
+{
+       GSList *list;
+       char *filename;
+
+       if (policy->lsm_filename != NULL &&
+                       load_policy(policy, policy->lsm_filename) == 0) {
+               policy->filename = g_strdup(policy->lsm_filename);
+       } else if (policy->uid_filename != NULL &&
+                       load_policy(policy, policy->uid_filename) == 0) {
+               policy->filename = g_strdup(policy->uid_filename);
+       } else {
+               for (list = policy->gid_filenames; list != NULL;
+                               list = list->next) {
+                       filename = list->data;
+
+                       if (load_policy(policy, filename) < 0)
+                               continue;
+
+                       break;
+               }
+       }
+
+       g_hash_table_replace(session_hash, policy->session, policy);
+
+       (*cb)(policy->session, policy->config, user_data, 0);
+}
+
+static void failed_create(struct policy_data *policy,
+                       connman_session_config_func_t cb,
+                       void *user_data, int err)
+{
+       (*cb)(policy->session, NULL, user_data, err);
+
+       cleanup_policy(policy);
+}
+
 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 policy_data *policy = cbd->data;
-       struct connman_session_config *config = NULL;
        char *ident = NULL;
 
        DBG("session %p", policy->session);
 
-       if (err < 0)
+       if (err < 0) {
+               failed_create(policy, cb, user_data, err);
                goto done;
+       }
 
        DBG("SELinux context %s", context);
 
        ident = parse_selinux_type((const char*)context);
-       if (ident == NULL) {
-               err = -EINVAL;
-               goto done;
-       }
+       if (ident != NULL)
+               policy->lsm_filename = g_strdup(ident);
 
-       policy->lsm_filename = g_strdup(ident);
-       if (load_policy(policy, policy->lsm_filename) == 0)
-               policy->filename = g_strdup(policy->lsm_filename);
-
-       g_hash_table_replace(session_hash, policy->session, policy);
-       config = policy->config;
+       finish_create(policy, cb, cbd->user_data);
 
 done:
-       (*cb)(policy->session, config, cbd->user_data, err);
+       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_data *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_policy(policy);
+               goto err;
+
+       pwd = getpwuid((uid_t)uid);
+       if (pwd == NULL) {
+               if (errno != 0)
+                       err = -errno;
+               else
+                       err = -EINVAL;
+               goto err;
+       }
+
+       policy->uid_filename = g_strdup_printf("uid_%s", pwd->pw_name);
+
+       nrgroups = 0;
+       getgrouplist(pwd->pw_name, pwd->pw_gid, NULL, &nrgroups);
+       groups = g_try_new0(gid_t, nrgroups);
+       if (groups == NULL) {
+               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 == NULL) {
+                       if (errno != 0)
+                               err = -errno;
+                       else
+                               err = -EINVAL;
+                       goto err;
+               }
+
+               policy->gid_filenames = g_slist_prepend(policy->gid_filenames,
+                               g_strdup_printf("gid_%s", grp->gr_name));
+       }
+       g_free(groups);
+
+       owner = connman_session_get_owner(policy->session);
+
+       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;
+       }
+
+       finish_create(policy, cb, cbd->user_data);
        g_free(cbd);
-       g_free(ident);
+
+       return;
+
+err:
+       failed_create(policy, cb, user_data, err);
+       g_free(cbd);
+       g_free(groups);
 }
 
 static int policy_local_create(struct connman_session *session,
@@ -263,11 +376,10 @@ static int policy_local_create(struct connman_session 
*session,
 
        owner = connman_session_get_owner(session);
 
-       err = connman_dbus_get_selinux_context(connection, owner,
-                                       selinux_context_reply,
-                                       cbd);
+       err = connman_dbus_get_connection_unix_user(connection, owner,
+                                               get_uid_reply, cbd);
        if (err < 0) {
-               connman_error("Could not get SELinux context");
+               connman_error("Could not get UID");
                cleanup_policy(policy);
                g_free(cbd);
                return err;
@@ -331,6 +443,8 @@ static void apply_policy(const char *filename)
 {
        GHashTableIter iter;
        gpointer value, key;
+       GSList *list;
+       char *name;
 
        g_hash_table_iter_init(&iter, session_hash);
        while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
@@ -338,8 +452,25 @@ static void apply_policy(const char *filename)
 
                if (g_strcmp0(policy->lsm_filename, filename) == 0 &&
                                load_policy(policy, filename) == 0) {
-               } else
-                       continue;
+               } else if (g_strcmp0(policy->uid_filename, filename) == 0 &&
+                               load_policy(policy, filename) == 0) {
+               } else {
+                       for (list = policy->gid_filenames; list != NULL;
+                                       list = list->next) {
+                               name = list->data;
+
+                               if (g_strcmp0(name, filename) != 0)
+                                       continue;
+
+                               if (load_policy(policy, filename) < 0)
+                                       continue;
+
+                               break;
+                       }
+
+                       if (list == NULL)
+                               continue;
+               }
 
                g_free(policy->filename);
                policy->filename = g_strdup(filename);
-- 
1.8.2.rc3.16.gce432ca

_______________________________________________
connman mailing list
connman@connman.net
http://lists.connman.net/listinfo/connman

Reply via email to