[SSSD] [PATCH] Refactor the SELinux processing in the PAM responder a little

Jakub Hrozek jhrozek at redhat.com
Sun Jan 6 23:50:13 UTC 2013


I tried to move the whole PAM processing from the provider into the
responder but stumbled upon several things that had to be refactored in
order to make the code right. These two patches are a start, the next
phase should be getting rid of the per-request score.

So far these patches are intended for master only and their review has
lower priority than reviewing any of the patches targeted for 1.9 as
well.

[PATCH 1/2] PAM: Split SELinux processing into a separate module
No functional change, the SELinux processing just began to occupy a
substantial part of the PAM code, so it had to be split into its own
file.

[PATCH 2/2] PAM: reuse existing code for reading selinux config
The PAM processing reimplemented splitting on separator for no good
reason. This patch utilizes the existing code to reduce code
duplication.
-------------- next part --------------
>From 37de86026729cf1a8c1a2614e76be029eefe8281 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Sun, 6 Jan 2013 16:13:41 +0100
Subject: [PATCH 1/2] PAM: Split SELinux processing into a separate module

No functional change, the SELinux processing just began to occupy a
substantial part of the PAM code, so it had to be split into its own
file.
---
 Makefile.am                        |   1 +
 src/responder/pam/pamsrv.h         |   2 +
 src/responder/pam/pamsrv_cmd.c     | 286 --------------------------------
 src/responder/pam/pamsrv_selinux.c | 322 +++++++++++++++++++++++++++++++++++++
 4 files changed, 325 insertions(+), 286 deletions(-)
 create mode 100644 src/responder/pam/pamsrv_selinux.c

diff --git a/Makefile.am b/Makefile.am
index feebcc9e47b02cb09bae3150631818a80f080f1f..8248d370251e9291163edd577d4216b451838653 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -576,6 +576,7 @@ sssd_pam_SOURCES = \
     src/responder/pam/pam_LOCAL_domain.c \
     src/responder/pam/pamsrv.c \
     src/responder/pam/pamsrv_cmd.c \
+    src/responder/pam/pamsrv_selinux.c \
     src/responder/pam/pamsrv_dp.c \
     src/responder/pam/pam_helpers.c \
     $(SSSD_RESPONDER_OBJ)
diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h
index 3617231d025d1e7dd7ff116f0f74adfb8024cbb7..63009c093462c9ebfb029e977aaed0c470165a74 100644
--- a/src/responder/pam/pamsrv.h
+++ b/src/responder/pam/pamsrv.h
@@ -58,4 +58,6 @@ int pam_dp_send_req(struct pam_auth_req *preq, int timeout);
 
 int LOCAL_pam_handler(struct pam_auth_req *preq);
 
+errno_t process_selinux_mappings(struct pam_auth_req *preq);
+
 #endif /* __PAMSRV_H__ */
diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
index 4269642206cc0295c0046de4e59a3ad8f1044d1a..62d6e9410f0e1b2173f4ce00daad666bc04f4cac 100644
--- a/src/responder/pam/pamsrv_cmd.c
+++ b/src/responder/pam/pamsrv_cmd.c
@@ -22,7 +22,6 @@
 
 #include <time.h>
 #include "util/util.h"
-#include "util/sss_selinux.h"
 #include "util/auth_utils.h"
 #include "db/sysdb.h"
 #include "confdb/confdb.h"
@@ -32,11 +31,6 @@
 #include "providers/data_provider.h"
 #include "responder/pam/pamsrv.h"
 #include "responder/pam/pam_helpers.h"
-#include "db/sysdb.h"
-#include "db/sysdb_selinux.h"
-#ifdef HAVE_SELINUX_LOGIN_DIR
-#include <selinux/selinux.h>
-#endif
 
 enum pam_verbosity {
     PAM_VERBOSITY_NO_MESSAGES = 0,
@@ -362,284 +356,6 @@ fail:
     return ret;
 }
 
-#ifdef HAVE_SELINUX_LOGIN_DIR
-
-#define ALL_SERVICES "*"
-#define selogin_path(mem_ctx, username) \
-    talloc_asprintf(mem_ctx, "%s/logins/%s", selinux_policy_root(), username)
-
-static errno_t write_selinux_login_file(const char *username, char *string)
-{
-    char *path = NULL;
-    char *tmp_path = NULL;
-    ssize_t written;
-    int len;
-    int fd = -1;
-    mode_t oldmask;
-    TALLOC_CTX *tmp_ctx;
-    char *full_string = NULL;
-    errno_t ret = EOK;
-
-    len = strlen(string);
-    if (len == 0) {
-        return EINVAL;
-    }
-
-    tmp_ctx = talloc_new(NULL);
-    if (tmp_ctx == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n"));
-        return ENOMEM;
-    }
-
-    path = selogin_path(tmp_ctx, username);
-    if (path == NULL) {
-        ret = ENOMEM;
-        goto done;
-    }
-
-    tmp_path = talloc_asprintf(tmp_ctx, "%sXXXXXX", path);
-    if (tmp_path == NULL) {
-        ret = ENOMEM;
-        goto done;
-    }
-
-    oldmask = umask(022);
-    fd = mkstemp(tmp_path);
-    umask(oldmask);
-    if (fd < 0) {
-        DEBUG(SSSDBG_OP_FAILURE, ("creating the temp file for SELinux "
-                                  "data failed. %s", tmp_path));
-        ret = EIO;
-        goto done;
-    }
-
-    full_string = talloc_asprintf(tmp_ctx, "%s:%s", ALL_SERVICES, string);
-    if (full_string == NULL) {
-        ret = ENOMEM;
-        goto done;
-    }
-
-    len = strlen(full_string);
-
-    errno = 0;
-    written = sss_atomic_write_s(fd, full_string, len);
-    if (written == -1) {
-        ret = errno;
-        DEBUG(SSSDBG_OP_FAILURE, ("writing to SELinux data file %s"
-                                  "failed [%d]: %s", tmp_path, ret,
-                                  strerror(ret)));
-        goto done;
-    }
-
-    if (written != len) {
-        DEBUG(SSSDBG_OP_FAILURE, ("Expected to write %d bytes, wrote %d",
-                                  written, len));
-        ret = EIO;
-        goto done;
-    }
-
-    errno = 0;
-    if (rename(tmp_path, path) < 0) {
-        ret = errno;
-    } else {
-        ret = EOK;
-    }
-    close(fd);
-    fd = -1;
-
-done:
-    if (fd != -1) {
-        close(fd);
-        if (unlink(tmp_path) < 0) {
-            DEBUG(SSSDBG_MINOR_FAILURE, ("Could not remove file [%s]",
-                                         tmp_path));
-        }
-    }
-
-    talloc_free(tmp_ctx);
-    return ret;
-}
-
-static errno_t remove_selinux_login_file(const char *username)
-{
-    char *path;
-    errno_t ret;
-
-    path = selogin_path(NULL, username);
-    if (!path) return ENOMEM;
-
-    errno = 0;
-    ret = unlink(path);
-    if (ret < 0) {
-        ret = errno;
-        if (ret == ENOENT) {
-            /* Just return success if the file was not there */
-            ret = EOK;
-        } else {
-            DEBUG(SSSDBG_OP_FAILURE,
-                  ("Could not remove login file %s [%d]: %s\n",
-                   path, ret, strerror(ret)));
-        }
-    }
-
-    talloc_free(path);
-    return ret;
-}
-
-static errno_t process_selinux_mappings(struct pam_auth_req *preq)
-{
-    struct sysdb_ctx *sysdb;
-    TALLOC_CTX *tmp_ctx;
-    struct pam_data *pd = preq->pd;
-    char *file_content = NULL;
-    struct ldb_message **usermaps;
-    struct ldb_message *config;
-    const char *default_user = NULL;
-    const char *tmp_str;
-    char *order = NULL;
-    char **order_array;
-    errno_t ret, err;
-    int i, j;
-    size_t order_count;
-    size_t len = 0;
-
-    tmp_ctx = talloc_new(NULL);
-    if (tmp_ctx == NULL) {
-        ret = ENOMEM;
-        goto done;
-    }
-
-    sysdb = preq->domain->sysdb;
-    if (sysdb == NULL) {
-        DEBUG(SSSDBG_FATAL_FAILURE, ("Fatal: Sysdb CTX not found for "
-                                     "domain [%s]!\n", preq->domain->name));
-        ret = EINVAL;
-        goto done;
-    }
-
-    ret = sysdb_search_selinux_config(tmp_ctx, sysdb, NULL, &config);
-    if (ret == ENOENT) {
-        DEBUG(SSSDBG_TRACE_INTERNAL, ("No SELinux support found for the domain\n"));
-        ret = EOK;
-        goto done;
-    } else if (ret != EOK) {
-        goto done;
-    }
-
-    default_user = ldb_msg_find_attr_as_string(config,
-                                               SYSDB_SELINUX_DEFAULT_USER,
-                                               NULL);
-    if (!default_user || default_user[0] == '\0') {
-        /* Skip creating the maps altogether if there is no default
-         * or empty default
-         */
-        ret = EOK;
-        goto done;
-    }
-
-    tmp_str = ldb_msg_find_attr_as_string(config,
-                                          SYSDB_SELINUX_DEFAULT_ORDER,
-                                          NULL);
-    if (tmp_str == NULL) {
-        DEBUG(SSSDBG_OP_FAILURE, ("No map order given!\n"));
-        ret = EINVAL;
-        goto done;
-    }
-
-    order = talloc_strdup(tmp_ctx, tmp_str);
-    if (order == NULL) {
-        ret = ENOMEM;
-        goto done;
-    }
-    len = strlen(order);
-
-    /* The "order" string contains one or more SELinux user records
-     * separated by $. Now we need to create an array of string from
-     * this one string. First find out how many elements in the array
-     * will be. This way only one alloc will be necessary for the array
-     */
-    order_count = 1;
-    for (i = 0; i < len; i++) {
-        if (order[i] == '$') order_count++;
-    }
-
-    order_array = talloc_array(tmp_ctx, char *, order_count);
-    if (order_array == NULL) {
-        ret = ENOMEM;
-        goto done;
-    }
-
-    /* Now fill the array with pointers to the original string. Also
-     * use binary zeros to make multiple string out of the one.
-     */
-    order_array[0] = order;
-    order_count = 1;
-    for (i = 0; i < len; i++) {
-        if (order[i] == '$') {
-            order[i] = '\0';
-            order_array[order_count] = &order[i+1];
-            order_count++;
-        }
-    }
-
-    /* Fetch all maps applicable to the user who is currently logging in */
-    ret = sysdb_search_selinux_usermap_by_username(tmp_ctx, sysdb, pd->user,
-                                                   &usermaps);
-    if (ret != EOK && ret != ENOENT) {
-        goto done;
-    }
-
-    /* If no maps match, we'll use the default SELinux user from the
-     * config */
-    file_content = talloc_strdup(tmp_ctx, default_user);
-    if (file_content == NULL) {
-        ret = ENOMEM;
-        goto done;
-    }
-
-    /* Iterate through the order array and try to find SELinux users
-     * in fetched maps. The order array contains all SELinux users
-     * allowed in the domain in the same order they should appear
-     * in the SELinux config file. If any user from the order array
-     * is not in fetched user maps, it means it should not be allowed
-     * for the user who is just logging in.
-     *
-     * Right now we have empty content of the SELinux config file,
-     * we shall add only those SELinux users that are present both in
-     * the order array and user maps applicable to the user who is
-     * logging in.
-     */
-    for (i = 0; i < order_count; i++) {
-        for (j = 0; usermaps[j] != NULL; j++) {
-            tmp_str = sss_selinux_map_get_seuser(usermaps[j]);
-
-            if (tmp_str && !strcasecmp(tmp_str, order_array[i])) {
-                /* If file_content contained something, overwrite it.
-                 * This record has higher priority.
-                 */
-                talloc_zfree(file_content);
-                file_content = talloc_strdup(tmp_ctx, tmp_str);
-                if (file_content == NULL) {
-                    ret = ENOMEM;
-                    goto done;
-                }
-                break;
-            }
-        }
-    }
-
-    ret = write_selinux_login_file(pd->user, file_content);
-done:
-    if (!file_content) {
-        err = remove_selinux_login_file(pd->user);
-        /* Don't overwrite original error condition if there was one */
-        if (ret == EOK) ret = err;
-    }
-    talloc_free(tmp_ctx);
-    return ret;
-}
-#endif
-
 static errno_t filter_responses(struct confdb_ctx *cdb,
                                 struct response_data *resp_list)
 {
@@ -835,7 +551,6 @@ static void pam_reply(struct pam_auth_req *preq)
         return;
     }
 
-#ifdef HAVE_SELINUX_LOGIN_DIR
     if (pd->cmd == SSS_PAM_ACCT_MGMT &&
         pd->pam_status == PAM_SUCCESS) {
         /* Try to fetch data from sysdb
@@ -845,7 +560,6 @@ static void pam_reply(struct pam_auth_req *preq)
             pd->pam_status = PAM_SYSTEM_ERR;
         }
     }
-#endif
 
     ret = sss_packet_new(cctx->creq, 0, sss_packet_get_cmd(cctx->creq->in),
                          &cctx->creq->out);
diff --git a/src/responder/pam/pamsrv_selinux.c b/src/responder/pam/pamsrv_selinux.c
new file mode 100644
index 0000000000000000000000000000000000000000..7d89c3f786ac7bf5834c00df3a6c768cc54f452a
--- /dev/null
+++ b/src/responder/pam/pamsrv_selinux.c
@@ -0,0 +1,322 @@
+/*
+   SSSD
+
+   PAM Responder
+
+   Copyright (C) Simo Sorce <ssorce at redhat.com>	2009
+   Copyright (C) Sumit Bose <sbose at redhat.com>	2009
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "util/util.h"
+#include "db/sysdb.h"
+#include "responder/pam/pamsrv.h"
+#include "providers/data_provider.h"
+#include "util/sss_selinux.h"
+
+#include "db/sysdb_selinux.h"
+#ifdef HAVE_SELINUX_LOGIN_DIR
+#include <selinux/selinux.h>
+#endif
+
+#ifdef HAVE_SELINUX_LOGIN_DIR
+
+#define ALL_SERVICES "*"
+#define selogin_path(mem_ctx, username) \
+    talloc_asprintf(mem_ctx, "%s/logins/%s", selinux_policy_root(), username)
+
+static errno_t
+remove_selinux_login_file(const char *username)
+{
+    char *path;
+    errno_t ret;
+
+    path = selogin_path(NULL, username);
+    if (!path) return ENOMEM;
+
+    errno = 0;
+    ret = unlink(path);
+    if (ret < 0) {
+        ret = errno;
+        if (ret == ENOENT) {
+            /* Just return success if the file was not there */
+            ret = EOK;
+        } else {
+            DEBUG(SSSDBG_OP_FAILURE,
+                  ("Could not remove login file %s [%d]: %s\n",
+                   path, ret, strerror(ret)));
+        }
+    }
+
+    talloc_free(path);
+    return ret;
+}
+
+static errno_t
+write_selinux_login_file(const char *username, char *string)
+{
+    char *path = NULL;
+    char *tmp_path = NULL;
+    ssize_t written;
+    int len;
+    int fd = -1;
+    mode_t oldmask;
+    TALLOC_CTX *tmp_ctx;
+    char *full_string = NULL;
+    errno_t ret = EOK;
+
+    len = strlen(string);
+    if (len == 0) {
+        return EINVAL;
+    }
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n"));
+        return ENOMEM;
+    }
+
+    path = selogin_path(tmp_ctx, username);
+    if (path == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    tmp_path = talloc_asprintf(tmp_ctx, "%sXXXXXX", path);
+    if (tmp_path == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    oldmask = umask(022);
+    fd = mkstemp(tmp_path);
+    umask(oldmask);
+    if (fd < 0) {
+        DEBUG(SSSDBG_OP_FAILURE, ("creating the temp file for SELinux "
+                                  "data failed. %s", tmp_path));
+        ret = EIO;
+        goto done;
+    }
+
+    full_string = talloc_asprintf(tmp_ctx, "%s:%s", ALL_SERVICES, string);
+    if (full_string == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    len = strlen(full_string);
+
+    errno = 0;
+    written = sss_atomic_write_s(fd, full_string, len);
+    if (written == -1) {
+        ret = errno;
+        DEBUG(SSSDBG_OP_FAILURE, ("writing to SELinux data file %s"
+                                  "failed [%d]: %s", tmp_path, ret,
+                                  strerror(ret)));
+        goto done;
+    }
+
+    if (written != len) {
+        DEBUG(SSSDBG_OP_FAILURE, ("Expected to write %d bytes, wrote %d",
+                                  written, len));
+        ret = EIO;
+        goto done;
+    }
+
+    errno = 0;
+    if (rename(tmp_path, path) < 0) {
+        ret = errno;
+    } else {
+        ret = EOK;
+    }
+    close(fd);
+    fd = -1;
+
+done:
+    if (fd != -1) {
+        close(fd);
+        if (unlink(tmp_path) < 0) {
+            DEBUG(SSSDBG_MINOR_FAILURE, ("Could not remove file [%s]",
+                                         tmp_path));
+        }
+    }
+
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
+errno_t
+process_selinux_mappings(struct pam_auth_req *preq)
+{
+    struct sysdb_ctx *sysdb;
+    TALLOC_CTX *tmp_ctx;
+    struct pam_data *pd = preq->pd;
+    char *file_content = NULL;
+    struct ldb_message **usermaps;
+    struct ldb_message *config;
+    const char *default_user = NULL;
+    const char *tmp_str;
+    char *order = NULL;
+    char **order_array;
+    errno_t ret, err;
+    int i, j;
+    size_t order_count;
+    size_t len = 0;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    sysdb = preq->domain->sysdb;
+    if (sysdb == NULL) {
+        DEBUG(SSSDBG_FATAL_FAILURE, ("Fatal: Sysdb CTX not found for "
+                                     "domain [%s]!\n", preq->domain->name));
+        ret = EINVAL;
+        goto done;
+    }
+
+    ret = sysdb_search_selinux_config(tmp_ctx, sysdb, NULL, &config);
+    if (ret == ENOENT) {
+        DEBUG(SSSDBG_TRACE_INTERNAL, ("No SELinux support found for the domain\n"));
+        ret = EOK;
+        goto done;
+    } else if (ret != EOK) {
+        goto done;
+    }
+
+    default_user = ldb_msg_find_attr_as_string(config,
+                                               SYSDB_SELINUX_DEFAULT_USER,
+                                               NULL);
+    if (!default_user || default_user[0] == '\0') {
+        /* Skip creating the maps altogether if there is no default
+         * or empty default
+         */
+        ret = EOK;
+        goto done;
+    }
+
+    tmp_str = ldb_msg_find_attr_as_string(config,
+                                          SYSDB_SELINUX_DEFAULT_ORDER,
+                                          NULL);
+    if (tmp_str == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, ("No map order given!\n"));
+        ret = EINVAL;
+        goto done;
+    }
+
+    order = talloc_strdup(tmp_ctx, tmp_str);
+    if (order == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+    len = strlen(order);
+
+    /* The "order" string contains one or more SELinux user records
+     * separated by $. Now we need to create an array of string from
+     * this one string. First find out how many elements in the array
+     * will be. This way only one alloc will be necessary for the array
+     */
+    order_count = 1;
+    for (i = 0; i < len; i++) {
+        if (order[i] == '$') order_count++;
+    }
+
+    order_array = talloc_array(tmp_ctx, char *, order_count);
+    if (order_array == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    /* Now fill the array with pointers to the original string. Also
+     * use binary zeros to make multiple string out of the one.
+     */
+    order_array[0] = order;
+    order_count = 1;
+    for (i = 0; i < len; i++) {
+        if (order[i] == '$') {
+            order[i] = '\0';
+            order_array[order_count] = &order[i+1];
+            order_count++;
+        }
+    }
+
+    /* Fetch all maps applicable to the user who is currently logging in */
+    ret = sysdb_search_selinux_usermap_by_username(tmp_ctx, sysdb, pd->user,
+                                                   &usermaps);
+    if (ret != EOK && ret != ENOENT) {
+        goto done;
+    }
+
+    /* If no maps match, we'll use the default SELinux user from the
+     * config */
+    file_content = talloc_strdup(tmp_ctx, default_user);
+    if (file_content == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    /* Iterate through the order array and try to find SELinux users
+     * in fetched maps. The order array contains all SELinux users
+     * allowed in the domain in the same order they should appear
+     * in the SELinux config file. If any user from the order array
+     * is not in fetched user maps, it means it should not be allowed
+     * for the user who is just logging in.
+     *
+     * Right now we have empty content of the SELinux config file,
+     * we shall add only those SELinux users that are present both in
+     * the order array and user maps applicable to the user who is
+     * logging in.
+     */
+    for (i = 0; i < order_count; i++) {
+        for (j = 0; usermaps[j] != NULL; j++) {
+            tmp_str = sss_selinux_map_get_seuser(usermaps[j]);
+
+            if (tmp_str && !strcasecmp(tmp_str, order_array[i])) {
+                /* If file_content contained something, overwrite it.
+                 * This record has higher priority.
+                 */
+                talloc_zfree(file_content);
+                file_content = talloc_strdup(tmp_ctx, tmp_str);
+                if (file_content == NULL) {
+                    ret = ENOMEM;
+                    goto done;
+                }
+                break;
+            }
+        }
+    }
+
+    ret = write_selinux_login_file(pd->user, file_content);
+done:
+    if (!file_content) {
+        err = remove_selinux_login_file(pd->user);
+        /* Don't overwrite original error condition if there was one */
+        if (ret == EOK) ret = err;
+    }
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
+#else /* HAVE_SELINUX_LOGIN_DIR */
+
+errno_t
+process_selinux_mappings(struct pam_auth_req *preq)
+{
+    return EOK;
+}
+
+#endif /* HAVE_SELINUX_LOGIN_DIR */
-- 
1.8.0.2

-------------- next part --------------
>From 0fe89c8b9412579873674ea6e62b2733ea130abf Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Sun, 6 Jan 2013 16:53:20 +0100
Subject: [PATCH 2/2] PAM: reuse existing code for reading selinux config

---
 src/responder/pam/pamsrv_selinux.c | 80 +++++++++++++++++---------------------
 1 file changed, 35 insertions(+), 45 deletions(-)

diff --git a/src/responder/pam/pamsrv_selinux.c b/src/responder/pam/pamsrv_selinux.c
index 7d89c3f786ac7bf5834c00df3a6c768cc54f452a..d98aa6ad710fc405f74fc0675426062ebafcdafe 100644
--- a/src/responder/pam/pamsrv_selinux.c
+++ b/src/responder/pam/pamsrv_selinux.c
@@ -157,6 +157,38 @@ done:
     return ret;
 }
 
+static errno_t
+get_default_order(TALLOC_CTX *mem_ctx, struct ldb_message *config,
+                  char ***_order_array, size_t *_order_count)
+{
+    const char *tmp_str;
+    char **order_array;
+    int order_count;
+    errno_t ret;
+
+    tmp_str = ldb_msg_find_attr_as_string(config,
+                                          SYSDB_SELINUX_DEFAULT_ORDER,
+                                          NULL);
+    if (tmp_str == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, ("No map order given!\n"));
+        return EINVAL;
+    }
+
+    /* The "order" string contains one or more SELinux user records
+     * separated by $.
+     */
+    ret = split_on_separator(mem_ctx, tmp_str, '$', true, true,
+                             &order_array, &order_count);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, ("Cannot split the order string [%s]\n", tmp_str));
+        return EINVAL;
+    }
+
+    *_order_array = order_array;
+    *_order_count = order_count;
+    return EOK;
+}
+
 errno_t
 process_selinux_mappings(struct pam_auth_req *preq)
 {
@@ -168,12 +200,10 @@ process_selinux_mappings(struct pam_auth_req *preq)
     struct ldb_message *config;
     const char *default_user = NULL;
     const char *tmp_str;
-    char *order = NULL;
     char **order_array;
+    size_t order_count;
     errno_t ret, err;
     int i, j;
-    size_t order_count;
-    size_t len = 0;
 
     tmp_ctx = talloc_new(NULL);
     if (tmp_ctx == NULL) {
@@ -209,51 +239,11 @@ process_selinux_mappings(struct pam_auth_req *preq)
         goto done;
     }
 
-    tmp_str = ldb_msg_find_attr_as_string(config,
-                                          SYSDB_SELINUX_DEFAULT_ORDER,
-                                          NULL);
-    if (tmp_str == NULL) {
-        DEBUG(SSSDBG_OP_FAILURE, ("No map order given!\n"));
-        ret = EINVAL;
+    ret = get_default_order(tmp_ctx, config, &order_array, &order_count);
+    if (ret != EOK) {
         goto done;
     }
 
-    order = talloc_strdup(tmp_ctx, tmp_str);
-    if (order == NULL) {
-        ret = ENOMEM;
-        goto done;
-    }
-    len = strlen(order);
-
-    /* The "order" string contains one or more SELinux user records
-     * separated by $. Now we need to create an array of string from
-     * this one string. First find out how many elements in the array
-     * will be. This way only one alloc will be necessary for the array
-     */
-    order_count = 1;
-    for (i = 0; i < len; i++) {
-        if (order[i] == '$') order_count++;
-    }
-
-    order_array = talloc_array(tmp_ctx, char *, order_count);
-    if (order_array == NULL) {
-        ret = ENOMEM;
-        goto done;
-    }
-
-    /* Now fill the array with pointers to the original string. Also
-     * use binary zeros to make multiple string out of the one.
-     */
-    order_array[0] = order;
-    order_count = 1;
-    for (i = 0; i < len; i++) {
-        if (order[i] == '$') {
-            order[i] = '\0';
-            order_array[order_count] = &order[i+1];
-            order_count++;
-        }
-    }
-
     /* Fetch all maps applicable to the user who is currently logging in */
     ret = sysdb_search_selinux_usermap_by_username(tmp_ctx, sysdb, pd->user,
                                                    &usermaps);
-- 
1.8.0.2



More information about the sssd-devel mailing list