diff --git a/pam-0.99.6.2-selinux-select-context.patch b/pam-0.99.6.2-selinux-select-context.patch
new file mode 100644
index 0000000..0e61a60
--- /dev/null
+++ b/pam-0.99.6.2-selinux-select-context.patch
@@ -0,0 +1,254 @@
+--- Linux-PAM-0.99.6.2/modules/pam_selinux/pam_selinux.8.xml.select-context 2006-11-10 17:48:59.000000000 +0100
++++ Linux-PAM-0.99.6.2/modules/pam_selinux/pam_selinux.8.xml 2006-11-10 17:52:36.000000000 +0100
+@@ -33,6 +33,9 @@
+
+ verbose
+
++
++ select_context
++
+
+
+
+@@ -118,6 +121,17 @@
+
+
+
++
++
++
++
++
++
++ Attempt to ask the user for a custom security context role.
++ If MLS is on ask also for sensitivity level.
++
++
++
+
+
+
+--- Linux-PAM-0.99.6.2/modules/pam_selinux/pam_selinux.c.select-context 2006-11-10 17:48:59.000000000 +0100
++++ Linux-PAM-0.99.6.2/modules/pam_selinux/pam_selinux.c 2006-11-10 18:00:11.000000000 +0100
+@@ -63,6 +63,7 @@
+ #include
+ #include
+ #include
++#include
+ #include
+ #include
+
+@@ -151,6 +152,8 @@
+ }
+ else
+ send_text(pamh,_("Not a valid security context"),debug);
++
++ context_free(new_context); /* next time around allocates another */
+ }
+ else {
+ _pam_drop(responses);
+@@ -161,6 +164,86 @@
+ return NULL;
+ }
+
++static int mls_range_allowed(security_context_t src, security_context_t dst)
++{
++ struct av_decision avd;
++ int retval;
++ unsigned int bit = CONTEXT__CONTAINS;
++
++ retval = security_compute_av(src, dst, SECCLASS_CONTEXT, bit, &avd);
++ if (retval || ((bit & avd.allowed) != bit))
++ return 0;
++
++ return 1;
++}
++
++static security_context_t
++config_context (pam_handle_t *pamh, security_context_t puser_context, int debug)
++{
++ security_context_t newcon;
++ context_t new_context;
++ int mls_enabled = is_selinux_mls_enabled();
++ char *responses;
++ char resp_val = 0;
++
++ while (1) {
++ query_response(pamh,
++ _("Would you like to enter a role/level? [y] "),
++ &responses,debug);
++
++ resp_val = responses[0];
++ _pam_drop(responses);
++ if ((resp_val == 'y') || (resp_val == 'Y') || (resp_val == '\0'))
++ {
++ new_context = context_new(puser_context);
++
++ /* Allow the user to enter role and level individually */
++ query_response(pamh,_("role: "),&responses,debug);
++ if (responses[0] && context_role_set(new_context, responses))
++ goto fail_set;
++ _pam_drop(responses);
++ if (mls_enabled)
++ {
++ query_response(pamh,_("level: "),&responses,debug);
++ if (responses[0] && context_range_set(new_context, responses))
++ goto fail_set;
++ _pam_drop(responses);
++ }
++
++ /* 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);
++
++ /* 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(puser_context, newcon))
++ goto fail_range;
++
++ freecon(puser_context);
++ return newcon;
++ }
++ else
++ send_text(pamh,_("Not a valid security context"),debug);
++
++ context_free(new_context); /* next time around allocates another */
++ }
++ else
++ break;
++ } /* end while */
++
++ freecon(puser_context);
++ return NULL;
++
++ fail_set:
++ _pam_drop(responses);
++ context_free (new_context);
++ fail_range:
++ freecon(puser_context);
++ return NULL;
++}
++
+ static void
+ security_restorelabel_tty(const pam_handle_t *pamh,
+ const char *tty, security_context_t context)
+@@ -273,10 +356,12 @@
+ {
+ int i, debug = 0, ttys=1, has_tty=isatty(0);
+ int verbose=0, close_session=0;
++ int select_context = 0;
+ int ret = 0;
+ security_context_t* contextlist = NULL;
+ int num_contexts = 0;
+- const void *username = NULL;
++ const void *pusername = NULL;
++ const char *username = NULL;
+ const void *tty = NULL;
+ char *seuser=NULL;
+ char *level=NULL;
+@@ -295,6 +380,9 @@
+ if (strcmp(argv[i], "close") == 0) {
+ close_session = 1;
+ }
++ if (strcmp(argv[i], "select_context") == 0) {
++ select_context = 1;
++ }
+ }
+
+ if (debug)
+@@ -307,10 +395,11 @@
+ if (!(selinux_enabled = is_selinux_enabled()>0) )
+ return PAM_SUCCESS;
+
+- if (pam_get_item(pamh, PAM_USER, &username) != PAM_SUCCESS ||
+- username == NULL) {
++ if (pam_get_item(pamh, PAM_USER, &pusername) != PAM_SUCCESS ||
++ pusername == NULL) {
+ return PAM_USER_UNKNOWN;
+ }
++ username = pusername;
+
+ if (getseuserbyname(username, &seuser, &level)==0) {
+ num_contexts = get_ordered_context_list_with_level(seuser,
+@@ -319,19 +408,32 @@
+ &contextlist);
+ if (debug)
+ pam_syslog(pamh, LOG_DEBUG, "Username= %s SELinux User = %s Level= %s",
+- (const char *)username, seuser, level);
++ username, seuser, level);
+ free(seuser);
+ free(level);
+ }
+ if (num_contexts > 0) {
+ user_context = (security_context_t) strdup(contextlist[0]);
++
++ if (select_context && has_tty) {
++ user_context = config_context(pamh, user_context, debug);
++ if (user_context == NULL) {
++ pam_syslog(pamh, LOG_ERR, "Unable to get valid context for %s",
++ username);
++ if (security_getenforce() == 1)
++ return PAM_AUTH_ERR;
++ else
++ return PAM_SUCCESS;
++ }
++ }
++
+ freeconary(contextlist);
+ } else {
+ if (has_tty) {
+ user_context = manual_context(pamh,username,debug);
+ if (user_context == NULL) {
+ pam_syslog (pamh, LOG_ERR, "Unable to get valid context for %s",
+- (const char *)username);
++ username);
+ if (security_getenforce() == 1)
+ return PAM_AUTH_ERR;
+ else
+@@ -340,7 +442,7 @@
+ } else {
+ pam_syslog (pamh, LOG_ERR,
+ "Unable to get valid context for %s, No valid tty",
+- (const char *)username);
++ username);
+ if (security_getenforce() == 1)
+ return PAM_AUTH_ERR;
+ else
+@@ -381,7 +483,7 @@
+ if (ret) {
+ pam_syslog(pamh, LOG_ERR,
+ "Error! Unable to set %s executable context %s.",
+- (const char *)username, user_context);
++ username, user_context);
+ if (security_getenforce() == 1) {
+ freecon(user_context);
+ return PAM_AUTH_ERR;
+@@ -389,7 +491,7 @@
+ } else {
+ if (debug)
+ pam_syslog(pamh, LOG_NOTICE, "set %s security context to %s",
+- (const char *)username, user_context);
++ username, user_context);
+ }
+ #ifdef HAVE_SETKEYCREATECON
+ ret = setkeycreatecon(user_context);
+@@ -402,7 +504,7 @@
+ if (ret) {
+ pam_syslog(pamh, LOG_ERR,
+ "Error! Unable to set %s key creation context %s.",
+- (const char *)username, user_context);
++ username, user_context);
+ if (security_getenforce() == 1) {
+ freecon(user_context);
+ return PAM_AUTH_ERR;
+@@ -410,7 +512,7 @@
+ } else {
+ if (debug)
+ pam_syslog(pamh, LOG_NOTICE, "set %s key creation context to %s",
+- (const char *)username, user_context);
++ username, user_context);
+ }
+ #endif
+ freecon(user_context);
diff --git a/pam.spec b/pam.spec
index 4e5a55e..cc49033 100644
--- a/pam.spec
+++ b/pam.spec
@@ -11,7 +11,7 @@
Summary: A security tool which provides authentication for applications
Name: pam
Version: 0.99.6.2
-Release: 4%{?dist}
+Release: 5%{?dist}
License: GPL or BSD
Group: System Environment/Base
Source0: http://ftp.us.kernel.org/pub/linux/libs/pam/pre/library/Linux-PAM-%{version}.tar.bz2
@@ -39,6 +39,7 @@ Patch88: pam-0.99.6.2-doc-add-ids.patch
Patch89: pam-0.99.6.2-namespace-overflow.patch
Patch90: pam-0.99.6.2-keyinit-setgid.patch
Patch91: pam-0.99.6.2-unix-username.patch
+Patch92: pam-0.99.6.2-selinux-select-context.patch
BuildRoot: %{_tmppath}/%{name}-root
Requires: cracklib, cracklib-dicts >= 2.8
@@ -52,8 +53,8 @@ BuildRequires: perl, pkgconfig
BuildRequires: audit-libs-devel >= 1.0.8
Requires: audit-libs >= 1.0.8
%endif
-BuildRequires: libselinux-devel >= 1.27.7
-Requires: libselinux >= 1.27.7
+BuildRequires: libselinux-devel >= 1.33.2
+Requires: libselinux >= 1.33.2
BuildRequires: glibc >= 2.3.90-37
Requires: glibc >= 2.3.90-37
# Following deps are necessary only to build the pam library documentation.
@@ -105,6 +106,7 @@ cp %{SOURCE7} .
%patch89 -p1 -b .overflow
%patch90 -p1 -b .setgid
%patch91 -p1 -b .username
+%patch92 -p1 -b .select-context
autoreconf
@@ -382,6 +384,9 @@ fi
%doc doc/adg/*.txt doc/adg/html
%changelog
+* Thu Nov 30 2006 Tomas Mraz 0.99.6.2-5
+- add select-context option to pam_selinux (#213812)
+
* Mon Nov 13 2006 Tomas Mraz 0.99.6.2-4
- update internal db4 to 4.5.20 version
- move setgid before setuid in pam_keyinit (#212329)