From 543e122a80e25e9597cff418b837e214114bad1f Mon Sep 17 00:00:00 2001 From: Stefan Schubert Date: Wed, 16 Feb 2022 11:51:35 +0100 Subject: pam_namespace: use vendor specific namespace.conf and namespace.init as fallback Use the vendor directory as fallback for a distribution provided default config and scripts if there is no configuration in /etc. pam_namespace.c: Take care about the fallback configuration in vendor directory. pam_namespace.h: Define vendor specific files and directories. pam_namespace.8.xml: Add description for vendor directories and files. namespace.conf.5.xml: Add description for vendor directories and files. --- modules/pam_namespace/namespace.conf.5.xml | 18 +++- modules/pam_namespace/pam_namespace.8.xml | 30 +++++++ modules/pam_namespace/pam_namespace.c | 128 +++++++++++++++++++++++++---- modules/pam_namespace/pam_namespace.h | 6 ++ 4 files changed, 167 insertions(+), 15 deletions(-) (limited to 'modules/pam_namespace') diff --git a/modules/pam_namespace/namespace.conf.5.xml b/modules/pam_namespace/namespace.conf.5.xml index a94b49e2..67f8c043 100644 --- a/modules/pam_namespace/namespace.conf.5.xml +++ b/modules/pam_namespace/namespace.conf.5.xml @@ -30,13 +30,29 @@ directory path and the instance directory path as its arguments. - + The /etc/security/namespace.conf file specifies which directories are polyinstantiated, how they are polyinstantiated, how instance directories would be named, and any users for whom polyinstantiation would not be performed. + + The /etc/security/namespace.conf file + ( or %vendordir%/security/namespace.conf if it does + not exist) specifies which directories are polyinstantiated, how they are + polyinstantiated, how instance directories would be named, and any users + for whom polyinstantiation would not be performed. + Then individual *.conf files from the + /etc/security/namespace.d/ and + %vendordir%/security/namespace.d directories are taken too. + If /etc/security/namespace.d/@filename@.conf exists, then + %vendordir%/security/namespace.d/@filename@.conf will not be used. + All namespace.d/*.conf files are sorted by their + @filename@.conf in lexicographic order regardless of which + of the directories they reside in. + + When someone logs in, the file namespace.conf is scanned. Comments are marked by # characters. diff --git a/modules/pam_namespace/pam_namespace.8.xml b/modules/pam_namespace/pam_namespace.8.xml index 57c44c4b..ddaa00b4 100644 --- a/modules/pam_namespace/pam_namespace.8.xml +++ b/modules/pam_namespace/pam_namespace.8.xml @@ -74,6 +74,12 @@ and the user name as its arguments. + + If /etc/security/namespace.init does not exist, + %vendordir%/security/namespace.init is the + alternative to be used for it. + + The pam_namespace module disassociates the session namespace from the parent namespace. Any mounts/unmounts performed in the parent @@ -313,6 +319,14 @@ + + %vendordir%/security/namespace.conf + + Default configuration file if + /etc/security/namespace.conf does not exist. + + + /etc/security/namespace.d @@ -320,12 +334,28 @@ + + %vendordir%/security/namespace.d + + Directory for additional vendor specific configuration files. + + + /etc/security/namespace.init Init script for instance directories + + + %vendordir%/security/namespace.init + + Vendor init script for instance directories if + /etc/security/namespace.init does not exist. + + + diff --git a/modules/pam_namespace/pam_namespace.c b/modules/pam_namespace/pam_namespace.c index 4d4188d0..017d5019 100644 --- a/modules/pam_namespace/pam_namespace.c +++ b/modules/pam_namespace/pam_namespace.c @@ -39,6 +39,94 @@ #include "pam_namespace.h" #include "argv_parse.h" +/* --- evaluting all files in VENDORDIR/security/namespace.d and /etc/security/namespace.d --- */ +static const char *base_name(const char *path) +{ + const char *base = strrchr(path, '/'); + return base ? base+1 : path; +} + +static int +compare_filename(const void *a, const void *b) +{ + return strcmp(base_name(* (char * const *) a), + base_name(* (char * const *) b)); +} + +/* Evaluating a list of files which have to be parsed in the right order: + * + * - If etc/security/namespace.d/@filename@.conf exists, then + * %vendordir%/security/namespace.d/@filename@.conf should not be used. + * - All files in both namespace.d directories are sorted by their @filename@.conf in + * lexicographic order regardless of which of the directories they reside in. */ +static char **read_namespace_dir(struct instance_data *idata) +{ + glob_t globbuf; + size_t i=0; + int glob_rv = glob(NAMESPACE_D_GLOB, GLOB_ERR | GLOB_NOSORT, NULL, &globbuf); + char **file_list; + size_t file_list_size = glob_rv == 0 ? globbuf.gl_pathc : 0; + +#ifdef VENDOR_NAMESPACE_D_GLOB + glob_t globbuf_vendor; + int glob_rv_vendor = glob(VENDOR_NAMESPACE_D_GLOB, GLOB_ERR | GLOB_NOSORT, NULL, &globbuf_vendor); + if (glob_rv_vendor == 0) + file_list_size += globbuf_vendor.gl_pathc; +#endif + file_list = malloc((file_list_size + 1) * sizeof(char*)); + if (file_list == NULL) { + pam_syslog(idata->pamh, LOG_ERR, "Cannot allocate memory for file list: %m"); +#ifdef VENDOR_NAMESPACE_D_GLOB + if (glob_rv_vendor == 0) + globfree(&globbuf_vendor); +#endif + if (glob_rv == 0) + globfree(&globbuf); + return NULL; + } + + if (glob_rv == 0) { + for (i = 0; i < globbuf.gl_pathc; i++) { + file_list[i] = strdup(globbuf.gl_pathv[i]); + if (file_list[i] == NULL) { + pam_syslog(idata->pamh, LOG_ERR, "strdup failed: %m"); + break; + } + } + } +#ifdef VENDOR_NAMESPACE_D_GLOB + if (glob_rv_vendor == 0) { + for (size_t j = 0; j < globbuf_vendor.gl_pathc; j++) { + if (glob_rv == 0 && globbuf.gl_pathc > 0) { + int double_found = 0; + for (size_t k = 0; k < globbuf.gl_pathc; k++) { + if (strcmp(base_name(globbuf.gl_pathv[k]), + base_name(globbuf_vendor.gl_pathv[j])) == 0) { + double_found = 1; + break; + } + } + if (double_found) + continue; + } + file_list[i] = strdup(globbuf_vendor.gl_pathv[j]); + if (file_list[i] == NULL) { + pam_syslog(idata->pamh, LOG_ERR, "strdup failed: %m"); + break; + } + i++; + } + globfree(&globbuf_vendor); + } +#endif + file_list[i] = NULL; + qsort(file_list, i, sizeof(char *), compare_filename); + if (glob_rv == 0) + globfree(&globbuf); + + return file_list; +} + /* * Adds an entry for a polyinstantiated directory to the linked list of * polyinstantiated directories. It is called from process_line() while @@ -624,8 +712,6 @@ static int parse_config_file(struct instance_data *idata) char *line; int retval; size_t len = 0; - glob_t globbuf; - const char *oldlocale; size_t n; /* @@ -664,13 +750,16 @@ static int parse_config_file(struct instance_data *idata) * process_line to process each line. */ - memset(&globbuf, '\0', sizeof(globbuf)); - oldlocale = setlocale(LC_COLLATE, "C"); - glob(NAMESPACE_D_GLOB, 0, NULL, &globbuf); - if (oldlocale != NULL) - setlocale(LC_COLLATE, oldlocale); - confname = PAM_NAMESPACE_CONFIG; +#ifdef VENDOR_PAM_NAMESPACE_CONFIG + /* Check whether PAM_NAMESPACE_CONFIG file is available. + * If it does not exist, fall back to VENDOR_PAM_NAMESPACE_CONFIG file. */ + struct stat buffer; + if (stat(confname, &buffer) != 0 && errno == ENOENT) { + confname = VENDOR_PAM_NAMESPACE_CONFIG; + } +#endif + char **filename_list = read_namespace_dir(idata); n = 0; for (;;) { if (idata->flags & PAMNS_DEBUG) @@ -680,7 +769,6 @@ static int parse_config_file(struct instance_data *idata) if (fil == NULL) { pam_syslog(idata->pamh, LOG_ERR, "Error opening config file %s", confname); - globfree(&globbuf); free(rhome); free(home); return PAM_SERVICE_ERR; @@ -698,7 +786,6 @@ static int parse_config_file(struct instance_data *idata) "Error processing conf file %s line %s", confname, line); fclose(fil); free(line); - globfree(&globbuf); free(rhome); free(home); return PAM_SERVICE_ERR; @@ -707,14 +794,18 @@ static int parse_config_file(struct instance_data *idata) fclose(fil); free(line); - if (n >= globbuf.gl_pathc) + if (filename_list == NULL || filename_list[n] == NULL) break; - confname = globbuf.gl_pathv[n]; - n++; + confname = filename_list[n++]; + } + + if (filename_list != NULL) { + for (size_t i = 0; filename_list[i] != NULL; i++) + free(filename_list[i]); + free(filename_list); } - globfree(&globbuf); free(rhome); free(home); @@ -1254,6 +1345,15 @@ static int inst_init(const struct polydir_s *polyptr, const char *ipath, int status; const char *init_script = NAMESPACE_INIT_SCRIPT; +#ifdef VENDOR_NAMESPACE_INIT_SCRIPT + /* Check whether NAMESPACE_INIT_SCRIPT file is available. + * If it does not exist, fall back to VENDOR_NAMESPACE_INIT_SCRIPT file. */ + struct stat buffer; + if (stat(init_script, &buffer) != 0 && errno == ENOENT) { + init_script = VENDOR_NAMESPACE_INIT_SCRIPT; + } +#endif + memset(&newsa, '\0', sizeof(newsa)); newsa.sa_handler = SIG_DFL; if (sigaction(SIGCHLD, &newsa, &oldsa) == -1) { diff --git a/modules/pam_namespace/pam_namespace.h b/modules/pam_namespace/pam_namespace.h index 169bd59f..0b974ea7 100644 --- a/modules/pam_namespace/pam_namespace.h +++ b/modules/pam_namespace/pam_namespace.h @@ -94,6 +94,12 @@ #define NAMESPACE_INIT_SCRIPT (SCONFIGDIR "/namespace.init") #define NAMESPACE_D_DIR (SCONFIGDIR "/namespace.d/") #define NAMESPACE_D_GLOB (SCONFIGDIR "/namespace.d/*.conf") +#ifdef VENDOR_SCONFIGDIR +#define VENDOR_NAMESPACE_INIT_SCRIPT (VENDOR_SCONFIGDIR "/namespace.init") +#define VENDOR_PAM_NAMESPACE_CONFIG (VENDOR_SCONFIGDIR "/namespace.conf") +#define VENDOR_NAMESPACE_D_DIR (VENDOR_SCONFIGDIR "/namespace.d/") +#define VENDOR_NAMESPACE_D_GLOB (VENDOR_SCONFIGDIR "/namespace.d/*.conf") +#endif /* module flags */ #define PAMNS_DEBUG 0x00000100 /* Running in debug mode */ -- cgit v1.2.3