- pam_namespace: allow safe creation of directories owned by user (#437116)
- pam_unix: fix multiple error prompts on password change (#443872)
This commit is contained in:
parent
3be955e71c
commit
a37d2c7046
679
pam-1.0.1-namespace-create.patch
Normal file
679
pam-1.0.1-namespace-create.patch
Normal file
@ -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 <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>
|
31
pam-1.0.1-unix-prompts.patch
Normal file
31
pam-1.0.1-unix-prompts.patch
Normal file
@ -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 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
10
pam.spec
10
pam.spec
@ -5,7 +5,7 @@
|
|||||||
Summary: A security tool which provides authentication for applications
|
Summary: A security tool which provides authentication for applications
|
||||||
Name: pam
|
Name: pam
|
||||||
Version: 1.0.1
|
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
|
# 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+,
|
# as the BSD license allows that anyway. pam_timestamp and pam_console modules are GPLv2+,
|
||||||
# pam_rhosts_auth module is BSD with advertising
|
# 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
|
Patch11: pam-1.0.1-selinux-restore-execcon.patch
|
||||||
Patch12: pam-1.0.0-selinux-env-params.patch
|
Patch12: pam-1.0.0-selinux-env-params.patch
|
||||||
Patch21: pam-0.99.10.0-unix-audit-failed.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
|
Patch31: pam-0.99.3.0-cracklib-try-first-pass.patch
|
||||||
Patch32: pam-0.99.3.0-tally-fail-close.patch
|
Patch32: pam-0.99.3.0-tally-fail-close.patch
|
||||||
|
Patch41: pam-1.0.1-namespace-create.patch
|
||||||
|
|
||||||
%define _sbindir /sbin
|
%define _sbindir /sbin
|
||||||
%define _moduledir /%{_lib}/security
|
%define _moduledir /%{_lib}/security
|
||||||
@ -109,8 +111,10 @@ popd
|
|||||||
%patch11 -p1 -b .restore-execcon
|
%patch11 -p1 -b .restore-execcon
|
||||||
%patch12 -p0 -b .env-params
|
%patch12 -p0 -b .env-params
|
||||||
%patch21 -p1 -b .audit-failed
|
%patch21 -p1 -b .audit-failed
|
||||||
|
%patch22 -p1 -b .prompts
|
||||||
%patch31 -p1 -b .try-first-pass
|
%patch31 -p1 -b .try-first-pass
|
||||||
%patch32 -p1 -b .fail-close
|
%patch32 -p1 -b .fail-close
|
||||||
|
%patch41 -p1 -b .create
|
||||||
|
|
||||||
autoreconf
|
autoreconf
|
||||||
|
|
||||||
@ -380,6 +384,10 @@ fi
|
|||||||
%doc doc/adg/*.txt doc/adg/html
|
%doc doc/adg/*.txt doc/adg/html
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Wed May 21 2008 Tomas Mraz <tmraz@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@redhat.com> 1.0.1-3
|
* Tue May 20 2008 Tomas Mraz <tmraz@redhat.com> 1.0.1-3
|
||||||
- pam_selinux: add env_params option which will be used by OpenSSH
|
- pam_selinux: add env_params option which will be used by OpenSSH
|
||||||
- fix build with new autoconf
|
- fix build with new autoconf
|
||||||
|
Loading…
Reference in New Issue
Block a user