diff --git a/pam-1.0.0-selinux-env-params.patch b/pam-1.0.0-selinux-env-params.patch
new file mode 100644
index 0000000..0bf0613
--- /dev/null
+++ b/pam-1.0.0-selinux-env-params.patch
@@ -0,0 +1,561 @@
+Index: modules/pam_selinux/pam_selinux.8.xml
+===================================================================
+RCS file: /cvsroot/pam/Linux-PAM/modules/pam_selinux/pam_selinux.8.xml,v
+retrieving revision 1.2
+diff -u -p -r1.2 pam_selinux.8.xml
+--- modules/pam_selinux/pam_selinux.8.xml 15 Jun 2007 10:17:22 -0000 1.2
++++ modules/pam_selinux/pam_selinux.8.xml 19 May 2008 15:44:08 -0000
+@@ -37,6 +37,9 @@
+ select_context
+
+
++ env_params
++
++
+ use_current_range
+
+
+@@ -137,12 +140,30 @@
+
+
+
++
++
++
++
++ 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 SELINUX_ROLE_REQUESTED,
++ SELINUX_LEVEL_REQUESTED, and
++ SELINUX_USE_CURRENT_RANGE. 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.
++
++
++
++
++
+
+
+
+
+- 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.
+
+
+
+Index: modules/pam_selinux/pam_selinux.c
+===================================================================
+RCS file: /cvsroot/pam/Linux-PAM/modules/pam_selinux/pam_selinux.c,v
+retrieving revision 1.16
+diff -u -p -r1.16 pam_selinux.c
+--- modules/pam_selinux/pam_selinux.c 22 Apr 2008 19:21:37 -0000 1.16
++++ modules/pam_selinux/pam_selinux.c 19 May 2008 15:44:08 -0000
+@@ -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
++ * Additional improvements by Tomas Mraz
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+@@ -138,15 +139,22 @@ send_text (pam_handle_t *pamh, const cha
+ */
+ static int
+ query_response (pam_handle_t *pamh, const char *text, const char *def,
+- char **responses, int debug)
++ char **response, int debug)
+ {
+ int rc;
+ if (def)
+- rc = pam_prompt (pamh, PAM_PROMPT_ECHO_ON, responses, "%s [%s] ", text, def);
++ rc = pam_prompt (pamh, PAM_PROMPT_ECHO_ON, response, "%s [%s] ", text, def);
+ else
+- rc = pam_prompt (pamh, PAM_PROMPT_ECHO_ON, responses, "%s ", text);
+- if (debug)
+- pam_syslog(pamh, LOG_NOTICE, "%s %s", text, responses[0]);
++ rc = pam_prompt (pamh, PAM_PROMPT_ECHO_ON, response, "%s ", text);
++
++ if (*response == NULL) {
++ rc = PAM_CONV_ERR;
++ }
++
++ if (rc != PAM_SUCCESS) {
++ pam_syslog(pamh, LOG_WARNING, "No response to query: %s", text);
++ } else if (debug)
++ pam_syslog(pamh, LOG_NOTICE, "%s %s", text, *response);
+ return rc;
+ }
+
+@@ -157,13 +165,15 @@ manual_context (pam_handle_t *pamh, cons
+ context_t new_context;
+ int mls_enabled = is_selinux_mls_enabled();
+ char *type=NULL;
+- char *responses=NULL;
++ char *response=NULL;
+
+ while (1) {
+- query_response(pamh,
+- _("Would you like to enter a security context? [N] "), NULL,
+- &responses,debug);
+- if ((responses[0] == 'y') || (responses[0] == 'Y'))
++ if (query_response(pamh,
++ _("Would you like to enter a security context? [N] "), NULL,
++ &response, debug) != PAM_SUCCESS)
++ return NULL;
++
++ if ((response[0] == 'y') || (response[0] == 'Y'))
+ {
+ if (mls_enabled)
+ new_context = context_new ("user:role:type:level");
+@@ -176,26 +186,29 @@ manual_context (pam_handle_t *pamh, cons
+ if (context_user_set (new_context, user))
+ goto fail_set;
+
+- _pam_drop(responses);
++ _pam_drop(response);
+ /* Allow the user to enter each field of the context individually */
+- query_response(pamh,_("role:"), NULL, &responses,debug);
+- if (responses[0] != '\0') {
+- if (context_role_set (new_context, responses))
++ if (query_response(pamh, _("role:"), NULL, &response, debug) == PAM_SUCCESS &&
++ response[0] != '\0') {
++ if (context_role_set (new_context, response))
+ goto fail_set;
+- if (get_default_type(responses, &type))
++ if (get_default_type(response, &type))
+ goto fail_set;
+ if (context_type_set (new_context, type))
+ goto fail_set;
+ }
+- _pam_drop(responses);
++ _pam_drop(response);
++
+ if (mls_enabled)
+ {
+- query_response(pamh,_("level:"), NULL, &responses,debug);
+- if (responses[0] != '\0') {
+- if (context_range_set (new_context, responses))
++ if (query_response(pamh, _("level:"), NULL, &response, debug) == PAM_SUCCESS &&
++ response[0] != '\0') {
++ if (context_range_set (new_context, response))
+ goto fail_set;
+ }
++ _pam_drop(response);
+ }
++
+ /* 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));
+@@ -204,16 +217,17 @@ manual_context (pam_handle_t *pamh, cons
+ }
+ else
+ send_text(pamh,_("Not a valid security context"),debug);
+- context_free (new_context);
++
++ context_free (new_context);
+ }
+ else {
+- _pam_drop(responses);
++ _pam_drop(response);
+ return NULL;
+ }
+ } /* end while */
+ fail_set:
+ free(type);
+- _pam_drop(responses);
++ _pam_drop(response);
+ context_free (new_context);
+ return NULL;
+ }
+@@ -239,69 +253,91 @@ static int mls_range_allowed(pam_handle_
+ }
+
+ 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;
+ int mls_enabled = is_selinux_mls_enabled();
+- char *responses=NULL;
++ char *response=NULL;
+ 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) {
+- query_response(pamh,
++ if (query_response(pamh,
+ _("Would you like to enter a different role or level?"), "n",
+- &responses,debug);
+-
+- resp_val = responses[0];
+- _pam_drop(responses);
++ &response, debug) == PAM_SUCCESS) {
++ resp_val = response[0];
++ _pam_drop(response);
++ } else {
++ resp_val = 'N';
++ }
+ if ((resp_val == 'y') || (resp_val == 'Y'))
+ {
+- new_context = context_new(puser_context);
+-
++ if ((new_context = context_new(defaultcon)) == NULL)
++ goto fail_set;
++
+ /* Allow the user to enter role and level individually */
+- query_response(pamh,_("role:"), context_role_get(new_context),
+- &responses, debug);
+- if (responses[0]) {
+- if (get_default_type(responses, &type)) {
+- pam_prompt (pamh, PAM_ERROR_MSG, NULL, _("No default type for role %s\n"), responses);
+- _pam_drop(responses);
++ if (query_response(pamh, _("role:"), context_role_get(new_context),
++ &response, debug) == PAM_SUCCESS && response[0]) {
++ if (get_default_type(response, &type)) {
++ pam_prompt (pamh, PAM_ERROR_MSG, NULL, _("No default type for role %s\n"), response);
++ _pam_drop(response);
+ continue;
+ } else {
+- if (context_role_set(new_context, responses))
++ if (context_role_set(new_context, response))
+ goto fail_set;
+ if (context_type_set (new_context, type))
+ goto fail_set;
+ }
+ }
+- _pam_drop(responses);
++ _pam_drop(response);
++
+ if (mls_enabled)
+ {
+- query_response(pamh,_("level:"), context_range_get(new_context),
+- &responses, debug);
+- if (responses[0]) {
+- if (context_range_set(new_context, responses))
+- goto fail_set;
++ 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;
+ }
+- _pam_drop(responses);
++ _pam_drop(response);
+ }
++
+ if (debug)
+ pam_syslog(pamh, LOG_NOTICE, "Selected Security Context %s", context_str(new_context));
+
+ /* 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;
+@@ -309,26 +345,120 @@ config_context (pam_handle_t *pamh, secu
+ 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;
+
+ fail_set:
+ free(type);
+- _pam_drop(responses);
++ _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)
+@@ -439,13 +569,14 @@ PAM_EXTERN int
+ pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED,
+ int argc, const char **argv)
+ {
+- int i, debug = 0, ttys=1, has_tty=isatty(0);
++ int i, debug = 0, ttys=1;
+ int verbose=0, close_session=0;
+ int select_context = 0;
+ int use_current_range = 0;
+ 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;
+@@ -472,13 +603,16 @@ pam_sm_open_session(pam_handle_t *pamh,
+ 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;
+ }
+
+@@ -510,12 +644,17 @@ pam_sm_open_session(pam_handle_t *pamh,
+ 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 && has_tty) {
+- user_context = config_context(pamh, default_user_context, debug);
+- if (user_context == NULL) {
++ if (select_context) {
++ 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);
+@@ -524,11 +663,9 @@ pam_sm_open_session(pam_handle_t *pamh,
+ return PAM_AUTH_ERR;
+ else
+ return PAM_SUCCESS;
+- }
+- }
++ }
+ }
+ else {
+- if (has_tty) {
+ user_context = manual_context(pamh,seuser,debug);
+ if (user_context == NULL) {
+ pam_syslog (pamh, LOG_ERR, "Unable to get valid context for %s",
+@@ -538,59 +675,6 @@ pam_sm_open_session(pam_handle_t *pamh,
+ else
+ return PAM_SUCCESS;
+ }
+- } else {
+- pam_syslog (pamh, LOG_ERR,
+- "Unable to get valid context for %s, No valid tty",
+- username);
+- if (security_getenforce() == 1)
+- return PAM_AUTH_ERR;
+- else
+- return PAM_SUCCESS;
+- }
+- }
+-
+- 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) {
+@@ -613,7 +697,7 @@ pam_sm_open_session(pam_handle_t *pamh,
+ }
+ }
+ }
+- if(ttys && tty ) {
++ if (ttys && tty) {
+ ttyn=strdup(tty);
+ ttyn_context=security_label_tty(pamh,ttyn,user_context);
+ }
diff --git a/pam.spec b/pam.spec
index 85d471b..15c1414 100644
--- a/pam.spec
+++ b/pam.spec
@@ -5,7 +5,7 @@
Summary: A security tool which provides authentication for applications
Name: pam
Version: 1.0.1
-Release: 2%{?dist}
+Release: 3%{?dist}
# The library is BSD licensed with option to relicense as GPLv2+ - this option is redundant
# as the BSD license allows that anyway. pam_timestamp and pam_console modules are GPLv2+,
# pam_rhosts_auth module is BSD with advertising
@@ -27,6 +27,7 @@ Patch2: db-4.6.18-glibc.patch
Patch4: pam-0.99.8.1-dbpam.patch
Patch10: pam-1.0.0-sepermit-screensaver.patch
Patch11: pam-1.0.1-selinux-restore-execcon.patch
+Patch12: pam-1.0.0-selinux-env-params.patch
Patch21: pam-0.99.10.0-unix-audit-failed.patch
Patch31: pam-0.99.3.0-cracklib-try-first-pass.patch
Patch32: pam-0.99.3.0-tally-fail-close.patch
@@ -104,6 +105,7 @@ popd
%patch4 -p1 -b .dbpam
%patch10 -p1 -b .screensaver
%patch11 -p1 -b .restore-execcon
+%patch12 -p0 -b .env-params
%patch21 -p1 -b .audit-failed
%patch31 -p1 -b .try-first-pass
%patch32 -p1 -b .fail-close
@@ -376,6 +378,9 @@ fi
%doc doc/adg/*.txt doc/adg/html
%changelog
+* Mon May 19 2008 Tomas Mraz 1.0.1-3
+- pam_selinux: add env_params option which will be used by OpenSSH
+
* Tue Apr 22 2008 Tomas Mraz 1.0.1-2
- pam_selinux: restore execcon properly (#443667)