summaryrefslogtreecommitdiff
path: root/modules/pam_selinux
diff options
context:
space:
mode:
Diffstat (limited to 'modules/pam_selinux')
-rw-r--r--modules/pam_selinux/pam_selinux.8.xml25
-rw-r--r--modules/pam_selinux/pam_selinux.c208
2 files changed, 166 insertions, 67 deletions
diff --git a/modules/pam_selinux/pam_selinux.8.xml b/modules/pam_selinux/pam_selinux.8.xml
index 3acd1322..ab368a87 100644
--- a/modules/pam_selinux/pam_selinux.8.xml
+++ b/modules/pam_selinux/pam_selinux.8.xml
@@ -37,6 +37,9 @@
select_context
</arg>
<arg choice="opt">
+ env_params
+ </arg>
+ <arg choice="opt">
use_current_range
</arg>
</cmdsynopsis>
@@ -137,12 +140,30 @@
</varlistentry>
<varlistentry>
<term>
+ <option>env_params</option>
+ </term>
+ <listitem>
+ <para>
+ Attempt to obtain a custom security context role from PAM environment.
+ If MLS is on obtain also sensitivity level. This option and the
+ select_context option are mutually exclusive. The respective PAM
+ environment variables are <emphasis>SELINUX_ROLE_REQUESTED</emphasis>,
+ <emphasis>SELINUX_LEVEL_REQUESTED</emphasis>, and
+ <emphasis>SELINUX_USE_CURRENT_RANGE</emphasis>. The first two variables
+ are self describing and the last one if set to 1 makes the PAM module behave as
+ if the use_current_range was specified on the command line of the module.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
<option>use_current_range</option>
</term>
<listitem>
<para>
- Use the sensitivity range of the process for the user context.
- This option and the select_context option are mutually exclusive.
+ Use the sensitivity level of the current process for the user context
+ instead of the default level. Also supresses asking of the
+ sensitivity level from the user or obtaining it from PAM environment.
</para>
</listitem>
</varlistentry>
diff --git a/modules/pam_selinux/pam_selinux.c b/modules/pam_selinux/pam_selinux.c
index da1290f0..e45d6f99 100644
--- a/modules/pam_selinux/pam_selinux.c
+++ b/modules/pam_selinux/pam_selinux.c
@@ -2,8 +2,9 @@
* A module for Linux-PAM that will set the default security context after login
* via PAM.
*
- * Copyright (c) 2003 Red Hat, Inc.
+ * Copyright (c) 2003-2008 Red Hat, Inc.
* Written by Dan Walsh <dwalsh@redhat.com>
+ * Additional improvements by Tomas Mraz <tmraz@redhat.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -252,7 +253,7 @@ static int mls_range_allowed(pam_handle_t *pamh, security_context_t src, securit
}
static security_context_t
-config_context (pam_handle_t *pamh, security_context_t puser_context, int debug)
+config_context (pam_handle_t *pamh, security_context_t defaultcon, int use_current_range, int debug)
{
security_context_t newcon=NULL;
context_t new_context;
@@ -261,7 +262,7 @@ config_context (pam_handle_t *pamh, security_context_t puser_context, int debug)
char *type=NULL;
char resp_val = 0;
- pam_prompt (pamh, PAM_TEXT_INFO, NULL, _("Default Security Context %s\n"), puser_context);
+ pam_prompt (pamh, PAM_TEXT_INFO, NULL, _("Default Security Context %s\n"), defaultcon);
while (1) {
if (query_response(pamh,
@@ -274,7 +275,7 @@ config_context (pam_handle_t *pamh, security_context_t puser_context, int debug)
}
if ((resp_val == 'y') || (resp_val == 'Y'))
{
- if ((new_context = context_new(puser_context)) == NULL)
+ if ((new_context = context_new(defaultcon)) == NULL)
goto fail_set;
/* Allow the user to enter role and level individually */
@@ -295,10 +296,27 @@ config_context (pam_handle_t *pamh, security_context_t puser_context, int debug)
if (mls_enabled)
{
- if (query_response(pamh, _("level:"), context_range_get(new_context),
+ if (use_current_range) {
+ security_context_t mycon = NULL;
+ context_t my_context;
+
+ if (getcon(&mycon) != 0)
+ goto fail_set;
+ my_context = context_new(mycon);
+ if (my_context == NULL) {
+ freecon(mycon);
+ goto fail_set;
+ }
+ freecon(mycon);
+ if (context_range_set(new_context, context_range_get(my_context))) {
+ context_free(my_context);
+ goto fail_set;
+ }
+ context_free(my_context);
+ } else if (query_response(pamh, _("level:"), context_range_get(new_context),
&response, debug) == PAM_SUCCESS && response[0]) {
- if (context_range_set(new_context, response))
- goto fail_set;
+ if (context_range_set(new_context, response))
+ goto fail_set;
}
_pam_drop(response);
}
@@ -309,15 +327,17 @@ config_context (pam_handle_t *pamh, security_context_t puser_context, int debug)
/* Get the string value of the context and see if it is valid. */
if (!security_check_context(context_str(new_context))) {
newcon = strdup(context_str(new_context));
- context_free (new_context);
+ if (newcon == NULL)
+ goto fail_set;
+ context_free(new_context);
/* we have to check that this user is allowed to go into the
range they have specified ... role is tied to an seuser, so that'll
be checked at setexeccon time */
- if (mls_enabled && !mls_range_allowed(pamh, puser_context, newcon, debug)) {
- pam_syslog(pamh, LOG_NOTICE, "Security context %s is not allowed for %s", puser_context, newcon);
+ if (mls_enabled && !mls_range_allowed(pamh, defaultcon, newcon, debug)) {
+ pam_syslog(pamh, LOG_NOTICE, "Security context %s is not allowed for %s", defaultcon, newcon);
- send_audit_message(pamh, 0, puser_context, newcon);
+ send_audit_message(pamh, 0, defaultcon, newcon);
free(newcon);
goto fail_range;
@@ -325,13 +345,13 @@ config_context (pam_handle_t *pamh, security_context_t puser_context, int debug)
return newcon;
}
else {
- send_audit_message(pamh, 0, puser_context, context_str(new_context));
+ send_audit_message(pamh, 0, defaultcon, context_str(new_context));
send_text(pamh,_("Not a valid security context"),debug);
}
context_free(new_context); /* next time around allocates another */
}
else
- return strdup(puser_context);
+ return strdup(defaultcon);
} /* end while */
return NULL;
@@ -340,11 +360,105 @@ config_context (pam_handle_t *pamh, security_context_t puser_context, int debug)
free(type);
_pam_drop(response);
context_free (new_context);
- send_audit_message(pamh, 0, puser_context, NULL);
+ send_audit_message(pamh, 0, defaultcon, NULL);
fail_range:
return NULL;
}
+static security_context_t
+context_from_env (pam_handle_t *pamh, security_context_t defaultcon, int env_params, int use_current_range, int debug)
+{
+ security_context_t newcon = NULL;
+ context_t new_context;
+ context_t my_context = NULL;
+ int mls_enabled = is_selinux_mls_enabled();
+ const char *env = NULL;
+ char *type = NULL;
+
+ if ((new_context = context_new(defaultcon)) == NULL)
+ goto fail_set;
+
+ if (env_params && (env = pam_getenv(pamh, "SELINUX_ROLE_REQUESTED")) != NULL && env[0] != '\0') {
+ if (debug)
+ pam_syslog(pamh, LOG_NOTICE, "Requested role: %s", env);
+
+ if (get_default_type(env, &type)) {
+ pam_syslog(pamh, LOG_NOTICE, "No default type for role %s", env);
+ goto fail_set;
+ } else {
+ if (context_role_set(new_context, env))
+ goto fail_set;
+ if (context_type_set(new_context, type))
+ goto fail_set;
+ }
+ }
+
+ if (mls_enabled) {
+ if ((env = pam_getenv(pamh, "SELINUX_USE_CURRENT_RANGE")) != NULL && env[0] == '1') {
+ if (debug)
+ pam_syslog(pamh, LOG_NOTICE, "SELINUX_USE_CURRENT_RANGE is set");
+ use_current_range = 1;
+ }
+
+ if (use_current_range) {
+ security_context_t mycon = NULL;
+
+ if (getcon(&mycon) != 0)
+ goto fail_set;
+ my_context = context_new(mycon);
+ if (my_context == NULL) {
+ freecon(mycon);
+ goto fail_set;
+ }
+ freecon(mycon);
+ env = context_range_get(my_context);
+ } else {
+ env = pam_getenv(pamh, "SELINUX_LEVEL_REQUESTED");
+ }
+
+ if (env != NULL && env[0] != '\0') {
+ if (debug)
+ pam_syslog(pamh, LOG_NOTICE, "Requested level: %s", env);
+ if (context_range_set(new_context, env))
+ goto fail_set;
+ }
+ }
+
+ newcon = strdup(context_str(new_context));
+ if (newcon == NULL)
+ goto fail_set;
+
+ if (debug)
+ pam_syslog(pamh, LOG_NOTICE, "Selected Security Context %s", newcon);
+
+ /* Get the string value of the context and see if it is valid. */
+ if (security_check_context(newcon)) {
+ pam_syslog(pamh, LOG_NOTICE, "Not a valid security context %s", newcon);
+ send_audit_message(pamh, 0, defaultcon, newcon);
+ freecon(newcon);
+ newcon = NULL;
+
+ goto fail_set;
+ }
+
+ /* we have to check that this user is allowed to go into the
+ range they have specified ... role is tied to an seuser, so that'll
+ be checked at setexeccon time */
+ if (mls_enabled && !mls_range_allowed(pamh, defaultcon, newcon, debug)) {
+ pam_syslog(pamh, LOG_NOTICE, "Security context %s is not allowed for %s", defaultcon, newcon);
+ send_audit_message(pamh, 0, defaultcon, newcon);
+ freecon(newcon);
+ newcon = NULL;
+ }
+
+ fail_set:
+ free(type);
+ context_free(my_context);
+ context_free(new_context);
+ send_audit_message(pamh, 0, defaultcon, NULL);
+ return newcon;
+}
+
static void
security_restorelabel_tty(const pam_handle_t *pamh,
const char *tty, security_context_t context)
@@ -462,6 +576,7 @@ pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED,
int ret = 0;
security_context_t* contextlist = NULL;
int num_contexts = 0;
+ int env_params = 0;
const char *username = NULL;
const void *tty = NULL;
char *seuser=NULL;
@@ -488,13 +603,16 @@ pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED,
if (strcmp(argv[i], "use_current_range") == 0) {
use_current_range = 1;
}
+ if (strcmp(argv[i], "env_params") == 0) {
+ env_params = 1;
+ }
}
if (debug)
pam_syslog(pamh, LOG_NOTICE, "Open Session");
- if (select_context && use_current_range) {
- pam_syslog(pamh, LOG_ERR, "select_context cannot be used with use_current_range");
+ if (select_context && env_params) {
+ pam_syslog(pamh, LOG_ERR, "select_context cannot be used with env_params");
select_context = 0;
}
@@ -526,12 +644,17 @@ pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED,
freeconary(contextlist);
if (default_user_context == NULL) {
pam_syslog(pamh, LOG_ERR, "Out of memory");
- return PAM_AUTH_ERR;
+ return PAM_BUF_ERR;
}
+
user_context = default_user_context;
if (select_context) {
- user_context = config_context(pamh, default_user_context, debug);
- if (user_context == NULL) {
+ user_context = config_context(pamh, default_user_context, use_current_range, debug);
+ } else if (env_params || use_current_range) {
+ user_context = context_from_env(pamh, default_user_context, env_params, use_current_range, debug);
+ }
+
+ if (user_context == NULL) {
freecon(default_user_context);
pam_syslog(pamh, LOG_ERR, "Unable to get valid context for %s",
username);
@@ -540,8 +663,7 @@ pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED,
return PAM_AUTH_ERR;
else
return PAM_SUCCESS;
- }
- }
+ }
}
else {
user_context = manual_context(pamh,seuser,debug);
@@ -555,50 +677,6 @@ pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED,
}
}
- if (use_current_range && is_selinux_mls_enabled()) {
- security_context_t process_context=NULL;
- if (getcon(&process_context) == 0) {
- context_t pcon, ucon;
- char *process_level=NULL;
- security_context_t orig_context;
-
- if (user_context)
- orig_context = user_context;
- else
- orig_context = default_user_context;
-
- pcon = context_new(process_context);
- freecon(process_context);
- process_level = strdup(context_range_get(pcon));
- context_free(pcon);
-
- if (debug)
- pam_syslog (pamh, LOG_DEBUG, "process level=%s", process_level);
-
- ucon = context_new(orig_context);
-
- context_range_set(ucon, process_level);
- free(process_level);
-
- if (!mls_range_allowed(pamh, orig_context, context_str(ucon), debug)) {
- send_text(pamh, _("Requested MLS level not in permitted range"), debug);
- /* even if default_user_context is NULL audit that anyway */
- send_audit_message(pamh, 0, default_user_context, context_str(ucon));
- context_free(ucon);
- return PAM_AUTH_ERR;
- }
-
- if (debug)
- pam_syslog (pamh, LOG_DEBUG, "adjusted context=%s", context_str(ucon));
-
- /* replace the user context with the level adjusted one */
- freecon(user_context);
- user_context = strdup(context_str(ucon));
-
- context_free(ucon);
- }
- }
-
if (getexeccon(&prev_user_context)<0) {
prev_user_context=NULL;
}