diff --git a/pam-1.0.1-namespace-create.patch b/pam-1.0.1-namespace-create.patch
new file mode 100644
index 0000000..7b06d07
--- /dev/null
+++ b/pam-1.0.1-namespace-create.patch
@@ -0,0 +1,679 @@
+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 /etc/security/namespace.init
+- 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.
+
+
+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 /etc/security/namespace.init 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.
+
+
+
diff --git a/pam-1.0.1-unix-prompts.patch b/pam-1.0.1-unix-prompts.patch
new file mode 100644
index 0000000..28fdf0b
--- /dev/null
+++ b/pam-1.0.1-unix-prompts.patch
@@ -0,0 +1,31 @@
+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 */
+ }
+ }
+ /*
diff --git a/pam.spec b/pam.spec
index 131a4a1..5674a62 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: 3%{?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
@@ -30,8 +30,10 @@ 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
@@ -109,8 +111,10 @@ popd
%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
@@ -380,6 +384,10 @@ fi
%doc doc/adg/*.txt doc/adg/html
%changelog
+* Wed May 21 2008 Tomas Mraz 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 1.0.1-3
- pam_selinux: add env_params option which will be used by OpenSSH
- fix build with new autoconf