Skip to content

Commit

Permalink
SELinux support in PAM responder
Browse files Browse the repository at this point in the history
  • Loading branch information
Jan Zeleny authored and sgallagher committed Feb 6, 2012
1 parent 4c11f75 commit 45fea2d
Show file tree
Hide file tree
Showing 2 changed files with 167 additions and 0 deletions.
163 changes: 163 additions & 0 deletions src/responder/pam/pamsrv_cmd.c
Expand Up @@ -22,6 +22,7 @@

#include <time.h>
#include "util/util.h"
#include "util/sss_selinux.h"
#include "db/sysdb.h"
#include "confdb/confdb.h"
#include "responder/common/responder_packet.h"
Expand All @@ -31,6 +32,7 @@
#include "responder/pam/pamsrv.h"
#include "responder/pam/pam_helpers.h"
#include "db/sysdb.h"
#include "db/sysdb_selinux.h"

enum pam_verbosity {
PAM_VERBOSITY_NO_MESSAGES = 0,
Expand Down Expand Up @@ -352,6 +354,158 @@ static errno_t set_last_login(struct pam_auth_req *preq)
return ret;
}

static errno_t get_selinux_string(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;
int i, j;
size_t order_count;
size_t len;

tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) {
ret = ENOMEM;
goto done;
}

ret = sysdb_get_ctx_from_list(preq->cctx->rctx->db_list,
preq->domain, &sysdb);
if (ret != EOK) {
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;
}

/* We need two values from the config object:
* - default SELinux user in case no other is available
* - the order for fetched usermaps
*/
for (i = 0; i < config->num_elements; i++) {
if (strcasecmp(config->elements[i].name, SYSDB_SELINUX_DEFAULT_USER) == 0) {
default_user = (const char *)config->elements[i].values[0].data;
} else if (strcasecmp(config->elements[i].name, SYSDB_SELINUX_DEFAULT_ORDER) == 0) {
tmp_str = (char *)config->elements[i].values[0].data;
len = config->elements[i].values[0].length;
order = talloc_strdup(tmp_ctx, tmp_str);
if (order == NULL) {
goto done;
}
}
}

if (default_user == NULL || order == NULL) {
DEBUG(SSSDBG_OP_FAILURE, ("No default SELinux user "
"or map order given!\n"));
ret = EINVAL;
goto done;
}

/* 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 (ret == ENOENT) {
DEBUG(SSSDBG_TRACE_FUNC, ("No user maps found, using default!"));
file_content = talloc_strdup(tmp_ctx, default_user);
if (file_content == NULL) {
ret = ENOMEM;
goto done;
}
} else {
file_content = talloc_strdup(tmp_ctx, "");
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])) {
file_content = talloc_asprintf_append(file_content, "%s\n",
tmp_str);
if (file_content == NULL) {
ret = ENOMEM;
goto done;
}
break;
}
}
}
}

len = strlen(file_content);
if (len > 0) {
ret = pam_add_response(pd, SSS_PAM_SELINUX_MAP, len,
(uint8_t *)file_content);
}

done:
talloc_free(tmp_ctx);
return ret;
}

static errno_t filter_responses(struct confdb_ctx *cdb,
struct response_data *resp_list)
{
Expand Down Expand Up @@ -580,6 +734,15 @@ static void pam_reply(struct pam_auth_req *preq)
return;
}

if (pd->cmd == SSS_PAM_OPEN_SESSION) {
/* Try to fetch data from sysdb
* (auth already passed -> we should have them) */
ret = get_selinux_string(preq);
if (ret != EOK) {
pd->pam_status = PAM_SYSTEM_ERR;
}
}

ret = sss_packet_new(cctx->creq, 0, sss_packet_get_cmd(cctx->creq->in),
&cctx->creq->out);
if (ret != EOK) {
Expand Down
4 changes: 4 additions & 0 deletions src/sss_client/sss_cli.h
Expand Up @@ -358,6 +358,10 @@ enum response_type {
* the user.This should only be used in the case where
* it is not possile to use SSS_PAM_USER_INFO.
* @param A zero terminated string. */
SSS_PAM_SELINUX_MAP, /**< A content of a SELinux user mapping file. This
* file should be then written to a particular
* subdir in /etc/selinux for pam_selinux to read
* @param A zero terminated string. */
};

/**
Expand Down

0 comments on commit 45fea2d

Please sign in to comment.