rpms/pam/F-9 pam-1.0.0-selinux-env-params.patch, NONE, 1.1 pam-1.0.1-autoreconf.patch, NONE, 1.1 pam-1.0.1-namespace-create.patch, NONE, 1.1 pam-1.0.1-unix-prompts.patch, NONE, 1.1 pam.spec, 1.178, 1.179

Tomáš Mráz (tmraz) fedora-extras-commits at redhat.com
Wed May 21 08:38:19 UTC 2008


Author: tmraz

Update of /cvs/pkgs/rpms/pam/F-9
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv2732

Modified Files:
	pam.spec 
Added Files:
	pam-1.0.0-selinux-env-params.patch pam-1.0.1-autoreconf.patch 
	pam-1.0.1-namespace-create.patch pam-1.0.1-unix-prompts.patch 
Log Message:
* Wed May 21 2008 Tomas Mraz <tmraz at redhat.com> 1.0.1-4 
- pam_namespace: allow safe creation of directories owned by user (#437116)
- pam_unix: fix multiple error prompts on password change (#443872)

* Tue May 20 2008 Tomas Mraz <tmraz at redhat.com> 1.0.1-3 
- pam_selinux: add env_params option which will be used by OpenSSH
- fix build with new autoconf


pam-1.0.0-selinux-env-params.patch:

--- NEW FILE pam-1.0.0-selinux-env-params.patch ---
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
       </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>
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 <dwalsh at redhat.com>
+ * Additional improvements by Tomas Mraz <tmraz at redhat.com>
  *
  * 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);
   }

pam-1.0.1-autoreconf.patch:

--- NEW FILE pam-1.0.1-autoreconf.patch ---
diff -up Linux-PAM-1.0.1/configure.in.autoreconf Linux-PAM-1.0.1/configure.in
--- Linux-PAM-1.0.1/configure.in.autoreconf	2008-05-19 17:45:00.000000000 +0200
+++ Linux-PAM-1.0.1/configure.in	2008-05-20 15:24:54.000000000 +0200
@@ -72,7 +72,7 @@ fi
 AM_CONDITIONAL([STATIC_MODULES], [test "$STATIC_MODULES" != "no"])
 
 dnl Checks for programs.
-AC_GNU_SOURCE
+AC_USE_SYSTEM_EXTENSIONS
 AC_PROG_CC
 AC_PROG_YACC
 AM_PROG_LEX
@@ -491,8 +491,7 @@ AM_GNU_GETTEXT_VERSION
 AM_GNU_GETTEXT([external])
 AC_CHECK_FUNCS(dngettext)
 
-AH_VERBATIM([_ZZENABLE_NLS],
-[#ifdef ENABLE_NLS
+AH_BOTTOM([#ifdef ENABLE_NLS
 #include <libintl.h>
 #define _(msgid) dgettext(PACKAGE, msgid)
 #define N_(msgid) msgid

pam-1.0.1-namespace-create.patch:

--- NEW FILE pam-1.0.1-namespace-create.patch ---
diff -up Linux-PAM-1.0.1/modules/pam_namespace/pam_namespace.c.create Linux-PAM-1.0.1/modules/pam_namespace/pam_namespace.c
--- Linux-PAM-1.0.1/modules/pam_namespace/pam_namespace.c.create	2008-03-20 18:06:32.000000000 +0100
+++ Linux-PAM-1.0.1/modules/pam_namespace/pam_namespace.c	2008-04-03 17:32:28.000000000 +0200
@@ -32,6 +32,8 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
+#define _ATFILE_SOURCE
+
 #include "pam_namespace.h"
 #include "argv_parse.h"
 
@@ -78,11 +80,29 @@ static void del_polydir_list(struct poly
 	}
 }
 
-static void cleanup_data(pam_handle_t *pamh UNUSED , void *data, int err UNUSED)
+static void unprotect_dirs(struct protect_dir_s *dir)
+{
+	struct protect_dir_s *next;
+
+	while (dir != NULL) {
+		umount(dir->dir);
+		free(dir->dir);
+		next = dir->next;
+		free(dir);
+		dir = next;
+	}
+}
+
+static void cleanup_polydir_data(pam_handle_t *pamh UNUSED , void *data, int err UNUSED)
 {
 	del_polydir_list(data);
 }
 
+static void cleanup_protect_data(pam_handle_t *pamh UNUSED , void *data, int err UNUSED)
+{
+	unprotect_dirs(data);
+}
+
 static char *expand_variables(const char *orig, const char *var_names[], const char *var_values[])
 {
 	const char *src = orig;
@@ -132,8 +152,8 @@ static char *expand_variables(const char
 
 static int parse_create_params(char *params, struct polydir_s *poly)
 {
-    char *sptr;
-    struct passwd *pwd;
+    char *next;
+    struct passwd *pwd = NULL;
     struct group *grp;
 
     poly->mode = (mode_t)ULONG_MAX;
@@ -144,28 +164,40 @@ static int parse_create_params(char *par
     	return 0;
     params++;
     
-    params = strtok_r(params, ",", &sptr);
-    if (params == NULL)
-    	return 0;
+    next = strchr(params, ',');
+    if (next != NULL) {
+	*next = '\0';
+	next++;
+    }
 
-    errno = 0;
-    poly->mode = (mode_t)strtoul(params, NULL, 0);
-    if (errno != 0) {
-    	poly->mode = (mode_t)ULONG_MAX;
+    if (*params != '\0') {
+	errno = 0;
+	poly->mode = (mode_t)strtoul(params, NULL, 0);
+	if (errno != 0) {
+	    poly->mode = (mode_t)ULONG_MAX;
+	}
     }
 
-    params = strtok_r(NULL, ",", &sptr);
+    params = next;
     if (params == NULL)
     	return 0;
+    next = strchr(params, ',');
+    if (next != NULL) {
+	*next = '\0';
+	next++;
+    }
 
-    pwd = getpwnam(params); /* session modules are not reentrant */
-    if (pwd == NULL)
-    	return -1;
-    poly->owner = pwd->pw_uid;
-    
-    params = strtok_r(NULL, ",", &sptr);
-    if (params == NULL) {
-    	poly->group = pwd->pw_gid;
+    if (*params != '\0') {
+	pwd = getpwnam(params); /* session modules are not reentrant */
+	if (pwd == NULL)
+	    return -1;
+	poly->owner = pwd->pw_uid;
+    }
+
+    params = next;
+    if (params == NULL || *params == '\0') {
+	if (pwd != NULL)
+	    poly->group = pwd->pw_gid;
     	return 0;
     }
     grp = getgrnam(params);
@@ -199,7 +231,7 @@ static int parse_method(char *method, st
 		struct instance_data *idata)
 {
     enum polymethod pm;
-    char *sptr;
+    char *sptr = NULL;
     static const char *method_names[] = { "user", "context", "level", "tmpdir",
     	"tmpfs", NULL };
     static const char *flag_names[] = { "create", "noinit", "iscript",
@@ -921,10 +953,158 @@ fail:
     return rc;
 }
 
+static int protect_mount(int dfd, const char *path, struct instance_data *idata)
+{
+	struct protect_dir_s *dir = idata->protect_dirs;
+	char tmpbuf[64];
+	
+	while (dir != NULL) {
+		if (strcmp(path, dir->dir) == 0) {
+			return 0;
+		}
+		dir = dir->next;
+	}
+	
+	dir = calloc(1, sizeof(*dir));
+	
+	if (dir == NULL) {
+		return -1;
+	}
+	
+	dir->dir = strdup(path);
+	
+	if (dir->dir == NULL) {
+		free(dir);
+		return -1;
+	}
+	
+	snprintf(tmpbuf, sizeof(tmpbuf), "/proc/self/fd/%d", dfd);
+	
+	if (idata->flags & PAMNS_DEBUG) {
+		pam_syslog(idata->pamh, LOG_INFO,
+			"Protect mount of %s over itself", path);
+	}
+	
+	if (mount(tmpbuf, tmpbuf, NULL, MS_BIND, NULL) != 0) {
+		int save_errno = errno;
+		pam_syslog(idata->pamh, LOG_ERR,
+			"Protect mount of %s failed: %m", tmpbuf);
+		free(dir->dir);
+		free(dir);
+		errno = save_errno;
+		return -1;
+	}
+	
+	dir->next = idata->protect_dirs;
+	idata->protect_dirs = dir;
+
+	return 0;
+}
+
+static int protect_dir(const char *path, mode_t mode, int do_mkdir,
+	struct instance_data *idata)
+{
+	char *p = strdup(path);
+	char *d;
+	char *dir = p;
+	int dfd = AT_FDCWD;
+	int dfd_next;
+	int save_errno;
+	int flags = O_RDONLY;
+	int rv = -1;
+	struct stat st;
+
+	if (p == NULL) {
+		goto error;
+	}
+	
+	if (*dir == '/') {
+		dfd = open("/", flags);
+		if (dfd == -1) {
+			goto error;
+		}
+		dir++; 	/* assume / is safe */
+	}
+	
+	while ((d=strchr(dir, '/')) != NULL) {
+		*d = '\0';
+		dfd_next = openat(dfd, dir, flags);
+		if (dfd_next == -1) {
+			goto error;
+		}
+
+		if (dfd != AT_FDCWD)
+			close(dfd);
+		dfd = dfd_next;
+
+		if (fstat(dfd, &st) != 0) {
+			goto error;
+		}
+		
+		if (flags & O_NOFOLLOW) { 
+			/* we are inside user-owned dir - protect */
+			if (protect_mount(dfd, p, idata) == -1)
+				goto error;
+		} else if (st.st_uid != 0 || st.st_gid != 0 ||
+			(st.st_mode & S_IWOTH)) {
+			/* do not follow symlinks on subdirectories */
+			flags |= O_NOFOLLOW;
+		}
+
+		*d = '/';
+		dir = d + 1;
+	}
+
+	rv = openat(dfd, dir, flags);
+	
+	if (rv == -1) {
+		if (!do_mkdir || mkdirat(dfd, dir, mode) != 0) {
+			goto error;
+		}
+		rv = openat(dfd, dir, flags);
+	}
+	
+	if (rv != -1) {
+		if (fstat(rv, &st) != 0) {
+			save_errno = errno;
+			close(rv);
+			rv = -1;
+			errno = save_errno;
+			goto error;
+		}
+		if (!S_ISDIR(st.st_mode)) {
+			close(rv);
+			errno = ENOTDIR;
+			rv = -1;
+			goto error;
+		}
+	}
+
+	if (flags & O_NOFOLLOW) { 
+		/* we are inside user-owned dir - protect */
+		if (protect_mount(rv, p, idata) == -1) {
+			save_errno = errno;
+			close(rv);
+			rv = -1;
+			errno = save_errno;
+		}
+	}
+
+error:
+	save_errno = errno;
+	free(p);
+	if (dfd != AT_FDCWD)
+		close(dfd);
+	errno = save_errno;
+
+	return rv;
+}
+
 static int check_inst_parent(char *ipath, struct instance_data *idata)
 {
 	struct stat instpbuf;
 	char *inst_parent, *trailing_slash;
+	int dfd;
 	/*
 	 * stat the instance parent path to make sure it exists
 	 * and is a directory. Check that its mode is 000 (unless the
@@ -942,30 +1122,27 @@ static int check_inst_parent(char *ipath
 	if (trailing_slash)
 		*trailing_slash = '\0';
 
-	if (stat(inst_parent, &instpbuf) < 0) {
-		pam_syslog(idata->pamh, LOG_ERR, "Error stating %s, %m", inst_parent);
-		free(inst_parent);
-		return PAM_SESSION_ERR;
-	}
+	dfd = protect_dir(inst_parent, 0, 1, idata);
 
-	/*
-	 * Make sure we are dealing with a directory
-	 */
-	if (!S_ISDIR(instpbuf.st_mode)) {
-		pam_syslog(idata->pamh, LOG_ERR, "Instance parent %s is not a dir",
-				inst_parent);
+	if (dfd == -1 || fstat(dfd, &instpbuf) < 0) {
+		pam_syslog(idata->pamh, LOG_ERR,
+			"Error creating or accessing instance parent %s, %m", inst_parent);
+		if (dfd != -1)
+			close(dfd);
 		free(inst_parent);
 		return PAM_SESSION_ERR;
 	}
 
 	if ((idata->flags & PAMNS_IGN_INST_PARENT_MODE) == 0) {
-		if (instpbuf.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) {
-			pam_syslog(idata->pamh, LOG_ERR, "Mode of inst parent %s not 000",
+		if ((instpbuf.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) || instpbuf.st_uid != 0) {
+			pam_syslog(idata->pamh, LOG_ERR, "Mode of inst parent %s not 000 or owner not root",
 					inst_parent);
+			close(dfd);
 			free(inst_parent);
 			return PAM_SESSION_ERR;
 		}
 	}
+	close(dfd);
 	free(inst_parent);
 	return PAM_SUCCESS;
 }
@@ -1051,6 +1228,8 @@ static int create_polydir(struct polydir
     security_context_t dircon, oldcon = NULL;
 #endif
     const char *dir = polyptr->dir;
+    uid_t uid;
+    gid_t gid;
 
     if (polyptr->mode != (mode_t)ULONG_MAX)
             mode = polyptr->mode;
@@ -1077,8 +1256,8 @@ static int create_polydir(struct polydir
     }
 #endif
 
-    rc = mkdir(dir, mode);
-    if (rc != 0) {
+    rc = protect_dir(dir, mode, 1, idata);
+    if (rc == -1) {
             pam_syslog(idata->pamh, LOG_ERR,
                        "Error creating directory %s: %m", dir);
             return PAM_SESSION_ERR;
@@ -1098,36 +1277,41 @@ static int create_polydir(struct polydir
 
     if (polyptr->mode != (mode_t)ULONG_MAX) {
     	/* explicit mode requested */
-    	if (chmod(dir, mode) != 0) {
+    	if (fchmod(rc, mode) != 0) {
 		pam_syslog(idata->pamh, LOG_ERR,
                     	"Error changing mode of directory %s: %m", dir);
+                close(rc);
+                umount(dir); /* undo the eventual protection bind mount */
     		rmdir(dir);
         	return PAM_SESSION_ERR;
     	}
     }
 
-    if (polyptr->owner != (uid_t)ULONG_MAX) {
-            if (chown(dir, polyptr->owner, polyptr->group) != 0) {
-                    pam_syslog(idata->pamh, LOG_ERR,
-                               "Unable to change owner on directory %s: %m", dir);
-		    rmdir(dir);
-                    return PAM_SESSION_ERR;
-            }
-            if (idata->flags & PAMNS_DEBUG)
-                    pam_syslog(idata->pamh, LOG_DEBUG,
-                               "Polydir owner %u group %u from configuration", polyptr->owner, polyptr->group);
-    } else {
-            if (chown(dir, idata->uid, idata->gid) != 0) {
-                    pam_syslog(idata->pamh, LOG_ERR,
-                               "Unable to change owner on directory %s: %m", dir);
-		    rmdir(dir);
-                    return PAM_SESSION_ERR;
-            }
-            if (idata->flags & PAMNS_DEBUG)
-                    pam_syslog(idata->pamh, LOG_DEBUG,
-                               "Polydir owner %u group %u", idata->uid, idata->gid);
+    if (polyptr->owner != (uid_t)ULONG_MAX)
+	uid = polyptr->owner;
+    else
+	uid = idata->uid;
+
+    if (polyptr->group != (gid_t)ULONG_MAX)
+	gid = polyptr->group;
+    else
+	gid = idata->gid;
+
+    if (fchown(rc, uid, gid) != 0) {
+        pam_syslog(idata->pamh, LOG_ERR,
+                   "Unable to change owner on directory %s: %m", dir);
+        close(rc);
+        umount(dir); /* undo the eventual protection bind mount */
+	rmdir(dir);
+	return PAM_SESSION_ERR;
     }
 
+    close(rc);
+
+    if (idata->flags & PAMNS_DEBUG)
+	pam_syslog(idata->pamh, LOG_DEBUG,
+	           "Polydir owner %u group %u", uid, gid);
+
     return PAM_SUCCESS;
 }
 
@@ -1135,17 +1319,16 @@ static int create_polydir(struct polydir
  * Create polyinstantiated instance directory (ipath).
  */
 #ifdef WITH_SELINUX
-static int create_dirs(struct polydir_s *polyptr, char *ipath, struct stat *statbuf,
+static int create_instance(struct polydir_s *polyptr, char *ipath, struct stat *statbuf,
         security_context_t icontext, security_context_t ocontext,
 	struct instance_data *idata)
 #else
-static int create_dirs(struct polydir_s *polyptr, char *ipath, struct stat *statbuf,
+static int create_instance(struct polydir_s *polyptr, char *ipath, struct stat *statbuf,
 	struct instance_data *idata)
 #endif
 {
     struct stat newstatbuf;
     int fd;
-    int newdir = 0;
 
     /*
      * Check to make sure instance parent is valid.
@@ -1171,7 +1354,7 @@ static int create_dirs(struct polydir_s 
 	strcpy(ipath, polyptr->instance_prefix);
     } else if (mkdir(ipath, S_IRUSR) < 0) {
         if (errno == EEXIST)
-            goto inst_init;
+            return PAM_IGNORE;
         else {
             pam_syslog(idata->pamh, LOG_ERR, "Error creating %s, %m",
 			ipath);
@@ -1179,7 +1362,6 @@ static int create_dirs(struct polydir_s 
         }
     }
 
-    newdir = 1;
     /* Open a descriptor to it to prevent races */
     fd = open(ipath, O_DIRECTORY | O_RDONLY);
     if (fd < 0) {
@@ -1235,33 +1417,22 @@ static int create_dirs(struct polydir_s 
         return PAM_SESSION_ERR;
     }
     close(fd);
-
-    /*
-     * Check to see if there is a namespace initialization script in
-     * the /etc/security directory. If such a script exists
-     * execute it and pass directory to polyinstantiate and instance
-     * directory as arguments.
-     */
-
-inst_init:
-    if (polyptr->flags & POLYDIR_NOINIT)
-    	return PAM_SUCCESS;
-
-    return inst_init(polyptr, ipath, idata, newdir);
+    return PAM_SUCCESS;
 }
 
 
 /*
  * This function performs the namespace setup for a particular directory
- * that is being polyinstantiated. It creates an MD5 hash of instance
- * directory, calls create_dirs to create it with appropriate
+ * that is being polyinstantiated. It calls poly_name to create name of instance
+ * directory, calls create_instance to mkdir it with appropriate
  * security attributes, and performs bind mount to setup the process
  * namespace.
  */
 static int ns_setup(struct polydir_s *polyptr,
 	struct instance_data *idata)
 {
-    int retval = 0;
+    int retval;
+    int newdir = 1;
     char *inst_dir = NULL;
     char *instname = NULL;
     struct stat statbuf;
@@ -1273,37 +1444,40 @@ static int ns_setup(struct polydir_s *po
         pam_syslog(idata->pamh, LOG_DEBUG,
                "Set namespace for directory %s", polyptr->dir);
 
-    while (stat(polyptr->dir, &statbuf) < 0) {
-    	if (retval || !(polyptr->flags & POLYDIR_CREATE)) {
-        	pam_syslog(idata->pamh, LOG_ERR, "Error stating %s, %m",
-			polyptr->dir);
-        	return PAM_SESSION_ERR;
-    	} else {
-    		if (create_polydir(polyptr, idata) != PAM_SUCCESS)
-    			return PAM_SESSION_ERR;
-    		retval = PAM_SESSION_ERR; /* bail out on next failed stat */
-    	}
-    }
+    retval = protect_dir(polyptr->dir, 0, 0, idata);
 
-    /*
-     * Make sure we are dealing with a directory
-     */
-    if (!S_ISDIR(statbuf.st_mode)) {
-	pam_syslog(idata->pamh, LOG_ERR, "Polydir %s is not a dir",
+    if (retval < 0 && errno != ENOENT) {
+	pam_syslog(idata->pamh, LOG_ERR, "Polydir %s access error: %m",
 		polyptr->dir);
-        return PAM_SESSION_ERR;
+	return PAM_SESSION_ERR;    
     }
 
+    if (retval < 0 && (polyptr->flags & POLYDIR_CREATE)) {
+	if (create_polydir(polyptr, idata) != PAM_SUCCESS)
+		return PAM_SESSION_ERR;
+    } else {
+    	close(retval);
+    }
+    
     if (polyptr->method == TMPFS) {
 	if (mount("tmpfs", polyptr->dir, "tmpfs", 0, NULL) < 0) {
 	    pam_syslog(idata->pamh, LOG_ERR, "Error mounting tmpfs on %s, %m",
         	polyptr->dir);
             return PAM_SESSION_ERR;
 	}
-	/* we must call inst_init after the mount in this case */
+
+	if (polyptr->flags & POLYDIR_NOINIT)
+	    return PAM_SUCCESS;
+
 	return inst_init(polyptr, "tmpfs", idata, 1);
     }
 
+    if (stat(polyptr->dir, &statbuf) < 0) {
+	pam_syslog(idata->pamh, LOG_ERR, "Error stating %s: %m",
+		polyptr->dir);
+        return PAM_SESSION_ERR;
+    }
+ 
     /*
      * Obtain the name of instance pathname based on the
      * polyinstantiation method and instance context returned by
@@ -1341,14 +1515,18 @@ static int ns_setup(struct polydir_s *po
      * contexts, owner, group and mode bits.
      */
 #ifdef WITH_SELINUX
-    retval = create_dirs(polyptr, inst_dir, &statbuf, instcontext,
+    retval = create_instance(polyptr, inst_dir, &statbuf, instcontext,
 			 origcontext, idata);
 #else
-    retval = create_dirs(polyptr, inst_dir, &statbuf, idata);
+    retval = create_instance(polyptr, inst_dir, &statbuf, idata);
 #endif
 
-    if (retval < 0) {
-        pam_syslog(idata->pamh, LOG_ERR, "Error creating instance dir");
+    if (retval == PAM_IGNORE) {
+    	newdir = 0;
+    	retval = PAM_SUCCESS;
+    }
+
+    if (retval != PAM_SUCCESS) {
         goto error_out;
     }
 
@@ -1363,6 +1541,9 @@ static int ns_setup(struct polydir_s *po
         goto error_out;
     }
 
+    if (!(polyptr->flags & POLYDIR_NOINIT))
+	retval = inst_init(polyptr, inst_dir, idata, newdir);
+
     goto cleanup;
 
     /*
@@ -1600,12 +1781,21 @@ static int setup_namespace(struct instan
         }
     }
 out:
-    if (retval != PAM_SUCCESS)
+    if (retval != PAM_SUCCESS) {
+    	cleanup_tmpdirs(idata);
+    	unprotect_dirs(idata->protect_dirs);
+    } else if (pam_set_data(idata->pamh, NAMESPACE_PROTECT_DATA, idata->protect_dirs,
+    		cleanup_protect_data) != PAM_SUCCESS) {
+	pam_syslog(idata->pamh, LOG_ERR, "Unable to set namespace protect data");
     	cleanup_tmpdirs(idata);
-    else if (pam_set_data(idata->pamh, NAMESPACE_POLYDIR_DATA, idata->polydirs_ptr,
-    		cleanup_data) != PAM_SUCCESS) {
-	pam_syslog(idata->pamh, LOG_ERR, "Unable to set namespace data");
+    	unprotect_dirs(idata->protect_dirs);
+	return PAM_SYSTEM_ERR;
+    } else if (pam_set_data(idata->pamh, NAMESPACE_POLYDIR_DATA, idata->polydirs_ptr,
+    		cleanup_polydir_data) != PAM_SUCCESS) {
+	pam_syslog(idata->pamh, LOG_ERR, "Unable to set namespace polydir data");
     	cleanup_tmpdirs(idata);
+    	pam_set_data(idata->pamh, NAMESPACE_PROTECT_DATA, NULL, NULL);
+    	idata->protect_dirs = NULL;
 	return PAM_SYSTEM_ERR;
     }
     return retval;
@@ -1742,6 +1932,7 @@ PAM_EXTERN int pam_sm_open_session(pam_h
     /* init instance data */
     idata.flags = 0;
     idata.polydirs_ptr = NULL;
+    idata.protect_dirs = NULL;
     idata.pamh = pamh;
 #ifdef WITH_SELINUX
     if (is_selinux_enabled())
@@ -1893,6 +2084,7 @@ PAM_EXTERN int pam_sm_close_session(pam_
     }
 
     pam_set_data(idata.pamh, NAMESPACE_POLYDIR_DATA, NULL, NULL);
+    pam_set_data(idata.pamh, NAMESPACE_PROTECT_DATA, NULL, NULL);
     
     return PAM_SUCCESS;
 }
diff -up Linux-PAM-1.0.1/modules/pam_namespace/pam_namespace.h.create Linux-PAM-1.0.1/modules/pam_namespace/pam_namespace.h
--- Linux-PAM-1.0.1/modules/pam_namespace/pam_namespace.h.create	2008-02-13 13:49:44.000000000 +0100
+++ Linux-PAM-1.0.1/modules/pam_namespace/pam_namespace.h	2008-03-20 18:07:29.000000000 +0100
@@ -107,6 +107,7 @@
 
 #define NAMESPACE_MAX_DIR_LEN 80
 #define NAMESPACE_POLYDIR_DATA "pam_namespace:polydir_data"
+#define NAMESPACE_PROTECT_DATA "pam_namespace:protect_data"
 
 /*
  * Polyinstantiation method options, based on user, security context
@@ -156,9 +157,15 @@ struct polydir_s {
     struct polydir_s *next;		/* pointer to the next polydir entry */
 };
 
+struct protect_dir_s {
+    char *dir;				/* protected directory */
+    struct protect_dir_s *next;		/* next entry */
+};
+
 struct instance_data {
     pam_handle_t *pamh;		/* The pam handle for this instance */
     struct polydir_s *polydirs_ptr; /* The linked list pointer */
+    struct protect_dir_s *protect_dirs;	/* The pointer to stack of mount-protected dirs */
     char user[LOGIN_NAME_MAX];	/* User name */
     char ruser[LOGIN_NAME_MAX];	/* Requesting user name */
     uid_t uid;			/* The uid of the user */
@@ -166,3 +173,4 @@ struct instance_data {
     uid_t ruid;			/* The uid of the requesting user */
     unsigned long flags;	/* Flags for debug, selinux etc */
 };
+
diff -up Linux-PAM-1.0.1/modules/pam_namespace/namespace.conf.5.xml.create Linux-PAM-1.0.1/modules/pam_namespace/namespace.conf.5.xml
--- Linux-PAM-1.0.1/modules/pam_namespace/namespace.conf.5.xml.create	2008-02-13 13:49:44.000000000 +0100
+++ Linux-PAM-1.0.1/modules/pam_namespace/namespace.conf.5.xml	2008-04-18 14:38:57.000000000 +0200
@@ -25,8 +25,8 @@
       Directories can be polyinstantiated based on user name
       or, in the case of SELinux, user name, sensitivity level or complete security context.  If an
       executable script <filename>/etc/security/namespace.init</filename>
-      exists, it is used to initialize the namespace every time a new instance
-      directory is setup. The script receives the polyinstantiated
+      exists, it is used to initialize the namespace every time an instance
+      directory is set up and mounted. The script receives the polyinstantiated
       directory path and the instance directory path as its arguments.
     </para>
 
diff -up Linux-PAM-1.0.1/modules/pam_namespace/pam_namespace.8.xml.create Linux-PAM-1.0.1/modules/pam_namespace/pam_namespace.8.xml
--- Linux-PAM-1.0.1/modules/pam_namespace/pam_namespace.8.xml.create	2008-02-13 13:49:44.000000000 +0100
+++ Linux-PAM-1.0.1/modules/pam_namespace/pam_namespace.8.xml	2008-04-18 14:40:54.000000000 +0200
@@ -64,11 +64,11 @@
       provides a different instance of itself based on user name, or when
       using SELinux, user name, security context or both.  If an executable
       script <filename>/etc/security/namespace.init</filename> exists, it
-      is used to initialize the namespace every time a new instance
-      directory is setup. The script receives the polyinstantiated
-      directory path, the instance directory path, flag whether the instance
-      directory was newly created (0 for no, 1 for yes), and the user name
-      as its arguments.
+      is used to initialize the instance directory after it is set up
+      and mounted on the polyinstantiated direcory. The script receives the
+      polyinstantiated directory path, the instance directory path, flag
+      whether the instance directory was newly created (0 for no, 1 for yes),
+      and the user name as its arguments.
     </para>
 
     <para>

pam-1.0.1-unix-prompts.patch:

--- NEW FILE pam-1.0.1-unix-prompts.patch ---
diff -up Linux-PAM-1.0.1/modules/pam_unix/pam_unix_passwd.c.prompts Linux-PAM-1.0.1/modules/pam_unix/pam_unix_passwd.c
--- Linux-PAM-1.0.1/modules/pam_unix/pam_unix_passwd.c.prompts	2008-02-29 16:22:03.000000000 +0100
+++ Linux-PAM-1.0.1/modules/pam_unix/pam_unix_passwd.c	2008-04-24 13:27:29.000000000 +0200
@@ -699,6 +699,10 @@ PAM_EXTERN int pam_sm_chauthtok(pam_hand
 				pass_new = NULL;
 			}
 			retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new);
+			
+			if (retval != PAM_SUCCESS && off(UNIX_NOT_SET_PASS, ctrl)) {
+				pam_set_item(pamh, PAM_AUTHTOK, NULL);
+			}
 		}
 
 		if (retval != PAM_SUCCESS) {
diff -up Linux-PAM-1.0.1/modules/pam_unix/support.c.prompts Linux-PAM-1.0.1/modules/pam_unix/support.c
--- Linux-PAM-1.0.1/modules/pam_unix/support.c.prompts	2008-01-23 16:35:13.000000000 +0100
+++ Linux-PAM-1.0.1/modules/pam_unix/support.c	2008-04-24 14:49:21.000000000 +0200
@@ -743,11 +743,11 @@ int _unix_read_password(pam_handle_t * p
 			return retval;
 		} else if (*pass != NULL) {	/* we have a password! */
 			return PAM_SUCCESS;
-		} else if (on(UNIX_USE_FIRST_PASS, ctrl)) {
-			return PAM_AUTHTOK_RECOVERY_ERR;	  /* didn't work */
 		} else if (on(UNIX_USE_AUTHTOK, ctrl)
 			   && off(UNIX__OLD_PASSWD, ctrl)) {
 			return PAM_AUTHTOK_ERR;
+		} else if (on(UNIX_USE_FIRST_PASS, ctrl)) {
+			return PAM_AUTHTOK_RECOVERY_ERR;	  /* didn't work */
 		}
 	}
 	/*


Index: pam.spec
===================================================================
RCS file: /cvs/pkgs/rpms/pam/F-9/pam.spec,v
retrieving revision 1.178
retrieving revision 1.179
diff -u -r1.178 -r1.179
--- pam.spec	22 Apr 2008 19:40:54 -0000	1.178
+++ pam.spec	21 May 2008 08:37:37 -0000	1.179
@@ -5,7 +5,7 @@
 Summary: A security tool which provides authentication for applications
 Name: pam
 Version: 1.0.1
-Release: 2%{?dist}
+Release: 4%{?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
@@ -25,11 +25,15 @@
 Patch1:  pam-0.99.7.0-redhat-modules.patch
 Patch2:  db-4.6.18-glibc.patch
 Patch4:  pam-0.99.8.1-dbpam.patch
+Patch5:  pam-1.0.1-autoreconf.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
+Patch22: pam-1.0.1-unix-prompts.patch
 Patch31: pam-0.99.3.0-cracklib-try-first-pass.patch
 Patch32: pam-0.99.3.0-tally-fail-close.patch
+Patch41: pam-1.0.1-namespace-create.patch
 
 %define _sbindir /sbin
 %define _moduledir /%{_lib}/security
@@ -102,11 +106,15 @@
 %patch2 -p1 -b .db4-glibc
 popd
 %patch4 -p1 -b .dbpam
+%patch5 -p1 -b .autoreconf
 %patch10 -p1 -b .screensaver
 %patch11 -p1 -b .restore-execcon
+%patch12 -p0 -b .env-params
 %patch21 -p1 -b .audit-failed
+%patch22 -p1 -b .prompts
 %patch31 -p1 -b .try-first-pass
 %patch32 -p1 -b .fail-close
+%patch41 -p1 -b .create
 
 autoreconf
 
@@ -376,6 +384,14 @@
 %doc doc/adg/*.txt doc/adg/html
 
 %changelog
+* Wed May 21 2008 Tomas Mraz <tmraz at redhat.com> 1.0.1-4
+- pam_namespace: allow safe creation of directories owned by user (#437116)
+- pam_unix: fix multiple error prompts on password change (#443872)
+
+* Tue May 20 2008 Tomas Mraz <tmraz at redhat.com> 1.0.1-3
+- pam_selinux: add env_params option which will be used by OpenSSH
+- fix build with new autoconf
+
 * Tue Apr 22 2008 Tomas Mraz <tmraz at redhat.com> 1.0.1-2
 - pam_selinux: restore execcon properly (#443667)
 




More information about the fedora-extras-commits mailing list