1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272 |
- /******************************************************************************
- * A module for Linux-PAM that will set the default namespace after
- * establishing a session via PAM.
- *
- * (C) Copyright IBM Corporation 2005
- * (C) Copyright Red Hat, Inc. 2006, 2008
- * All Rights Reserved.
- *
- * Written by: Janak Desai <janak@us.ibm.com>
- * With Revisions by: Steve Grubb <sgrubb@redhat.com>
- * Contributions by: Xavier Toth <txtoth@gmail.com>,
- * Tomas Mraz <tmraz@redhat.com>
- * Derived from a namespace setup patch by Chad Sellers <cdselle@tycho.nsa.gov>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * on the rights to use, copy, modify, merge, publish, distribute, sub
- * license, and/or sell copies of the Software, and to permit persons to whom
- * the Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
- #define _ATFILE_SOURCE
- #include "pam_cc_compat.h"
- #include "pam_inline.h"
- #include "pam_namespace.h"
- #include "argv_parse.h"
- /*
- * Adds an entry for a polyinstantiated directory to the linked list of
- * polyinstantiated directories. It is called from process_line() while
- * parsing the namespace configuration file.
- */
- static void add_polydir_entry(struct instance_data *idata,
- struct polydir_s *ent)
- {
- /* Now attach to linked list */
- ent->next = NULL;
- if (idata->polydirs_ptr == NULL)
- idata->polydirs_ptr = ent;
- else {
- struct polydir_s *tail;
- tail = idata->polydirs_ptr;
- while (tail->next)
- tail = tail->next;
- tail->next = ent;
- }
- }
- static void del_polydir(struct polydir_s *poly)
- {
- if (poly) {
- free(poly->uid);
- free(poly->init_script);
- free(poly->mount_opts);
- free(poly);
- }
- }
- /*
- * Deletes all the entries in the linked list.
- */
- static void del_polydir_list(struct polydir_s *polydirs_ptr)
- {
- struct polydir_s *dptr = polydirs_ptr;
- while (dptr) {
- struct polydir_s *tptr = dptr;
- dptr = dptr->next;
- del_polydir(tptr);
- }
- }
- 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;
- char *dst;
- char *expanded;
- char c;
- size_t dstlen = 0;
- while (*src) {
- if (*src == '$') {
- int i;
- for (i = 0; var_names[i]; i++) {
- int namelen = strlen(var_names[i]);
- if (strncmp(var_names[i], src+1, namelen) == 0) {
- dstlen += strlen(var_values[i]) - 1; /* $ */
- src += namelen;
- break;
- }
- }
- }
- ++dstlen;
- ++src;
- }
- if ((dst=expanded=malloc(dstlen + 1)) == NULL)
- return NULL;
- src = orig;
- while ((c=*src) != '\0') {
- if (c == '$') {
- int i;
- for (i = 0; var_names[i]; i++) {
- int namelen = strlen(var_names[i]);
- if (strncmp(var_names[i], src+1, namelen) == 0) {
- dst = stpcpy(dst, var_values[i]);
- --dst;
- c = *dst; /* replace $ */
- src += namelen;
- break;
- }
- }
- }
- *dst = c;
- ++dst;
- ++src;
- }
- *dst = '\0';
- return expanded;
- }
- static int parse_create_params(char *params, struct polydir_s *poly)
- {
- char *next;
- struct passwd *pwd = NULL;
- struct group *grp;
- poly->mode = (mode_t)ULONG_MAX;
- poly->owner = (uid_t)ULONG_MAX;
- poly->group = (gid_t)ULONG_MAX;
- if (*params != '=')
- return 0;
- params++;
- next = strchr(params, ',');
- if (next != NULL) {
- *next = '\0';
- next++;
- }
- if (*params != '\0') {
- errno = 0;
- poly->mode = (mode_t)strtoul(params, NULL, 0);
- if (errno != 0) {
- poly->mode = (mode_t)ULONG_MAX;
- }
- }
- params = next;
- if (params == NULL)
- return 0;
- next = strchr(params, ',');
- if (next != NULL) {
- *next = '\0';
- next++;
- }
- 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);
- if (grp == NULL)
- return -1;
- poly->group = grp->gr_gid;
- return 0;
- }
- static int parse_iscript_params(char *params, struct polydir_s *poly)
- {
- if (*params != '=')
- 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)
- return -1;
- } else {
- poly->init_script = strdup(params);
- }
- if (poly->init_script == NULL)
- return -1;
- }
- return 0;
- }
- struct mntflag {
- const char *name;
- size_t len;
- unsigned long flag;
- };
- #define LITERAL_AND_LEN(x) x, sizeof(x) - 1
- static const struct mntflag mntflags[] = {
- { LITERAL_AND_LEN("noexec"), MS_NOEXEC },
- { LITERAL_AND_LEN("nosuid"), MS_NOSUID },
- { LITERAL_AND_LEN("nodev"), MS_NODEV }
- };
- static int filter_mntopts(const char *opts, char **filtered,
- unsigned long *mountflags)
- {
- size_t origlen = strlen(opts);
- const char *end;
- char *dest;
- dest = *filtered = NULL;
- *mountflags = 0;
- if (origlen == 0)
- return 0;
- do {
- size_t len;
- unsigned int i;
- end = strchr(opts, ',');
- if (end == NULL) {
- len = strlen(opts);
- } else {
- len = end - opts;
- }
- for (i = 0; i < PAM_ARRAY_SIZE(mntflags); i++) {
- if (mntflags[i].len != len)
- continue;
- if (memcmp(mntflags[i].name, opts, len) == 0) {
- *mountflags |= mntflags[i].flag;
- opts = end;
- break;
- }
- }
- if (opts != end) {
- if (dest != NULL) {
- *dest = ',';
- ++dest;
- } else {
- dest = *filtered = calloc(1, origlen + 1);
- if (dest == NULL)
- return -1;
- }
- memcpy(dest, opts, len);
- dest += len;
- }
- opts = end + 1;
- } while (end != NULL);
- return 0;
- }
- static int parse_method(char *method, struct polydir_s *poly,
- struct instance_data *idata)
- {
- enum polymethod pm;
- char *sptr = NULL;
- static const char *method_names[] = { "user", "context", "level", "tmpdir",
- "tmpfs", NULL };
- static const char *flag_names[] = { "create", "noinit", "iscript",
- "shared", "mntopts", NULL };
- static const unsigned int flag_values[] = { POLYDIR_CREATE, POLYDIR_NOINIT,
- POLYDIR_ISCRIPT, POLYDIR_SHARED, POLYDIR_MNTOPTS };
- int i;
- char *flag;
- method = strtok_r(method, ":", &sptr);
- pm = NONE;
- for (i = 0; method_names[i]; i++) {
- 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) {
- pam_syslog(idata->pamh, LOG_CRIT, "Invalid create parameters");
- return -1;
- }
- break;
- case POLYDIR_ISCRIPT:
- if (parse_iscript_params(flag+namelen, poly) != 0) {
- pam_syslog(idata->pamh, LOG_CRIT, "Memory allocation error");
- 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 */
- poly->mount_opts = NULL;
- if (filter_mntopts(flag+namelen+1, &poly->mount_opts, &poly->mount_flags) != 0) {
- pam_syslog(idata->pamh, LOG_CRIT, "Memory allocation error");
- return -1;
- }
- break;
- }
- }
- }
- }
- return 0;
- }
- /*
- * Called from parse_config_file, this function processes a single line
- * of the namespace configuration file. It skips over comments and incomplete
- * or malformed lines. It processes a valid line with information on
- * polyinstantiating a directory by populating appropriate fields of a
- * polyinstatiated directory structure and then calling add_polydir_entry to
- * add that entry to the linked list of polyinstantiated directories.
- */
- static int process_line(char *line, const char *home, const char *rhome,
- struct instance_data *idata)
- {
- char *dir = NULL, *instance_prefix = NULL, *rdir = NULL;
- char *method, *uids;
- char *tptr;
- struct polydir_s *poly;
- int retval = 0;
- char **config_options = NULL;
- static const char *var_names[] = {"HOME", "USER", NULL};
- const char *var_values[] = {home, idata->user};
- const char *rvar_values[] = {rhome, idata->ruser};
- int len;
- /*
- * skip the leading white space
- */
- while (*line && isspace(*line))
- line++;
- /*
- * Rip off the comments
- */
- tptr = strchr(line,'#');
- if (tptr)
- *tptr = '\0';
- /*
- * Rip off the newline char
- */
- tptr = strchr(line,'\n');
- if (tptr)
- *tptr = '\0';
- /*
- * Anything left ?
- */
- if (line[0] == 0)
- return 0;
- poly = calloc(1, sizeof(*poly));
- if (poly == NULL)
- goto erralloc;
- /*
- * Initialize and scan the five strings from the line from the
- * namespace configuration file.
- */
- retval = argv_parse(line, NULL, &config_options);
- if (retval != 0) {
- goto erralloc;
- }
- dir = config_options[0];
- if (dir == NULL) {
- pam_syslog(idata->pamh, LOG_NOTICE, "Invalid line missing polydir");
- goto skipping;
- }
- instance_prefix = config_options[1];
- if (instance_prefix == NULL) {
- pam_syslog(idata->pamh, LOG_NOTICE, "Invalid line missing instance_prefix");
- instance_prefix = NULL;
- goto skipping;
- }
- method = config_options[2];
- if (method == NULL) {
- pam_syslog(idata->pamh, LOG_NOTICE, "Invalid line missing method");
- instance_prefix = NULL;
- dir = NULL;
- goto skipping;
- }
- /*
- * Only the uids field is allowed to be blank, to indicate no
- * override users for polyinstantiation of that directory. If
- * any of the other fields are blank, the line is incomplete so
- * skip it.
- */
- uids = config_options[3];
- /*
- * Expand $HOME and $USER in poly dir and instance dir prefix
- */
- if ((rdir=expand_variables(dir, var_names, rvar_values)) == NULL) {
- instance_prefix = NULL;
- 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;
- }
- if (idata->flags & PAMNS_DEBUG) {
- pam_syslog(idata->pamh, LOG_DEBUG, "Expanded polydir: '%s'", dir);
- pam_syslog(idata->pamh, LOG_DEBUG, "Expanded ruser polydir: '%s'", rdir);
- pam_syslog(idata->pamh, LOG_DEBUG, "Expanded instance prefix: '%s'", instance_prefix);
- }
- len = strlen(dir);
- if (len > 0 && dir[len-1] == '/') {
- dir[len-1] = '\0';
- }
- len = strlen(rdir);
- 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;
- }
- /*
- * Populate polyinstantiated directory structure with appropriate
- * pathnames and the method with which to polyinstantiate.
- */
- if (strlen(dir) >= sizeof(poly->dir)
- || strlen(rdir) >= sizeof(poly->rdir)
- || strlen(instance_prefix) >= sizeof(poly->instance_prefix)) {
- pam_syslog(idata->pamh, LOG_NOTICE, "Pathnames too long");
- goto skipping;
- }
- strcpy(poly->dir, dir);
- strcpy(poly->rdir, rdir);
- strcpy(poly->instance_prefix, instance_prefix);
- if (parse_method(method, poly, idata) != 0) {
- 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;
- }
- strcat(poly->instance_prefix, "XXXXXX");
- }
- /*
- * Ensure that all pathnames are absolute path names.
- */
- if ((poly->dir[0] != '/') || (poly->method != TMPFS && poly->instance_prefix[0] != '/')) {
- pam_syslog(idata->pamh, LOG_NOTICE, "Pathnames must start with '/'");
- goto skipping;
- }
- if (strstr(dir, "..") || strstr(poly->instance_prefix, "..")) {
- pam_syslog(idata->pamh, LOG_NOTICE, "Pathnames must not contain '..'");
- goto skipping;
- }
- /*
- * If the line in namespace.conf for a directory to polyinstantiate
- * contains a list of override users (users for whom polyinstantiation
- * is not performed), read the user ids, convert names into uids, and
- * add to polyinstantiated directory structure.
- */
- if (uids) {
- uid_t *uidptr;
- const char *ustr, *sstr;
- int count, i;
- if (*uids == '~') {
- poly->flags |= POLYDIR_EXCLUSIVE;
- uids++;
- }
- for (count = 0, ustr = sstr = uids; sstr; ustr = sstr + 1, count++)
- sstr = strchr(ustr, ',');
- poly->num_uids = count;
- poly->uid = (uid_t *) malloc(count * sizeof (uid_t));
- uidptr = poly->uid;
- if (uidptr == NULL) {
- goto erralloc;
- }
- ustr = uids;
- for (i = 0; i < count; i++) {
- struct passwd *pwd;
- tptr = strchr(ustr, ',');
- if (tptr)
- *tptr = '\0';
- 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--;
- } else {
- *uidptr = pwd->pw_uid;
- uidptr++;
- }
- ustr = tptr + 1;
- }
- }
- /*
- * Add polyinstantiated directory structure to the linked list
- * of all polyinstantiated directory structures.
- */
- add_polydir_entry(idata, poly);
- goto out;
- erralloc:
- pam_syslog(idata->pamh, LOG_CRIT, "Memory allocation error");
- skipping:
- if (idata->flags & PAMNS_IGN_CONFIG_ERR)
- retval = 0;
- else
- retval = PAM_SERVICE_ERR;
- del_polydir(poly);
- out:
- free(rdir);
- free(dir);
- free(instance_prefix);
- argv_free(config_options);
- return retval;
- }
- /*
- * Parses /etc/security/namespace.conf file to build a linked list of
- * polyinstantiated directory structures of type polydir_s. Each entry
- * in the linked list contains information needed to polyinstantiate
- * one directory.
- */
- static int parse_config_file(struct instance_data *idata)
- {
- FILE *fil;
- char *home, *rhome;
- const char *confname;
- struct passwd *cpwd;
- char *line;
- int retval;
- size_t len = 0;
- glob_t globbuf;
- const char *oldlocale;
- size_t n;
- /*
- * Extract the user's home directory to resolve $HOME entries
- * in the namespace configuration file.
- */
- cpwd = pam_modutil_getpwnam(idata->pamh, idata->user);
- if (!cpwd) {
- pam_syslog(idata->pamh, LOG_ERR,
- "Error getting home dir for '%s'", idata->user);
- return PAM_SESSION_ERR;
- }
- if ((home=strdup(cpwd->pw_dir)) == NULL) {
- pam_syslog(idata->pamh, LOG_CRIT,
- "Memory allocation error");
- return PAM_SESSION_ERR;
- }
- cpwd = pam_modutil_getpwnam(idata->pamh, idata->ruser);
- if (!cpwd) {
- pam_syslog(idata->pamh, LOG_ERR,
- "Error getting home dir for '%s'", idata->ruser);
- free(home);
- return PAM_SESSION_ERR;
- }
- if ((rhome=strdup(cpwd->pw_dir)) == NULL) {
- pam_syslog(idata->pamh, LOG_CRIT,
- "Memory allocation error");
- free(home);
- return PAM_SESSION_ERR;
- }
- /*
- * Open configuration file, read one line at a time and call
- * 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;
- n = 0;
- for (;;) {
- if (idata->flags & PAMNS_DEBUG)
- pam_syslog(idata->pamh, LOG_DEBUG, "Parsing config file %s",
- confname);
- fil = fopen(confname, "r");
- 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;
- }
- /* Use unlocked IO */
- __fsetlocking(fil, FSETLOCKING_BYCALLER);
- line = NULL;
- /* loop reading the file */
- while (getline(&line, &len, fil) > 0) {
- retval = process_line(line, home, rhome, idata);
- if (retval) {
- pam_syslog(idata->pamh, LOG_ERR,
- "Error processing conf file %s line %s", confname, line);
- fclose(fil);
- free(line);
- globfree(&globbuf);
- free(rhome);
- free(home);
- return PAM_SERVICE_ERR;
- }
- }
- fclose(fil);
- free(line);
- if (n >= globbuf.gl_pathc)
- break;
- 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;
- uid_t *iptr;
- uid_t i;
- pam_syslog(idata->pamh, LOG_DEBUG,
- 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);
- for (i = 0, iptr = dptr->uid; i < dptr->num_uids; i++, iptr++)
- pam_syslog(idata->pamh, LOG_DEBUG, "override user %d ", *iptr);
- dptr = dptr->next;
- }
- }
- return PAM_SUCCESS;
- }
- /*
- * This function returns true if a given uid is present in the polyinstantiated
- * directory's list of override uids. If the uid is one of the override
- * uids for the polyinstantiated directory, polyinstantiation is not
- * performed for that user for that directory.
- * If exclusive is set the returned values are opposite.
- */
- static int ns_override(struct polydir_s *polyptr, struct instance_data *idata,
- uid_t uid)
- {
- unsigned int i;
- if (idata->flags & PAMNS_DEBUG)
- pam_syslog(idata->pamh, LOG_DEBUG,
- "Checking for ns override in dir %s for uid %d",
- polyptr->dir, uid);
- for (i = 0; i < polyptr->num_uids; i++) {
- if (uid == polyptr->uid[i]) {
- return !(polyptr->flags & POLYDIR_EXCLUSIVE);
- }
- }
- return !!(polyptr->flags & POLYDIR_EXCLUSIVE);
- }
- /*
- * md5hash generates a hash of the passed in instance directory name.
- */
- static char *md5hash(const char *instname, struct instance_data *idata)
- {
- int i;
- char *md5inst = NULL;
- char *to;
- unsigned char inst_digest[MD5_DIGEST_LENGTH];
- /*
- * Create MD5 hashes for instance pathname.
- */
- MD5((const unsigned char *)instname, strlen(instname), inst_digest);
- if ((md5inst = malloc(MD5_DIGEST_LENGTH * 2 + 1)) == NULL) {
- pam_syslog(idata->pamh, LOG_CRIT, "Unable to allocate buffer");
- return NULL;
- }
- to = md5inst;
- for (i = 0; i < MD5_DIGEST_LENGTH; i++) {
- snprintf(to, 3, "%02x", (unsigned int)inst_digest[i]);
- to += 2;
- }
- return md5inst;
- }
- #ifdef WITH_SELINUX
- static int form_context(const struct polydir_s *polyptr,
- char **i_context, char **origcon,
- struct instance_data *idata)
- {
- int rc = PAM_SUCCESS;
- char *scon = NULL;
- security_class_t tclass;
- /*
- * Get the security context of the directory to polyinstantiate.
- */
- rc = getfilecon(polyptr->dir, origcon);
- if (rc < 0 || *origcon == NULL) {
- pam_syslog(idata->pamh, LOG_ERR,
- "Error getting poly dir context, %m");
- return PAM_SESSION_ERR;
- }
- if (polyptr->method == USER) return PAM_SUCCESS;
- if (idata->flags & PAMNS_USE_CURRENT_CONTEXT) {
- rc = getcon(&scon);
- } else if (idata->flags & PAMNS_USE_DEFAULT_CONTEXT) {
- char *seuser = NULL, *level = NULL;
- if ((rc=getseuserbyname(idata->user, &seuser, &level)) == 0) {
- rc = get_default_context_with_level(seuser, level, NULL, &scon);
- free(seuser);
- free(level);
- }
- } else {
- rc = getexeccon(&scon);
- }
- if (rc < 0 || scon == NULL) {
- pam_syslog(idata->pamh, LOG_ERR,
- "Error getting exec context, %m");
- return PAM_SESSION_ERR;
- }
- /*
- * If polyinstantiating based on security context, get current
- * process security context, get security class for directories,
- * and ask the policy to provide security context of the
- * polyinstantiated instance directory.
- */
- if (polyptr->method == CONTEXT) {
- tclass = string_to_security_class("dir");
- if (tclass == 0) {
- pam_syslog(idata->pamh, LOG_ERR,
- "Error getting dir security class");
- freecon(scon);
- return PAM_SESSION_ERR;
- }
- if (security_compute_member(scon, *origcon, tclass,
- i_context) < 0) {
- pam_syslog(idata->pamh, LOG_ERR,
- "Error computing poly dir member context");
- freecon(scon);
- return PAM_SESSION_ERR;
- } else if (idata->flags & PAMNS_DEBUG)
- pam_syslog(idata->pamh, LOG_DEBUG,
- "member context returned by policy %s", *i_context);
- freecon(scon);
- return PAM_SUCCESS;
- }
- /*
- * If polyinstantiating based on security level, get current
- * process security context, get security class for directories,
- * and change the directories MLS Level to match process.
- */
- if (polyptr->method == LEVEL) {
- context_t scontext = NULL;
- context_t fcontext = NULL;
- rc = PAM_SESSION_ERR;
- scontext = context_new(scon);
- if (! scontext) {
- pam_syslog(idata->pamh, LOG_CRIT, "out of memory");
- goto fail;
- }
- fcontext = context_new(*origcon);
- if (! fcontext) {
- pam_syslog(idata->pamh, LOG_CRIT, "out of memory");
- goto fail;
- }
- if (context_range_set(fcontext, context_range_get(scontext)) != 0) {
- pam_syslog(idata->pamh, LOG_ERR, "Unable to set MLS Component of context");
- goto fail;
- }
- *i_context=strdup(context_str(fcontext));
- if (! *i_context) {
- pam_syslog(idata->pamh, LOG_CRIT, "out of memory");
- goto fail;
- }
- rc = PAM_SUCCESS;
- fail:
- context_free(scontext);
- context_free(fcontext);
- freecon(scon);
- return rc;
- }
- /* Should never get here */
- return PAM_SUCCESS;
- }
- #endif
- /*
- * poly_name returns the name of the polyinstantiated instance directory
- * based on the method used for polyinstantiation (user, context or level)
- * In addition, the function also returns the security contexts of the
- * original directory to polyinstantiate and the polyinstantiated instance
- * directory.
- */
- #ifdef WITH_SELINUX
- static int poly_name(const struct polydir_s *polyptr, char **i_name,
- char **i_context, char **origcon,
- struct instance_data *idata)
- #else
- static int poly_name(const struct polydir_s *polyptr, char **i_name,
- struct instance_data *idata)
- #endif
- {
- int rc;
- char *hash = NULL;
- enum polymethod pm;
- #ifdef WITH_SELINUX
- char *rawcon = NULL;
- #endif
- *i_name = NULL;
- #ifdef WITH_SELINUX
- *i_context = NULL;
- *origcon = NULL;
- if ((idata->flags & PAMNS_SELINUX_ENABLED) &&
- (rc=form_context(polyptr, i_context, origcon, idata)) != PAM_SUCCESS) {
- return rc;
- }
- #endif
- rc = PAM_SESSION_ERR;
- /*
- * Set the name of the polyinstantiated instance dir based on the
- * polyinstantiation method.
- */
- pm = polyptr->method;
- if (pm == LEVEL || pm == CONTEXT)
- #ifdef WITH_SELINUX
- if (!(idata->flags & PAMNS_CTXT_BASED_INST)) {
- #else
- {
- pam_syslog(idata->pamh, LOG_NOTICE,
- "Context and level methods not available, using user method");
- #endif
- if (polyptr->flags & POLYDIR_SHARED) {
- rc = PAM_IGNORE;
- goto fail;
- }
- pm = USER;
- }
- switch (pm) {
- case USER:
- if (asprintf(i_name, "%s", idata->user) < 0) {
- *i_name = NULL;
- goto fail;
- }
- break;
- #ifdef WITH_SELINUX
- case LEVEL:
- case CONTEXT:
- if (selinux_trans_to_raw_context(*i_context, &rawcon) < 0) {
- pam_syslog(idata->pamh, LOG_ERR, "Error translating directory context");
- goto fail;
- }
- if (polyptr->flags & POLYDIR_SHARED) {
- 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;
- #endif /* WITH_SELINUX */
- case TMPDIR:
- case TMPFS:
- if ((*i_name=strdup("")) == NULL)
- goto fail;
- return PAM_SUCCESS;
- default:
- if (idata->flags & PAMNS_DEBUG)
- pam_syslog(idata->pamh, LOG_ERR, "Unknown method");
- goto fail;
- }
- if (idata->flags & PAMNS_DEBUG)
- pam_syslog(idata->pamh, LOG_DEBUG, "poly_name %s", *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;
- }
- if (idata->flags & PAMNS_GEN_HASH) {
- 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;
- }
- }
- rc = PAM_SUCCESS;
- fail:
- free(hash);
- #ifdef WITH_SELINUX
- freecon(rawcon);
- #endif
- if (rc != PAM_SUCCESS) {
- #ifdef WITH_SELINUX
- freecon(*i_context);
- *i_context = NULL;
- freecon(*origcon);
- *origcon = NULL;
- #endif
- free(*i_name);
- *i_name = NULL;
- }
- 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 && dfd >= 0)
- 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
- * admin explicitly instructs to ignore the instance parent
- * mode by the "ignore_instance_parent_mode" argument).
- */
- inst_parent = (char *) malloc(strlen(ipath)+1);
- if (!inst_parent) {
- pam_syslog(idata->pamh, LOG_CRIT, "Error allocating pathname string");
- return PAM_SESSION_ERR;
- }
- strcpy(inst_parent, ipath);
- trailing_slash = strrchr(inst_parent, '/');
- if (trailing_slash)
- *trailing_slash = '\0';
- dfd = protect_dir(inst_parent, 0, 1, idata);
- 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)) || 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;
- }
- /*
- * 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.
- */
- static int inst_init(const struct polydir_s *polyptr, const char *ipath,
- struct instance_data *idata, int newdir)
- {
- pid_t rc, pid;
- struct sigaction newsa, oldsa;
- int status;
- const char *init_script = NAMESPACE_INIT_SCRIPT;
- memset(&newsa, '\0', sizeof(newsa));
- newsa.sa_handler = SIG_DFL;
- if (sigaction(SIGCHLD, &newsa, &oldsa) == -1) {
- pam_syslog(idata->pamh, LOG_ERR, "Cannot set signal value");
- return PAM_SESSION_ERR;
- }
- if ((polyptr->flags & POLYDIR_ISCRIPT) && polyptr->init_script)
- init_script = polyptr->init_script;
- if (access(init_script, F_OK) == 0) {
- if (access(init_script, X_OK) < 0) {
- if (idata->flags & PAMNS_DEBUG)
- pam_syslog(idata->pamh, LOG_ERR,
- "Namespace init script not executable");
- rc = PAM_SESSION_ERR;
- goto out;
- } else {
- pid = fork();
- if (pid == 0) {
- static char *envp[] = { NULL };
- #ifdef WITH_SELINUX
- if (idata->flags & PAMNS_SELINUX_ENABLED) {
- if (setexeccon(NULL) < 0)
- _exit(1);
- }
- #endif
- /* Pass maximum privs when we exec() */
- if (setuid(geteuid()) < 0) {
- /* ignore failures, they don't matter */
- }
- if (execle(init_script, init_script,
- polyptr->dir, ipath, newdir?"1":"0", idata->user, NULL, envp) < 0)
- _exit(1);
- } else if (pid > 0) {
- while (((rc = waitpid(pid, &status, 0)) == (pid_t)-1) &&
- (errno == EINTR));
- if (rc == (pid_t)-1) {
- pam_syslog(idata->pamh, LOG_ERR, "waitpid failed- %m");
- rc = PAM_SESSION_ERR;
- goto out;
- }
- if (!WIFEXITED(status) || WIFSIGNALED(status) > 0) {
- pam_syslog(idata->pamh, LOG_ERR,
- "Error initializing instance");
- rc = PAM_SESSION_ERR;
- goto out;
- }
- } else if (pid < 0) {
- pam_syslog(idata->pamh, LOG_ERR,
- "Cannot fork to run namespace init script, %m");
- rc = PAM_SESSION_ERR;
- goto out;
- }
- }
- }
- rc = PAM_SUCCESS;
- out:
- (void) sigaction(SIGCHLD, &oldsa, NULL);
- return rc;
- }
- static int create_polydir(struct polydir_s *polyptr,
- struct instance_data *idata)
- {
- mode_t mode;
- int rc;
- #ifdef WITH_SELINUX
- char *dircon_raw, *oldcon_raw = NULL;
- struct selabel_handle *label_handle;
- #endif
- const char *dir = polyptr->dir;
- uid_t uid;
- gid_t gid;
- if (polyptr->mode != (mode_t)ULONG_MAX)
- mode = polyptr->mode;
- else
- mode = 0777;
- #ifdef WITH_SELINUX
- if (idata->flags & PAMNS_SELINUX_ENABLED) {
- getfscreatecon_raw(&oldcon_raw);
- label_handle = selabel_open(SELABEL_CTX_FILE, NULL, 0);
- if (!label_handle) {
- pam_syslog(idata->pamh, LOG_NOTICE,
- "Unable to initialize SELinux labeling handle: %m");
- } else {
- rc = selabel_lookup_raw(label_handle, &dircon_raw, dir, S_IFDIR);
- if (rc) {
- pam_syslog(idata->pamh, LOG_NOTICE,
- "Unable to get default context for directory %s, check your policy: %m", dir);
- } else {
- if (idata->flags & PAMNS_DEBUG)
- pam_syslog(idata->pamh, LOG_DEBUG,
- "Polydir %s context: %s", dir, dircon_raw);
- if (setfscreatecon_raw(dircon_raw) != 0)
- pam_syslog(idata->pamh, LOG_NOTICE,
- "Error setting context for directory %s: %m", dir);
- freecon(dircon_raw);
- }
- selabel_close(label_handle);
- }
- }
- #endif
- 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;
- }
- #ifdef WITH_SELINUX
- if (idata->flags & PAMNS_SELINUX_ENABLED) {
- if (setfscreatecon_raw(oldcon_raw) != 0)
- pam_syslog(idata->pamh, LOG_NOTICE,
- "Error resetting fs create context: %m");
- freecon(oldcon_raw);
- }
- #endif
- if (idata->flags & PAMNS_DEBUG)
- 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) {
- 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)
- 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;
- }
- /*
- * Create polyinstantiated instance directory (ipath).
- */
- #ifdef WITH_SELINUX
- static int create_instance(struct polydir_s *polyptr, char *ipath, struct stat *statbuf,
- const char *icontext, const char *ocontext,
- struct instance_data *idata)
- #else
- static int create_instance(struct polydir_s *polyptr, char *ipath, struct stat *statbuf,
- struct instance_data *idata)
- #endif
- {
- struct stat newstatbuf;
- int fd;
- /*
- * Check to make sure instance parent is valid.
- */
- if (check_inst_parent(ipath, idata))
- return PAM_SESSION_ERR;
- /*
- * Create instance directory and set its security context to the context
- * returned by the security policy. Set its mode and ownership
- * attributes to match that of the original directory that is being
- * polyinstantiated.
- */
- if (polyptr->method == TMPDIR) {
- 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) {
- if (errno == EEXIST)
- return PAM_IGNORE;
- else {
- pam_syslog(idata->pamh, LOG_ERR, "Error creating %s, %m",
- ipath);
- return PAM_SESSION_ERR;
- }
- }
- /* Open a descriptor to it to prevent races */
- fd = open(ipath, O_DIRECTORY | O_RDONLY);
- if (fd < 0) {
- pam_syslog(idata->pamh, LOG_ERR, "Error opening %s, %m", ipath);
- rmdir(ipath);
- return PAM_SESSION_ERR;
- }
- #ifdef WITH_SELINUX
- /* If SE Linux is disabled, no need to label it */
- if (idata->flags & PAMNS_SELINUX_ENABLED) {
- /* If method is USER, icontext is NULL */
- if (icontext) {
- if (fsetfilecon(fd, icontext) < 0) {
- pam_syslog(idata->pamh, LOG_ERR,
- "Error setting context of %s to %s", ipath, icontext);
- close(fd);
- rmdir(ipath);
- return PAM_SESSION_ERR;
- }
- } else {
- if (fsetfilecon(fd, ocontext) < 0) {
- pam_syslog(idata->pamh, LOG_ERR,
- "Error setting context of %s to %s", ipath, ocontext);
- close(fd);
- rmdir(ipath);
- return PAM_SESSION_ERR;
- }
- }
- }
- #endif
- if (fstat(fd, &newstatbuf) < 0) {
- pam_syslog(idata->pamh, LOG_ERR, "Error stating %s, %m",
- ipath);
- close(fd);
- rmdir(ipath);
- return PAM_SESSION_ERR;
- }
- if (newstatbuf.st_uid != statbuf->st_uid ||
- newstatbuf.st_gid != statbuf->st_gid) {
- if (fchown(fd, statbuf->st_uid, statbuf->st_gid) < 0) {
- pam_syslog(idata->pamh, LOG_ERR,
- "Error changing owner for %s, %m",
- ipath);
- close(fd);
- rmdir(ipath);
- return PAM_SESSION_ERR;
- }
- }
- if (fchmod(fd, statbuf->st_mode & 07777) < 0) {
- pam_syslog(idata->pamh, LOG_ERR, "Error changing mode for %s, %m",
- ipath);
- close(fd);
- rmdir(ipath);
- return PAM_SESSION_ERR;
- }
- close(fd);
- return PAM_SUCCESS;
- }
- /*
- * This function performs the namespace setup for a particular directory
- * 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;
- int newdir = 1;
- char *inst_dir = NULL;
- char *instname = NULL;
- struct stat statbuf;
- #ifdef WITH_SELINUX
- char *instcontext = NULL, *origcontext = NULL;
- #endif
- if (idata->flags & PAMNS_DEBUG)
- pam_syslog(idata->pamh, LOG_DEBUG,
- "Set namespace for directory %s", polyptr->dir);
- 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;
- }
- if (retval < 0) {
- if ((polyptr->flags & POLYDIR_CREATE) &&
- create_polydir(polyptr, idata) != PAM_SUCCESS)
- return PAM_SESSION_ERR;
- } else {
- close(retval);
- }
- if (polyptr->method == TMPFS) {
- if (mount("tmpfs", polyptr->dir, "tmpfs", polyptr->mount_flags, polyptr->mount_opts) < 0) {
- pam_syslog(idata->pamh, LOG_ERR, "Error mounting tmpfs on %s, %m",
- polyptr->dir);
- return PAM_SESSION_ERR;
- }
- 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
- * security policy.
- */
- #ifdef WITH_SELINUX
- retval = poly_name(polyptr, &instname, &instcontext,
- &origcontext, idata);
- #else
- retval = poly_name(polyptr, &instname, idata);
- #endif
- if (retval != PAM_SUCCESS) {
- if (retval != PAM_IGNORE)
- pam_syslog(idata->pamh, LOG_ERR, "Error getting instance name");
- goto cleanup;
- } else {
- #ifdef WITH_SELINUX
- if ((idata->flags & PAMNS_DEBUG) &&
- (idata->flags & PAMNS_SELINUX_ENABLED))
- pam_syslog(idata->pamh, LOG_DEBUG, "Inst ctxt %s Orig ctxt %s",
- instcontext, origcontext);
- #endif
- }
- if (asprintf(&inst_dir, "%s%s", polyptr->instance_prefix, instname) < 0)
- goto error_out;
- if (idata->flags & PAMNS_DEBUG)
- pam_syslog(idata->pamh, LOG_DEBUG, "instance_dir %s",
- inst_dir);
- /*
- * Create instance directory with appropriate security
- * contexts, owner, group and mode bits.
- */
- #ifdef WITH_SELINUX
- retval = create_instance(polyptr, inst_dir, &statbuf, instcontext,
- origcontext, idata);
- #else
- retval = create_instance(polyptr, inst_dir, &statbuf, idata);
- #endif
- if (retval == PAM_IGNORE) {
- newdir = 0;
- retval = PAM_SUCCESS;
- }
- if (retval != PAM_SUCCESS) {
- goto error_out;
- }
- /*
- * Bind mount instance directory on top of the polyinstantiated
- * directory to provide an instance of polyinstantiated directory
- * based on polyinstantiated method.
- */
- if (mount(inst_dir, polyptr->dir, NULL, MS_BIND, NULL) < 0) {
- pam_syslog(idata->pamh, LOG_ERR, "Error mounting %s on %s, %m",
- inst_dir, polyptr->dir);
- goto error_out;
- }
- if (!(polyptr->flags & POLYDIR_NOINIT))
- retval = inst_init(polyptr, inst_dir, idata, newdir);
- goto cleanup;
- /*
- * various error exit points. Free allocated memory and set return
- * value to indicate a pam session error.
- */
- error_out:
- retval = PAM_SESSION_ERR;
- cleanup:
- free(inst_dir);
- free(instname);
- #ifdef WITH_SELINUX
- freecon(instcontext);
- freecon(origcontext);
- #endif
- return retval;
- }
- /*
- * This function checks to see if the current working directory is
- * inside the directory passed in as the first argument.
- */
- static int cwd_in(char *dir, struct instance_data *idata)
- {
- int retval = 0;
- char cwd[PATH_MAX];
- if (getcwd(cwd, PATH_MAX) == NULL) {
- pam_syslog(idata->pamh, LOG_ERR, "Can't get current dir, %m");
- return -1;
- }
- if (strncmp(cwd, dir, strlen(dir)) == 0) {
- if (idata->flags & PAMNS_DEBUG)
- pam_syslog(idata->pamh, LOG_DEBUG, "cwd is inside %s", dir);
- retval = 1;
- } else {
- if (idata->flags & PAMNS_DEBUG)
- pam_syslog(idata->pamh, LOG_DEBUG, "cwd is outside %s", dir);
- }
- return retval;
- }
- static int cleanup_tmpdirs(struct instance_data *idata)
- {
- struct polydir_s *pptr;
- pid_t rc, pid;
- struct sigaction newsa, oldsa;
- int status;
- memset(&newsa, '\0', sizeof(newsa));
- newsa.sa_handler = SIG_DFL;
- if (sigaction(SIGCHLD, &newsa, &oldsa) == -1) {
- pam_syslog(idata->pamh, LOG_ERR, "Cannot set signal value");
- return PAM_SESSION_ERR;
- }
- for (pptr = idata->polydirs_ptr; pptr; pptr = pptr->next) {
- if (pptr->method == TMPDIR && access(pptr->instance_prefix, F_OK) == 0) {
- pid = fork();
- if (pid == 0) {
- static char *envp[] = { NULL };
- #ifdef WITH_SELINUX
- if (idata->flags & PAMNS_SELINUX_ENABLED) {
- if (setexeccon(NULL) < 0)
- _exit(1);
- }
- #endif
- if (execle("/bin/rm", "/bin/rm", "-rf", pptr->instance_prefix, NULL, envp) < 0)
- _exit(1);
- } else if (pid > 0) {
- while (((rc = waitpid(pid, &status, 0)) == (pid_t)-1) &&
- (errno == EINTR));
- if (rc == (pid_t)-1) {
- pam_syslog(idata->pamh, LOG_ERR, "waitpid failed: %m");
- rc = PAM_SESSION_ERR;
- goto out;
- }
- if (!WIFEXITED(status) || WIFSIGNALED(status) > 0) {
- pam_syslog(idata->pamh, LOG_ERR,
- "Error removing %s", pptr->instance_prefix);
- }
- } else if (pid < 0) {
- pam_syslog(idata->pamh, LOG_ERR,
- "Cannot fork to run namespace init script, %m");
- rc = PAM_SESSION_ERR;
- goto out;
- }
- }
- }
- rc = PAM_SUCCESS;
- out:
- sigaction(SIGCHLD, &oldsa, NULL);
- return rc;
- }
- /*
- * This function checks to see if polyinstantiation is needed for any
- * of the directories listed in the configuration file. If needed,
- * cycles through all polyinstantiated directory entries and calls
- * ns_setup to setup polyinstantiation for each one of them.
- */
- static int setup_namespace(struct instance_data *idata, enum unmnt_op unmnt)
- {
- int retval = 0, need_poly = 0, changing_dir = 0;
- char *cptr, *fptr, poly_parent[PATH_MAX];
- struct polydir_s *pptr;
- if (idata->flags & PAMNS_DEBUG)
- pam_syslog(idata->pamh, LOG_DEBUG, "Set up namespace for pid %d",
- getpid());
- /*
- * Cycle through all polyinstantiated directory entries to see if
- * polyinstantiation is needed at all.
- */
- 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,
- "Overriding poly for user %d for dir %s",
- idata->uid, pptr->dir);
- } else {
- 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;
- break;
- }
- continue;
- } else {
- if (idata->flags & PAMNS_DEBUG)
- pam_syslog(idata->pamh, LOG_DEBUG,
- "Need poly ns for user %d for dir %s",
- idata->uid, pptr->dir);
- need_poly = 1;
- break;
- }
- }
- /*
- * If polyinstantiation is needed, call the unshare system call to
- * disassociate from the parent namespace.
- */
- if (need_poly) {
- if (unshare(CLONE_NEWNS) < 0) {
- pam_syslog(idata->pamh, LOG_ERR,
- "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);
- return PAM_SUCCESS;
- }
- /*
- * Again cycle through all polyinstantiated directories, this time,
- * call ns_setup to setup polyinstantiation for a particular entry.
- */
- for (pptr = idata->polydirs_ptr; pptr; pptr = pptr->next) {
- enum unmnt_op dir_unmnt = unmnt;
- if (ns_override(pptr, idata, idata->ruid)) {
- dir_unmnt = NO_UNMNT;
- }
- if (ns_override(pptr, idata, idata->uid)) {
- if (dir_unmnt == NO_UNMNT) {
- continue;
- } else {
- dir_unmnt = UNMNT_ONLY;
- }
- }
- if (idata->flags & PAMNS_DEBUG)
- pam_syslog(idata->pamh, LOG_DEBUG,
- "Setting poly ns for user %d for dir %s",
- idata->uid, pptr->dir);
- if ((dir_unmnt == UNMNT_REMNT) || (dir_unmnt == UNMNT_ONLY)) {
- /*
- * Check to see if process current directory is in the
- * bind mounted instance_parent directory that we are trying to
- * umount
- */
- if ((changing_dir = cwd_in(pptr->rdir, idata)) < 0) {
- retval = PAM_SESSION_ERR;
- goto out;
- } else if (changing_dir) {
- if (idata->flags & PAMNS_DEBUG)
- pam_syslog(idata->pamh, LOG_DEBUG, "changing cwd");
- /*
- * Change current working directory to the parent of
- * the mount point, that is parent of the orig
- * directory where original contents of the polydir
- * 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';
- if (chdir(poly_parent) < 0) {
- pam_syslog(idata->pamh, LOG_ERR,
- "Can't chdir to %s, %m", poly_parent);
- }
- }
- 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;
- }
- } else if (idata->flags & PAMNS_DEBUG)
- pam_syslog(idata->pamh, LOG_DEBUG, "Umount succeeded %s",
- pptr->rdir);
- }
- if (dir_unmnt != UNMNT_ONLY) {
- retval = ns_setup(pptr, idata);
- if (retval == PAM_IGNORE)
- retval = PAM_SUCCESS;
- if (retval != PAM_SUCCESS)
- break;
- }
- }
- out:
- 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);
- 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;
- }
- /*
- * Orig namespace. This function is called from when closing a pam
- * session. If authorized, it unmounts instance directory.
- */
- static int orig_namespace(struct instance_data *idata)
- {
- struct polydir_s *pptr;
- if (idata->flags & PAMNS_DEBUG)
- pam_syslog(idata->pamh, LOG_DEBUG, "orig namespace for pid %d",
- getpid());
- /*
- * Cycle through all polyinstantiated directories from the namespace
- * configuration file to see if polyinstantiation was performed for
- * this user for each of the entry. If it was, try and unmount
- * appropriate polyinstantiated instance directories.
- */
- for (pptr = idata->polydirs_ptr; pptr; pptr = pptr->next) {
- if (ns_override(pptr, idata, idata->uid))
- continue;
- else {
- if (idata->flags & PAMNS_DEBUG)
- pam_syslog(idata->pamh, LOG_DEBUG,
- "Unmounting instance dir for user %d & dir %s",
- idata->uid, pptr->dir);
- if (umount(pptr->dir) < 0) {
- pam_syslog(idata->pamh, LOG_ERR, "Unmount of %s failed, %m",
- pptr->dir);
- return PAM_SESSION_ERR;
- } else if (idata->flags & PAMNS_DEBUG)
- pam_syslog(idata->pamh, LOG_DEBUG, "Unmount of %s succeeded",
- pptr->dir);
- }
- }
- cleanup_tmpdirs(idata);
- return 0;
- }
- #ifdef WITH_SELINUX
- /*
- * This function checks if the calling program has requested context
- * change by calling setexeccon(). If context change is not requested
- * then it does not make sense to polyinstantiate based on context.
- * The return value from this function is used when selecting the
- * polyinstantiation method. If context change is not requested then
- * the polyinstantiation method is set to USER, even if the configuration
- * file lists the method as "context" or "level".
- */
- static int ctxt_based_inst_needed(void)
- {
- char *scon = NULL;
- int rc = 0;
- rc = getexeccon(&scon);
- if (rc < 0 || scon == NULL)
- return 0;
- else {
- freecon(scon);
- return 1;
- }
- }
- #endif
- static int root_shared(void)
- {
- FILE *f;
- char *line = NULL;
- size_t n = 0;
- int rv = 0;
- f = fopen("/proc/self/mountinfo", "r");
- if (f == NULL)
- return 0;
- while(getline(&line, &n, f) != -1) {
- char *l;
- char *sptr;
- int i;
- l = line;
- sptr = NULL;
- for (i = 0; i < 7; i++) {
- char *tok;
- tok = strtok_r(l, " ", &sptr);
- l = NULL;
- if (tok == NULL)
- /* next mountinfo line */
- break;
- if (i == 4 && strcmp(tok, "/") != 0)
- /* next mountinfo line */
- break;
- if (i == 6) {
- if (pam_str_skip_prefix(tok, "shared:") != NULL)
- /* there might be more / mounts, the last one counts */
- rv = 1;
- else
- rv = 0;
- }
- }
- }
- free(line);
- fclose(f);
- return rv;
- }
- 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 );
- if ( user_name == NULL || retval != PAM_SUCCESS ) {
- pam_syslog(idata->pamh, LOG_ERR, "Error recovering pam user name");
- return PAM_SESSION_ERR;
- }
- pwd = pam_modutil_getpwnam(idata->pamh, user_name);
- if (!pwd) {
- pam_syslog(idata->pamh, LOG_ERR, "user unknown '%s'", user_name);
- return PAM_USER_UNKNOWN;
- }
- /*
- * Add the user info to the instance data so we can refer to them later.
- */
- idata->user[0] = 0;
- strncat(idata->user, user_name, sizeof(idata->user) - 1);
- idata->uid = pwd->pw_uid;
- idata->gid = pwd->pw_gid;
- /* 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);
- } else {
- pwd = pam_modutil_getpwuid(idata->pamh, getuid());
- }
- if (!pwd) {
- pam_syslog(idata->pamh, LOG_ERR, "user unknown '%s'", user_name);
- return PAM_USER_UNKNOWN;
- }
- user_name = pwd->pw_name;
- idata->ruser[0] = 0;
- strncat(idata->ruser, user_name, sizeof(idata->ruser) - 1);
- idata->ruid = pwd->pw_uid;
- return PAM_SUCCESS;
- }
- /*
- * Entry point from pam_open_session call.
- */
- int pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED,
- int argc, const char **argv)
- {
- int i, retval;
- struct instance_data idata;
- enum unmnt_op unmnt = NO_UNMNT;
- /* init instance data */
- idata.flags = 0;
- idata.polydirs_ptr = NULL;
- idata.protect_dirs = NULL;
- idata.pamh = pamh;
- #ifdef WITH_SELINUX
- if (is_selinux_enabled())
- idata.flags |= PAMNS_SELINUX_ENABLED;
- if (ctxt_based_inst_needed())
- idata.flags |= PAMNS_CTXT_BASED_INST;
- #endif
- /* Parse arguments. */
- for (i = 0; i < argc; i++) {
- if (strcmp(argv[i], "debug") == 0)
- idata.flags |= PAMNS_DEBUG;
- if (strcmp(argv[i], "gen_hash") == 0)
- idata.flags |= PAMNS_GEN_HASH;
- if (strcmp(argv[i], "ignore_config_error") == 0)
- idata.flags |= PAMNS_IGN_CONFIG_ERR;
- if (strcmp(argv[i], "ignore_instance_parent_mode") == 0)
- idata.flags |= PAMNS_IGN_INST_PARENT_MODE;
- if (strcmp(argv[i], "use_current_context") == 0) {
- idata.flags |= PAMNS_USE_CURRENT_CONTEXT;
- idata.flags |= PAMNS_CTXT_BASED_INST;
- }
- if (strcmp(argv[i], "use_default_context") == 0) {
- idata.flags |= PAMNS_USE_DEFAULT_CONTEXT;
- idata.flags |= PAMNS_CTXT_BASED_INST;
- }
- if (strcmp(argv[i], "mount_private") == 0) {
- idata.flags |= PAMNS_MOUNT_PRIVATE;
- }
- if (strcmp(argv[i], "unmnt_remnt") == 0)
- unmnt = UNMNT_REMNT;
- if (strcmp(argv[i], "unmnt_only") == 0)
- unmnt = UNMNT_ONLY;
- if (strcmp(argv[i], "require_selinux") == 0) {
- if (!(idata.flags & PAMNS_SELINUX_ENABLED)) {
- pam_syslog(idata.pamh, LOG_ERR,
- "selinux_required option given and selinux is disabled");
- return PAM_SESSION_ERR;
- }
- }
- }
- if (idata.flags & PAMNS_DEBUG)
- pam_syslog(idata.pamh, LOG_DEBUG, "open_session - start");
- retval = get_user_data(&idata);
- if (retval != PAM_SUCCESS)
- return retval;
- if (root_shared()) {
- idata.flags |= PAMNS_MOUNT_PRIVATE;
- }
- /*
- * Parse namespace configuration file which lists directories to
- * polyinstantiate, directory where instance directories are to
- * be created and the method used for polyinstantiation.
- */
- retval = parse_config_file(&idata);
- if (retval != PAM_SUCCESS) {
- del_polydir_list(idata.polydirs_ptr);
- return PAM_SESSION_ERR;
- }
- if (idata.polydirs_ptr) {
- retval = setup_namespace(&idata, unmnt);
- if (idata.flags & PAMNS_DEBUG) {
- if (retval)
- pam_syslog(idata.pamh, LOG_DEBUG,
- "namespace setup failed for pid %d", getpid());
- else
- pam_syslog(idata.pamh, LOG_DEBUG,
- "namespace setup ok for pid %d", getpid());
- }
- } else if (idata.flags & PAMNS_DEBUG)
- pam_syslog(idata.pamh, LOG_DEBUG, "Nothing to polyinstantiate");
- if (retval != PAM_SUCCESS)
- del_polydir_list(idata.polydirs_ptr);
- return retval;
- }
- /*
- * Entry point from pam_close_session call.
- */
- int pam_sm_close_session(pam_handle_t *pamh, int flags UNUSED,
- int argc, const char **argv)
- {
- int i, retval;
- struct instance_data idata;
- const void *polyptr;
- /* init instance data */
- idata.flags = 0;
- idata.polydirs_ptr = NULL;
- idata.pamh = pamh;
- #ifdef WITH_SELINUX
- if (is_selinux_enabled())
- idata.flags |= PAMNS_SELINUX_ENABLED;
- if (ctxt_based_inst_needed())
- idata.flags |= PAMNS_CTXT_BASED_INST;
- #endif
- /* Parse arguments. */
- for (i = 0; i < argc; i++) {
- if (strcmp(argv[i], "debug") == 0)
- idata.flags |= PAMNS_DEBUG;
- if (strcmp(argv[i], "ignore_config_error") == 0)
- idata.flags |= PAMNS_IGN_CONFIG_ERR;
- 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");
- /*
- * 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_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 - successful");
- return PAM_SUCCESS;
- }
- retval = get_user_data(&idata);
- if (retval != PAM_SUCCESS)
- return retval;
- retval = pam_get_data(idata.pamh, NAMESPACE_POLYDIR_DATA, &polyptr);
- if (retval != PAM_SUCCESS || polyptr == NULL)
- /* nothing to reset */
- return PAM_SUCCESS;
- DIAG_PUSH_IGNORE_CAST_QUAL;
- idata.polydirs_ptr = (void *)polyptr;
- DIAG_POP_IGNORE_CAST_QUAL;
- if (idata.flags & PAMNS_DEBUG)
- pam_syslog(idata.pamh, LOG_DEBUG, "Resetting namespace for pid %d",
- getpid());
- retval = orig_namespace(&idata);
- if (idata.flags & PAMNS_DEBUG) {
- if (retval)
- pam_syslog(idata.pamh, LOG_DEBUG,
- "resetting namespace failed for pid %d", getpid());
- else
- pam_syslog(idata.pamh, LOG_DEBUG,
- "resetting namespace ok for pid %d", getpid());
- }
- pam_set_data(idata.pamh, NAMESPACE_POLYDIR_DATA, NULL, NULL);
- pam_set_data(idata.pamh, NAMESPACE_PROTECT_DATA, NULL, NULL);
- return PAM_SUCCESS;
- }
|