From a37d2c70466c6c3339ed6678ad9dec0f4571635c Mon Sep 17 00:00:00 2001 From: Tomáš Mráz Date: May 21 2008 08:08:39 +0000 Subject: - pam_namespace: allow safe creation of directories owned by user (#437116) - pam_unix: fix multiple error prompts on password change (#443872) --- 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