diff options
Diffstat (limited to 'modules/pam_namespace/pam_namespace.c')
-rw-r--r-- | modules/pam_namespace/pam_namespace.c | 409 |
1 files changed, 212 insertions, 197 deletions
diff --git a/modules/pam_namespace/pam_namespace.c b/modules/pam_namespace/pam_namespace.c index 4a99184..e0d5e30 100644 --- a/modules/pam_namespace/pam_namespace.c +++ b/modules/pam_namespace/pam_namespace.c @@ -64,6 +64,7 @@ static void del_polydir(struct polydir_s *poly) if (poly) { free(poly->uid); free(poly->init_script); + free(poly->mount_opts); free(poly); } } @@ -76,7 +77,7 @@ static void del_polydir_list(struct polydir_s *polydirs_ptr) struct polydir_s *dptr = polydirs_ptr; while (dptr) { - struct polydir_s *tptr = dptr; + struct polydir_s *tptr = dptr; dptr = dptr->next; del_polydir(tptr); } @@ -163,9 +164,9 @@ static int parse_create_params(char *params, struct polydir_s *poly) poly->group = (gid_t)ULONG_MAX; if (*params != '=') - return 0; + return 0; params++; - + next = strchr(params, ','); if (next != NULL) { *next = '\0'; @@ -182,7 +183,7 @@ static int parse_create_params(char *params, struct polydir_s *poly) params = next; if (params == NULL) - return 0; + return 0; next = strchr(params, ','); if (next != NULL) { *next = '\0'; @@ -200,22 +201,22 @@ static int parse_create_params(char *params, struct polydir_s *poly) if (params == NULL || *params == '\0') { if (pwd != NULL) poly->group = pwd->pw_gid; - return 0; + return 0; } grp = getgrnam(params); if (grp == NULL) - return -1; + return -1; poly->group = grp->gr_gid; - + return 0; } static int parse_iscript_params(char *params, struct polydir_s *poly) { if (*params != '=') - return 0; + return 0; params++; - + if (*params != '\0') { if (*params != '/') { /* path is relative to NAMESPACE_D_DIR */ if (asprintf(&poly->init_script, "%s%s", NAMESPACE_D_DIR, params) == -1) @@ -235,11 +236,11 @@ static int parse_method(char *method, struct polydir_s *poly, enum polymethod pm; char *sptr = NULL; static const char *method_names[] = { "user", "context", "level", "tmpdir", - "tmpfs", NULL }; + "tmpfs", NULL }; static const char *flag_names[] = { "create", "noinit", "iscript", - "shared", NULL }; + "shared", "mntopts", NULL }; static const unsigned int flag_values[] = { POLYDIR_CREATE, POLYDIR_NOINIT, - POLYDIR_ISCRIPT, POLYDIR_SHARED }; + POLYDIR_ISCRIPT, POLYDIR_SHARED, POLYDIR_MNTOPTS }; int i; char *flag; @@ -247,41 +248,55 @@ static int parse_method(char *method, struct polydir_s *poly, pm = NONE; for (i = 0; method_names[i]; i++) { - if (strcmp(method, method_names[i]) == 0) { - pm = i + 1; /* 0 = NONE */ - } + if (strcmp(method, method_names[i]) == 0) { + pm = i + 1; /* 0 = NONE */ + } } if (pm == NONE) { pam_syslog(idata->pamh, LOG_NOTICE, "Unknown method"); return -1; } - + poly->method = pm; - + while ((flag=strtok_r(NULL, ":", &sptr)) != NULL) { - for (i = 0; flag_names[i]; i++) { - int namelen = strlen(flag_names[i]); - - if (strncmp(flag, flag_names[i], namelen) == 0) { - poly->flags |= flag_values[i]; - switch (flag_values[i]) { - case POLYDIR_CREATE: - if (parse_create_params(flag+namelen, poly) != 0) { + for (i = 0; flag_names[i]; i++) { + int namelen = strlen(flag_names[i]); + + if (strncmp(flag, flag_names[i], namelen) == 0) { + poly->flags |= flag_values[i]; + switch (flag_values[i]) { + case POLYDIR_CREATE: + if (parse_create_params(flag+namelen, poly) != 0) { pam_syslog(idata->pamh, LOG_CRIT, "Invalid create parameters"); - return -1; - } - break; + return -1; + } + break; - case POLYDIR_ISCRIPT: - if (parse_iscript_params(flag+namelen, poly) != 0) { + case POLYDIR_ISCRIPT: + if (parse_iscript_params(flag+namelen, poly) != 0) { pam_syslog(idata->pamh, LOG_CRIT, "Memory allocation error"); - return -1; - }; - break; - } - } - } + return -1; + }; + break; + + case POLYDIR_MNTOPTS: + if (flag[namelen] != '=') + break; + if (poly->method != TMPFS) { + pam_syslog(idata->pamh, LOG_WARNING, "Mount options applicable only to tmpfs method"); + break; + } + free(poly->mount_opts); /* if duplicate mntopts specified */ + if ((poly->mount_opts = strdup(flag+namelen+1)) == NULL) { + pam_syslog(idata->pamh, LOG_CRIT, "Memory allocation error"); + return -1; + } + break; + } + } + } } return 0; @@ -337,7 +352,7 @@ static int process_line(char *line, const char *home, const char *rhome, poly = calloc(1, sizeof(*poly)); if (poly == NULL) - goto erralloc; + goto erralloc; /* * Initialize and scan the five strings from the line from the @@ -383,12 +398,12 @@ static int process_line(char *line, const char *home, const char *rhome, dir = NULL; goto erralloc; } - + if ((dir=expand_variables(dir, var_names, var_values)) == NULL) { instance_prefix = NULL; goto erralloc; } - + if ((instance_prefix=expand_variables(instance_prefix, var_names, var_values)) == NULL) { goto erralloc; @@ -409,12 +424,12 @@ static int process_line(char *line, const char *home, const char *rhome, if (len > 0 && rdir[len-1] == '/') { rdir[len-1] = '\0'; } - + if (dir[0] == '\0' || rdir[0] == '\0') { - pam_syslog(idata->pamh, LOG_NOTICE, "Invalid polydir"); - goto skipping; + pam_syslog(idata->pamh, LOG_NOTICE, "Invalid polydir"); + goto skipping; } - + /* * Populate polyinstantiated directory structure with appropriate * pathnames and the method with which to polyinstantiate. @@ -430,14 +445,14 @@ static int process_line(char *line, const char *home, const char *rhome, strcpy(poly->instance_prefix, instance_prefix); if (parse_method(method, poly, idata) != 0) { - goto skipping; + goto skipping; } if (poly->method == TMPDIR) { - if (sizeof(poly->instance_prefix) - strlen(poly->instance_prefix) < 7) { - pam_syslog(idata->pamh, LOG_NOTICE, "Pathnames too long"); - goto skipping; - } + if (sizeof(poly->instance_prefix) - strlen(poly->instance_prefix) < 7) { + pam_syslog(idata->pamh, LOG_NOTICE, "Pathnames too long"); + goto skipping; + } strcat(poly->instance_prefix, "XXXXXX"); } @@ -463,7 +478,7 @@ static int process_line(char *line, const char *home, const char *rhome, uid_t *uidptr; const char *ustr, *sstr; int count, i; - + if (*uids == '~') { poly->flags |= POLYDIR_EXCLUSIVE; uids++; @@ -488,8 +503,8 @@ static int process_line(char *line, const char *home, const char *rhome, pwd = pam_modutil_getpwnam(idata->pamh, ustr); if (pwd == NULL) { - pam_syslog(idata->pamh, LOG_ERR, "Unknown user %s in configuration", ustr); - poly->num_uids--; + pam_syslog(idata->pamh, LOG_ERR, "Unknown user %s in configuration", ustr); + poly->num_uids--; } else { *uidptr = pwd->pw_uid; uidptr++; @@ -508,7 +523,7 @@ static int process_line(char *line, const char *home, const char *rhome, erralloc: pam_syslog(idata->pamh, LOG_CRIT, "Memory allocation error"); - + skipping: if (idata->flags & PAMNS_IGN_CONFIG_ERR) retval = 0; @@ -554,9 +569,9 @@ static int parse_config_file(struct instance_data *idata) return PAM_SESSION_ERR; } if ((home=strdup(cpwd->pw_dir)) == NULL) { - pam_syslog(idata->pamh, LOG_CRIT, - "Memory allocation error"); - return PAM_SESSION_ERR; + pam_syslog(idata->pamh, LOG_CRIT, + "Memory allocation error"); + return PAM_SESSION_ERR; } cpwd = pam_modutil_getpwnam(idata->pamh, idata->ruser); @@ -568,10 +583,10 @@ static int parse_config_file(struct instance_data *idata) } if ((rhome=strdup(cpwd->pw_dir)) == NULL) { - pam_syslog(idata->pamh, LOG_CRIT, - "Memory allocation error"); - free(home); - return PAM_SESSION_ERR; + pam_syslog(idata->pamh, LOG_CRIT, + "Memory allocation error"); + free(home); + return PAM_SESSION_ERR; } /* @@ -594,7 +609,7 @@ static int parse_config_file(struct instance_data *idata) fil = fopen(confname, "r"); if (fil == NULL) { pam_syslog(idata->pamh, LOG_ERR, "Error opening config file %s", - confname); + confname); globfree(&globbuf); free(rhome); free(home); @@ -625,14 +640,14 @@ static int parse_config_file(struct instance_data *idata) if (n >= globbuf.gl_pathc) break; - confname = globbuf.gl_pathv[n]; + confname = globbuf.gl_pathv[n]; n++; } - + globfree(&globbuf); free(rhome); free(home); - + /* All done...just some debug stuff */ if (idata->flags & PAMNS_DEBUG) { struct polydir_s *dptr = idata->polydirs_ptr; @@ -640,7 +655,7 @@ static int parse_config_file(struct instance_data *idata) uid_t i; pam_syslog(idata->pamh, LOG_DEBUG, - dptr?"Configured poly dirs:":"No configured poly dirs"); + dptr?"Configured poly dirs:":"No configured poly dirs"); while (dptr) { pam_syslog(idata->pamh, LOG_DEBUG, "dir='%s' iprefix='%s' meth=%d", dptr->dir, dptr->instance_prefix, dptr->method); @@ -667,7 +682,7 @@ static int ns_override(struct polydir_s *polyptr, struct instance_data *idata, unsigned int i; if (idata->flags & PAMNS_DEBUG) - pam_syslog(idata->pamh, LOG_DEBUG, + pam_syslog(idata->pamh, LOG_DEBUG, "Checking for ns override in dir %s for uid %d", polyptr->dir, uid); @@ -745,7 +760,7 @@ static int form_context(const struct polydir_s *polyptr, rc = getexeccon(&scon); } if (rc < 0 || scon == NULL) { - pam_syslog(idata->pamh, LOG_ERR, + pam_syslog(idata->pamh, LOG_ERR, "Error getting exec context, %m"); return PAM_SESSION_ERR; } @@ -870,17 +885,17 @@ static int poly_name(const struct polydir_s *polyptr, char **i_name, } pm = USER; } - + switch (pm) { case USER: if (asprintf(i_name, "%s", idata->user) < 0) { *i_name = NULL; goto fail; - } - break; + } + break; #ifdef WITH_SELINUX - case LEVEL: + case LEVEL: case CONTEXT: if (selinux_trans_to_raw_context(*i_context, &rawcon) < 0) { pam_syslog(idata->pamh, LOG_ERR, "Error translating directory context"); @@ -890,27 +905,27 @@ static int poly_name(const struct polydir_s *polyptr, char **i_name, if (asprintf(i_name, "%s", rawcon) < 0) { *i_name = NULL; goto fail; - } + } } else { if (asprintf(i_name, "%s_%s", rawcon, idata->user) < 0) { *i_name = NULL; goto fail; - } + } } - break; + break; #endif /* WITH_SELINUX */ case TMPDIR: case TMPFS: if ((*i_name=strdup("")) == NULL) - goto fail; + goto fail; return PAM_SUCCESS; - default: - if (idata->flags & PAMNS_DEBUG) - pam_syslog(idata->pamh, LOG_ERR, "Unknown method"); - goto fail; + default: + if (idata->flags & PAMNS_DEBUG) + pam_syslog(idata->pamh, LOG_ERR, "Unknown method"); + goto fail; } if (idata->flags & PAMNS_DEBUG) @@ -919,24 +934,24 @@ static int poly_name(const struct polydir_s *polyptr, char **i_name, if ((idata->flags & PAMNS_GEN_HASH) || strlen(*i_name) > NAMESPACE_MAX_DIR_LEN) { hash = md5hash(*i_name, idata); if (hash == NULL) { - goto fail; + goto fail; } if (idata->flags & PAMNS_GEN_HASH) { - free(*i_name); + free(*i_name); *i_name = hash; hash = NULL; } else { - char *newname; - if (asprintf(&newname, "%.*s_%s", NAMESPACE_MAX_DIR_LEN-1-(int)strlen(hash), - *i_name, hash) < 0) { - goto fail; - } - free(*i_name); - *i_name = newname; + char *newname; + if (asprintf(&newname, "%.*s_%s", NAMESPACE_MAX_DIR_LEN-1-(int)strlen(hash), + *i_name, hash) < 0) { + goto fail; + } + free(*i_name); + *i_name = newname; } } rc = PAM_SUCCESS; - + fail: free(hash); #ifdef WITH_SELINUX @@ -959,34 +974,34 @@ 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, @@ -996,14 +1011,14 @@ static int protect_mount(int dfd, const char *path, struct instance_data *idata) 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, int always, +static int protect_dir(const char *path, mode_t mode, int do_mkdir, struct instance_data *idata) { char *p = strdup(path); @@ -1019,15 +1034,15 @@ static int protect_dir(const char *path, mode_t mode, int do_mkdir, int always, if (p == NULL) { goto error; } - + if (*dir == '/') { dfd = open("/", flags); if (dfd == -1) { goto error; } - dir++; /* assume / is safe */ + dir++; /* assume / is safe */ } - + while ((d=strchr(dir, '/')) != NULL) { *d = '\0'; dfd_next = openat(dfd, dir, flags); @@ -1042,8 +1057,8 @@ static int protect_dir(const char *path, mode_t mode, int do_mkdir, int always, if (fstat(dfd, &st) != 0) { goto error; } - - if (flags & O_NOFOLLOW) { + + if (flags & O_NOFOLLOW) { /* we are inside user-owned dir - protect */ if (protect_mount(dfd, p, idata) == -1) goto error; @@ -1058,14 +1073,14 @@ static int protect_dir(const char *path, mode_t mode, int do_mkdir, int always, } 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; @@ -1082,7 +1097,7 @@ static int protect_dir(const char *path, mode_t mode, int do_mkdir, int always, } } - if ((flags & O_NOFOLLOW) || always) { + if (flags & O_NOFOLLOW) { /* we are inside user-owned dir - protect */ if (protect_mount(rv, p, idata) == -1) { save_errno = errno; @@ -1124,7 +1139,7 @@ static int check_inst_parent(char *ipath, struct instance_data *idata) if (trailing_slash) *trailing_slash = '\0'; - dfd = protect_dir(inst_parent, 0, 1, 0, idata); + dfd = protect_dir(inst_parent, 0, 1, idata); if (dfd == -1 || fstat(dfd, &instpbuf) < 0) { pam_syslog(idata->pamh, LOG_ERR, @@ -1251,7 +1266,7 @@ static int create_polydir(struct polydir_s *polyptr, pam_syslog(idata->pamh, LOG_DEBUG, "Polydir %s context: %s", dir, (char *)dircon); if (setfscreatecon(dircon) != 0) - pam_syslog(idata->pamh, LOG_NOTICE, + pam_syslog(idata->pamh, LOG_NOTICE, "Error setting context for directory %s: %m", dir); freecon(dircon); } @@ -1259,7 +1274,7 @@ static int create_polydir(struct polydir_s *polyptr, } #endif - rc = protect_dir(dir, mode, 1, idata->flags & PAMNS_MOUNT_PRIVATE, idata); + rc = protect_dir(dir, mode, 1, idata); if (rc == -1) { pam_syslog(idata->pamh, LOG_ERR, "Error creating directory %s: %m", dir); @@ -1279,15 +1294,15 @@ static int create_polydir(struct polydir_s *polyptr, pam_syslog(idata->pamh, LOG_DEBUG, "Created polydir %s", dir); if (polyptr->mode != (mode_t)ULONG_MAX) { - /* explicit mode requested */ - if (fchmod(rc, mode) != 0) { + /* explicit mode requested */ + if (fchmod(rc, mode) != 0) { pam_syslog(idata->pamh, LOG_ERR, - "Error changing mode of directory %s: %m", dir); + "Error changing mode of directory %s: %m", dir); close(rc); umount(dir); /* undo the eventual protection bind mount */ - rmdir(dir); - return PAM_SESSION_ERR; - } + rmdir(dir); + return PAM_SESSION_ERR; + } } if (polyptr->owner != (uid_t)ULONG_MAX) @@ -1345,14 +1360,14 @@ static int create_instance(struct polydir_s *polyptr, char *ipath, struct stat * * attributes to match that of the original directory that is being * polyinstantiated. */ - + if (polyptr->method == TMPDIR) { - if (mkdtemp(polyptr->instance_prefix) == NULL) { + if (mkdtemp(polyptr->instance_prefix) == NULL) { pam_syslog(idata->pamh, LOG_ERR, "Error creating temporary instance %s, %m", polyptr->instance_prefix); polyptr->method = NONE; /* do not clean up! */ return PAM_SESSION_ERR; - } + } /* copy the actual directory name to ipath */ strcpy(ipath, polyptr->instance_prefix); } else if (mkdir(ipath, S_IRUSR) < 0) { @@ -1447,26 +1462,26 @@ static int ns_setup(struct polydir_s *polyptr, pam_syslog(idata->pamh, LOG_DEBUG, "Set namespace for directory %s", polyptr->dir); - retval = protect_dir(polyptr->dir, 0, 0, idata->flags & PAMNS_MOUNT_PRIVATE, idata); + retval = protect_dir(polyptr->dir, 0, 0, idata); 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) { - if ((polyptr->flags & POLYDIR_CREATE) && + if ((polyptr->flags & POLYDIR_CREATE) && create_polydir(polyptr, idata) != PAM_SUCCESS) return PAM_SESSION_ERR; } else { - close(retval); + close(retval); } - + if (polyptr->method == TMPFS) { - if (mount("tmpfs", polyptr->dir, "tmpfs", 0, NULL) < 0) { + if (mount("tmpfs", polyptr->dir, "tmpfs", 0, polyptr->mount_opts) < 0) { pam_syslog(idata->pamh, LOG_ERR, "Error mounting tmpfs on %s, %m", - polyptr->dir); + polyptr->dir); return PAM_SESSION_ERR; } @@ -1481,7 +1496,7 @@ static int ns_setup(struct polydir_s *polyptr, polyptr->dir); return PAM_SESSION_ERR; } - + /* * Obtain the name of instance pathname based on the * polyinstantiation method and instance context returned by @@ -1495,8 +1510,8 @@ static int ns_setup(struct polydir_s *polyptr, #endif if (retval != PAM_SUCCESS) { - if (retval != PAM_IGNORE) - pam_syslog(idata->pamh, LOG_ERR, "Error getting instance name"); + if (retval != PAM_IGNORE) + pam_syslog(idata->pamh, LOG_ERR, "Error getting instance name"); goto cleanup; } else { #ifdef WITH_SELINUX @@ -1526,30 +1541,14 @@ static int ns_setup(struct polydir_s *polyptr, #endif if (retval == PAM_IGNORE) { - newdir = 0; - retval = PAM_SUCCESS; + newdir = 0; + retval = PAM_SUCCESS; } if (retval != PAM_SUCCESS) { goto error_out; } - if (idata->flags & PAMNS_MOUNT_PRIVATE) { - /* - * Make the polyinstantiated dir private mount. This depends - * on making the dir a mount point in the protect_dir call. - */ - if (mount(polyptr->dir, polyptr->dir, NULL, MS_PRIVATE|MS_REC, NULL) < 0) { - pam_syslog(idata->pamh, LOG_ERR, "Error making %s a private mount, %m", - polyptr->dir); - goto error_out; - } - if (idata->flags & PAMNS_DEBUG) - pam_syslog(idata->pamh, LOG_DEBUG, - "Polyinstantiated directory %s made as private mount", polyptr->dir); - - } - /* * Bind mount instance directory on top of the polyinstantiated * directory to provide an instance of polyinstantiated directory @@ -1647,7 +1646,7 @@ static int cleanup_tmpdirs(struct instance_data *idata) } if (!WIFEXITED(status) || WIFSIGNALED(status) > 0) { pam_syslog(idata->pamh, LOG_ERR, - "Error removing %s", pptr->instance_prefix); + "Error removing %s", pptr->instance_prefix); } } else if (pid < 0) { pam_syslog(idata->pamh, LOG_ERR, @@ -1686,14 +1685,14 @@ static int setup_namespace(struct instance_data *idata, enum unmnt_op unmnt) */ for (pptr = idata->polydirs_ptr; pptr; pptr = pptr->next) { if (ns_override(pptr, idata, idata->uid)) { - if (unmnt == NO_UNMNT || ns_override(pptr, idata, idata->ruid)) { - if (idata->flags & PAMNS_DEBUG) - pam_syslog(idata->pamh, LOG_DEBUG, + if (unmnt == NO_UNMNT || ns_override(pptr, idata, idata->ruid)) { + if (idata->flags & PAMNS_DEBUG) + pam_syslog(idata->pamh, LOG_DEBUG, "Overriding poly for user %d for dir %s", idata->uid, pptr->dir); } else { - if (idata->flags & PAMNS_DEBUG) - pam_syslog(idata->pamh, LOG_DEBUG, + if (idata->flags & PAMNS_DEBUG) + pam_syslog(idata->pamh, LOG_DEBUG, "Need unmount ns for user %d for dir %s", idata->ruid, pptr->dir); need_poly = 1; @@ -1720,8 +1719,22 @@ static int setup_namespace(struct instance_data *idata, enum unmnt_op unmnt) "Unable to unshare from parent namespace, %m"); return PAM_SESSION_ERR; } + if (idata->flags & PAMNS_MOUNT_PRIVATE) { + /* + * Remount / as SLAVE so that nothing mounted in the namespace + * shows up in the parent + */ + if (mount("/", "/", NULL, MS_SLAVE | MS_REC , NULL) < 0) { + pam_syslog(idata->pamh, LOG_ERR, + "Failed to mark / as a slave mount point, %m"); + return PAM_SESSION_ERR; + } + if (idata->flags & PAMNS_DEBUG) + pam_syslog(idata->pamh, LOG_DEBUG, + "The / mount point was marked as slave"); + } } else { - del_polydir_list(idata->polydirs_ptr); + del_polydir_list(idata->polydirs_ptr); return PAM_SUCCESS; } @@ -1768,12 +1781,12 @@ static int setup_namespace(struct instance_data *idata, enum unmnt_op unmnt) * are available from */ strcpy(poly_parent, pptr->rdir); - fptr = strchr(poly_parent, '/'); - cptr = strrchr(poly_parent, '/'); - if (fptr && cptr && (fptr == cptr)) - strcpy(poly_parent, "/"); - else if (cptr) - *cptr = '\0'; + fptr = strchr(poly_parent, '/'); + cptr = strrchr(poly_parent, '/'); + if (fptr && cptr && (fptr == cptr)) + strcpy(poly_parent, "/"); + else if (cptr) + *cptr = '\0'; if (chdir(poly_parent) < 0) { pam_syslog(idata->pamh, LOG_ERR, "Can't chdir to %s, %m", poly_parent); @@ -1781,12 +1794,12 @@ static int setup_namespace(struct instance_data *idata, enum unmnt_op unmnt) } if (umount(pptr->rdir) < 0) { - int saved_errno = errno; - pam_syslog(idata->pamh, LOG_ERR, "Unmount of %s failed, %m", - pptr->rdir); - if (saved_errno != EINVAL) { - retval = PAM_SESSION_ERR; - goto out; + int saved_errno = errno; + pam_syslog(idata->pamh, LOG_ERR, "Unmount of %s failed, %m", + pptr->rdir); + if (saved_errno != EINVAL) { + retval = PAM_SESSION_ERR; + goto out; } } else if (idata->flags & PAMNS_DEBUG) pam_syslog(idata->pamh, LOG_DEBUG, "Umount succeeded %s", @@ -1803,20 +1816,20 @@ static int setup_namespace(struct instance_data *idata, enum unmnt_op unmnt) } out: if (retval != PAM_SUCCESS) { - cleanup_tmpdirs(idata); - unprotect_dirs(idata->protect_dirs); + 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) { + cleanup_protect_data) != PAM_SUCCESS) { pam_syslog(idata->pamh, LOG_ERR, "Unable to set namespace protect data"); - cleanup_tmpdirs(idata); - unprotect_dirs(idata->protect_dirs); + cleanup_tmpdirs(idata); + 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) { + 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; + cleanup_tmpdirs(idata); + pam_set_data(idata->pamh, NAMESPACE_PROTECT_DATA, NULL, NULL); + idata->protect_dirs = NULL; return PAM_SYSTEM_ERR; } return retval; @@ -1943,7 +1956,7 @@ static int get_user_data(struct instance_data *idata) int retval; char *user_name; struct passwd *pwd; - /* + /* * Lookup user and fill struct items */ retval = pam_get_item(idata->pamh, PAM_USER, (void*) &user_name ); @@ -1969,10 +1982,10 @@ static int get_user_data(struct instance_data *idata) /* Fill in RUSER too */ retval = pam_get_item(idata->pamh, PAM_RUSER, (void*) &user_name ); if ( user_name != NULL && retval == PAM_SUCCESS && user_name[0] != '\0' ) { - strncat(idata->ruser, user_name, sizeof(idata->ruser) - 1); - pwd = pam_modutil_getpwnam(idata->pamh, user_name); + strncat(idata->ruser, user_name, sizeof(idata->ruser) - 1); + pwd = pam_modutil_getpwnam(idata->pamh, user_name); } else { - pwd = pam_modutil_getpwuid(idata->pamh, getuid()); + pwd = pam_modutil_getpwuid(idata->pamh, getuid()); } if (!pwd) { pam_syslog(idata->pamh, LOG_ERR, "user unknown '%s'", user_name); @@ -2005,7 +2018,7 @@ PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED, #ifdef WITH_SELINUX if (is_selinux_enabled()) idata.flags |= PAMNS_SELINUX_ENABLED; - if (ctxt_based_inst_needed()) + if (ctxt_based_inst_needed()) idata.flags |= PAMNS_CTXT_BASED_INST; #endif @@ -2036,7 +2049,7 @@ PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED, unmnt = UNMNT_ONLY; if (strcmp(argv[i], "require_selinux") == 0) { if (!(idata.flags & PAMNS_SELINUX_ENABLED)) { - pam_syslog(idata.pamh, LOG_ERR, + pam_syslog(idata.pamh, LOG_ERR, "selinux_required option given and selinux is disabled"); return PAM_SESSION_ERR; } @@ -2047,7 +2060,7 @@ PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED, retval = get_user_data(&idata); if (retval != PAM_SUCCESS) - return retval; + return retval; if (root_shared()) { idata.flags |= PAMNS_MOUNT_PRIVATE; @@ -2110,24 +2123,26 @@ PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags UNUSED, idata.flags |= PAMNS_DEBUG; if (strcmp(argv[i], "ignore_config_error") == 0) idata.flags |= PAMNS_IGN_CONFIG_ERR; - if (strcmp(argv[i], "no_unmount_on_close") == 0) - idata.flags |= PAMNS_NO_UNMOUNT_ON_CLOSE; + if (strcmp(argv[i], "unmount_on_close") == 0) + idata.flags |= PAMNS_UNMOUNT_ON_CLOSE; } if (idata.flags & PAMNS_DEBUG) pam_syslog(idata.pamh, LOG_DEBUG, "close_session - start"); /* - * For certain trusted programs such as newrole, open session - * is called from a child process while the parent perfoms - * close session and pam end functions. For these commands - * pam_close_session should not perform the unmount of the - * polyinstantiatied directory because it will result in - * undoing of parents polyinstantiatiaion. These commands - * will invoke pam_namespace with the "no_unmount_on_close" - * argument. + * Normally the unmount is implicitly done when the last + * process in the private namespace exits. + * If it is ensured that there are no child processes left in + * the private namespace by other means and if there are + * multiple sessions opened and closed sequentially by the + * same process, the "unmount_on_close" option might be + * used to unmount the polydirs explicitly. */ - if (idata.flags & PAMNS_NO_UNMOUNT_ON_CLOSE) { + if (!(idata.flags & PAMNS_UNMOUNT_ON_CLOSE)) { + pam_set_data(idata.pamh, NAMESPACE_POLYDIR_DATA, NULL, NULL); + pam_set_data(idata.pamh, NAMESPACE_PROTECT_DATA, NULL, NULL); + if (idata.flags & PAMNS_DEBUG) pam_syslog(idata.pamh, LOG_DEBUG, "close_session - sucessful"); return PAM_SUCCESS; @@ -2135,13 +2150,13 @@ PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags UNUSED, retval = get_user_data(&idata); if (retval != PAM_SUCCESS) - return retval; + return retval; retval = pam_get_data(idata.pamh, NAMESPACE_POLYDIR_DATA, (const void **)&polyptr); if (retval != PAM_SUCCESS || polyptr == NULL) - /* nothing to reset */ - return PAM_SUCCESS; - + /* nothing to reset */ + return PAM_SUCCESS; + idata.polydirs_ptr = polyptr; if (idata.flags & PAMNS_DEBUG) @@ -2160,7 +2175,7 @@ PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags UNUSED, pam_set_data(idata.pamh, NAMESPACE_POLYDIR_DATA, NULL, NULL); pam_set_data(idata.pamh, NAMESPACE_PROTECT_DATA, NULL, NULL); - + return PAM_SUCCESS; } |