pam_namespace.c 60 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272
  1. /******************************************************************************
  2. * A module for Linux-PAM that will set the default namespace after
  3. * establishing a session via PAM.
  4. *
  5. * (C) Copyright IBM Corporation 2005
  6. * (C) Copyright Red Hat, Inc. 2006, 2008
  7. * All Rights Reserved.
  8. *
  9. * Written by: Janak Desai <janak@us.ibm.com>
  10. * With Revisions by: Steve Grubb <sgrubb@redhat.com>
  11. * Contributions by: Xavier Toth <txtoth@gmail.com>,
  12. * Tomas Mraz <tmraz@redhat.com>
  13. * Derived from a namespace setup patch by Chad Sellers <cdselle@tycho.nsa.gov>
  14. *
  15. * Permission is hereby granted, free of charge, to any person obtaining a
  16. * copy of this software and associated documentation files (the "Software"),
  17. * to deal in the Software without restriction, including without limitation
  18. * on the rights to use, copy, modify, merge, publish, distribute, sub
  19. * license, and/or sell copies of the Software, and to permit persons to whom
  20. * the Software is furnished to do so, subject to the following conditions:
  21. *
  22. * The above copyright notice and this permission notice (including the next
  23. * paragraph) shall be included in all copies or substantial portions of the
  24. * Software.
  25. *
  26. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  27. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  28. * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
  29. * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  30. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  31. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  32. * DEALINGS IN THE SOFTWARE.
  33. */
  34. #define _ATFILE_SOURCE
  35. #include "pam_cc_compat.h"
  36. #include "pam_inline.h"
  37. #include "pam_namespace.h"
  38. #include "argv_parse.h"
  39. /*
  40. * Adds an entry for a polyinstantiated directory to the linked list of
  41. * polyinstantiated directories. It is called from process_line() while
  42. * parsing the namespace configuration file.
  43. */
  44. static void add_polydir_entry(struct instance_data *idata,
  45. struct polydir_s *ent)
  46. {
  47. /* Now attach to linked list */
  48. ent->next = NULL;
  49. if (idata->polydirs_ptr == NULL)
  50. idata->polydirs_ptr = ent;
  51. else {
  52. struct polydir_s *tail;
  53. tail = idata->polydirs_ptr;
  54. while (tail->next)
  55. tail = tail->next;
  56. tail->next = ent;
  57. }
  58. }
  59. static void del_polydir(struct polydir_s *poly)
  60. {
  61. if (poly) {
  62. free(poly->uid);
  63. free(poly->init_script);
  64. free(poly->mount_opts);
  65. free(poly);
  66. }
  67. }
  68. /*
  69. * Deletes all the entries in the linked list.
  70. */
  71. static void del_polydir_list(struct polydir_s *polydirs_ptr)
  72. {
  73. struct polydir_s *dptr = polydirs_ptr;
  74. while (dptr) {
  75. struct polydir_s *tptr = dptr;
  76. dptr = dptr->next;
  77. del_polydir(tptr);
  78. }
  79. }
  80. static void unprotect_dirs(struct protect_dir_s *dir)
  81. {
  82. struct protect_dir_s *next;
  83. while (dir != NULL) {
  84. umount(dir->dir);
  85. free(dir->dir);
  86. next = dir->next;
  87. free(dir);
  88. dir = next;
  89. }
  90. }
  91. static void cleanup_polydir_data(pam_handle_t *pamh UNUSED , void *data, int err UNUSED)
  92. {
  93. del_polydir_list(data);
  94. }
  95. static void cleanup_protect_data(pam_handle_t *pamh UNUSED , void *data, int err UNUSED)
  96. {
  97. unprotect_dirs(data);
  98. }
  99. static char *expand_variables(const char *orig, const char *var_names[], const char *var_values[])
  100. {
  101. const char *src = orig;
  102. char *dst;
  103. char *expanded;
  104. char c;
  105. size_t dstlen = 0;
  106. while (*src) {
  107. if (*src == '$') {
  108. int i;
  109. for (i = 0; var_names[i]; i++) {
  110. int namelen = strlen(var_names[i]);
  111. if (strncmp(var_names[i], src+1, namelen) == 0) {
  112. dstlen += strlen(var_values[i]) - 1; /* $ */
  113. src += namelen;
  114. break;
  115. }
  116. }
  117. }
  118. ++dstlen;
  119. ++src;
  120. }
  121. if ((dst=expanded=malloc(dstlen + 1)) == NULL)
  122. return NULL;
  123. src = orig;
  124. while ((c=*src) != '\0') {
  125. if (c == '$') {
  126. int i;
  127. for (i = 0; var_names[i]; i++) {
  128. int namelen = strlen(var_names[i]);
  129. if (strncmp(var_names[i], src+1, namelen) == 0) {
  130. dst = stpcpy(dst, var_values[i]);
  131. --dst;
  132. c = *dst; /* replace $ */
  133. src += namelen;
  134. break;
  135. }
  136. }
  137. }
  138. *dst = c;
  139. ++dst;
  140. ++src;
  141. }
  142. *dst = '\0';
  143. return expanded;
  144. }
  145. static int parse_create_params(char *params, struct polydir_s *poly)
  146. {
  147. char *next;
  148. struct passwd *pwd = NULL;
  149. struct group *grp;
  150. poly->mode = (mode_t)ULONG_MAX;
  151. poly->owner = (uid_t)ULONG_MAX;
  152. poly->group = (gid_t)ULONG_MAX;
  153. if (*params != '=')
  154. return 0;
  155. params++;
  156. next = strchr(params, ',');
  157. if (next != NULL) {
  158. *next = '\0';
  159. next++;
  160. }
  161. if (*params != '\0') {
  162. errno = 0;
  163. poly->mode = (mode_t)strtoul(params, NULL, 0);
  164. if (errno != 0) {
  165. poly->mode = (mode_t)ULONG_MAX;
  166. }
  167. }
  168. params = next;
  169. if (params == NULL)
  170. return 0;
  171. next = strchr(params, ',');
  172. if (next != NULL) {
  173. *next = '\0';
  174. next++;
  175. }
  176. if (*params != '\0') {
  177. pwd = getpwnam(params); /* session modules are not reentrant */
  178. if (pwd == NULL)
  179. return -1;
  180. poly->owner = pwd->pw_uid;
  181. }
  182. params = next;
  183. if (params == NULL || *params == '\0') {
  184. if (pwd != NULL)
  185. poly->group = pwd->pw_gid;
  186. return 0;
  187. }
  188. grp = getgrnam(params);
  189. if (grp == NULL)
  190. return -1;
  191. poly->group = grp->gr_gid;
  192. return 0;
  193. }
  194. static int parse_iscript_params(char *params, struct polydir_s *poly)
  195. {
  196. if (*params != '=')
  197. return 0;
  198. params++;
  199. if (*params != '\0') {
  200. if (*params != '/') { /* path is relative to NAMESPACE_D_DIR */
  201. if (asprintf(&poly->init_script, "%s%s", NAMESPACE_D_DIR, params) == -1)
  202. return -1;
  203. } else {
  204. poly->init_script = strdup(params);
  205. }
  206. if (poly->init_script == NULL)
  207. return -1;
  208. }
  209. return 0;
  210. }
  211. struct mntflag {
  212. const char *name;
  213. size_t len;
  214. unsigned long flag;
  215. };
  216. #define LITERAL_AND_LEN(x) x, sizeof(x) - 1
  217. static const struct mntflag mntflags[] = {
  218. { LITERAL_AND_LEN("noexec"), MS_NOEXEC },
  219. { LITERAL_AND_LEN("nosuid"), MS_NOSUID },
  220. { LITERAL_AND_LEN("nodev"), MS_NODEV }
  221. };
  222. static int filter_mntopts(const char *opts, char **filtered,
  223. unsigned long *mountflags)
  224. {
  225. size_t origlen = strlen(opts);
  226. const char *end;
  227. char *dest;
  228. dest = *filtered = NULL;
  229. *mountflags = 0;
  230. if (origlen == 0)
  231. return 0;
  232. do {
  233. size_t len;
  234. unsigned int i;
  235. end = strchr(opts, ',');
  236. if (end == NULL) {
  237. len = strlen(opts);
  238. } else {
  239. len = end - opts;
  240. }
  241. for (i = 0; i < PAM_ARRAY_SIZE(mntflags); i++) {
  242. if (mntflags[i].len != len)
  243. continue;
  244. if (memcmp(mntflags[i].name, opts, len) == 0) {
  245. *mountflags |= mntflags[i].flag;
  246. opts = end;
  247. break;
  248. }
  249. }
  250. if (opts != end) {
  251. if (dest != NULL) {
  252. *dest = ',';
  253. ++dest;
  254. } else {
  255. dest = *filtered = calloc(1, origlen + 1);
  256. if (dest == NULL)
  257. return -1;
  258. }
  259. memcpy(dest, opts, len);
  260. dest += len;
  261. }
  262. opts = end + 1;
  263. } while (end != NULL);
  264. return 0;
  265. }
  266. static int parse_method(char *method, struct polydir_s *poly,
  267. struct instance_data *idata)
  268. {
  269. enum polymethod pm;
  270. char *sptr = NULL;
  271. static const char *method_names[] = { "user", "context", "level", "tmpdir",
  272. "tmpfs", NULL };
  273. static const char *flag_names[] = { "create", "noinit", "iscript",
  274. "shared", "mntopts", NULL };
  275. static const unsigned int flag_values[] = { POLYDIR_CREATE, POLYDIR_NOINIT,
  276. POLYDIR_ISCRIPT, POLYDIR_SHARED, POLYDIR_MNTOPTS };
  277. int i;
  278. char *flag;
  279. method = strtok_r(method, ":", &sptr);
  280. pm = NONE;
  281. for (i = 0; method_names[i]; i++) {
  282. if (strcmp(method, method_names[i]) == 0) {
  283. pm = i + 1; /* 0 = NONE */
  284. }
  285. }
  286. if (pm == NONE) {
  287. pam_syslog(idata->pamh, LOG_NOTICE, "Unknown method");
  288. return -1;
  289. }
  290. poly->method = pm;
  291. while ((flag=strtok_r(NULL, ":", &sptr)) != NULL) {
  292. for (i = 0; flag_names[i]; i++) {
  293. int namelen = strlen(flag_names[i]);
  294. if (strncmp(flag, flag_names[i], namelen) == 0) {
  295. poly->flags |= flag_values[i];
  296. switch (flag_values[i]) {
  297. case POLYDIR_CREATE:
  298. if (parse_create_params(flag+namelen, poly) != 0) {
  299. pam_syslog(idata->pamh, LOG_CRIT, "Invalid create parameters");
  300. return -1;
  301. }
  302. break;
  303. case POLYDIR_ISCRIPT:
  304. if (parse_iscript_params(flag+namelen, poly) != 0) {
  305. pam_syslog(idata->pamh, LOG_CRIT, "Memory allocation error");
  306. return -1;
  307. };
  308. break;
  309. case POLYDIR_MNTOPTS:
  310. if (flag[namelen] != '=')
  311. break;
  312. if (poly->method != TMPFS) {
  313. pam_syslog(idata->pamh, LOG_WARNING, "Mount options applicable only to tmpfs method");
  314. break;
  315. }
  316. free(poly->mount_opts); /* if duplicate mntopts specified */
  317. poly->mount_opts = NULL;
  318. if (filter_mntopts(flag+namelen+1, &poly->mount_opts, &poly->mount_flags) != 0) {
  319. pam_syslog(idata->pamh, LOG_CRIT, "Memory allocation error");
  320. return -1;
  321. }
  322. break;
  323. }
  324. }
  325. }
  326. }
  327. return 0;
  328. }
  329. /*
  330. * Called from parse_config_file, this function processes a single line
  331. * of the namespace configuration file. It skips over comments and incomplete
  332. * or malformed lines. It processes a valid line with information on
  333. * polyinstantiating a directory by populating appropriate fields of a
  334. * polyinstatiated directory structure and then calling add_polydir_entry to
  335. * add that entry to the linked list of polyinstantiated directories.
  336. */
  337. static int process_line(char *line, const char *home, const char *rhome,
  338. struct instance_data *idata)
  339. {
  340. char *dir = NULL, *instance_prefix = NULL, *rdir = NULL;
  341. char *method, *uids;
  342. char *tptr;
  343. struct polydir_s *poly;
  344. int retval = 0;
  345. char **config_options = NULL;
  346. static const char *var_names[] = {"HOME", "USER", NULL};
  347. const char *var_values[] = {home, idata->user};
  348. const char *rvar_values[] = {rhome, idata->ruser};
  349. int len;
  350. /*
  351. * skip the leading white space
  352. */
  353. while (*line && isspace(*line))
  354. line++;
  355. /*
  356. * Rip off the comments
  357. */
  358. tptr = strchr(line,'#');
  359. if (tptr)
  360. *tptr = '\0';
  361. /*
  362. * Rip off the newline char
  363. */
  364. tptr = strchr(line,'\n');
  365. if (tptr)
  366. *tptr = '\0';
  367. /*
  368. * Anything left ?
  369. */
  370. if (line[0] == 0)
  371. return 0;
  372. poly = calloc(1, sizeof(*poly));
  373. if (poly == NULL)
  374. goto erralloc;
  375. /*
  376. * Initialize and scan the five strings from the line from the
  377. * namespace configuration file.
  378. */
  379. retval = argv_parse(line, NULL, &config_options);
  380. if (retval != 0) {
  381. goto erralloc;
  382. }
  383. dir = config_options[0];
  384. if (dir == NULL) {
  385. pam_syslog(idata->pamh, LOG_NOTICE, "Invalid line missing polydir");
  386. goto skipping;
  387. }
  388. instance_prefix = config_options[1];
  389. if (instance_prefix == NULL) {
  390. pam_syslog(idata->pamh, LOG_NOTICE, "Invalid line missing instance_prefix");
  391. instance_prefix = NULL;
  392. goto skipping;
  393. }
  394. method = config_options[2];
  395. if (method == NULL) {
  396. pam_syslog(idata->pamh, LOG_NOTICE, "Invalid line missing method");
  397. instance_prefix = NULL;
  398. dir = NULL;
  399. goto skipping;
  400. }
  401. /*
  402. * Only the uids field is allowed to be blank, to indicate no
  403. * override users for polyinstantiation of that directory. If
  404. * any of the other fields are blank, the line is incomplete so
  405. * skip it.
  406. */
  407. uids = config_options[3];
  408. /*
  409. * Expand $HOME and $USER in poly dir and instance dir prefix
  410. */
  411. if ((rdir=expand_variables(dir, var_names, rvar_values)) == NULL) {
  412. instance_prefix = NULL;
  413. dir = NULL;
  414. goto erralloc;
  415. }
  416. if ((dir=expand_variables(dir, var_names, var_values)) == NULL) {
  417. instance_prefix = NULL;
  418. goto erralloc;
  419. }
  420. if ((instance_prefix=expand_variables(instance_prefix, var_names, var_values))
  421. == NULL) {
  422. goto erralloc;
  423. }
  424. if (idata->flags & PAMNS_DEBUG) {
  425. pam_syslog(idata->pamh, LOG_DEBUG, "Expanded polydir: '%s'", dir);
  426. pam_syslog(idata->pamh, LOG_DEBUG, "Expanded ruser polydir: '%s'", rdir);
  427. pam_syslog(idata->pamh, LOG_DEBUG, "Expanded instance prefix: '%s'", instance_prefix);
  428. }
  429. len = strlen(dir);
  430. if (len > 0 && dir[len-1] == '/') {
  431. dir[len-1] = '\0';
  432. }
  433. len = strlen(rdir);
  434. if (len > 0 && rdir[len-1] == '/') {
  435. rdir[len-1] = '\0';
  436. }
  437. if (dir[0] == '\0' || rdir[0] == '\0') {
  438. pam_syslog(idata->pamh, LOG_NOTICE, "Invalid polydir");
  439. goto skipping;
  440. }
  441. /*
  442. * Populate polyinstantiated directory structure with appropriate
  443. * pathnames and the method with which to polyinstantiate.
  444. */
  445. if (strlen(dir) >= sizeof(poly->dir)
  446. || strlen(rdir) >= sizeof(poly->rdir)
  447. || strlen(instance_prefix) >= sizeof(poly->instance_prefix)) {
  448. pam_syslog(idata->pamh, LOG_NOTICE, "Pathnames too long");
  449. goto skipping;
  450. }
  451. strcpy(poly->dir, dir);
  452. strcpy(poly->rdir, rdir);
  453. strcpy(poly->instance_prefix, instance_prefix);
  454. if (parse_method(method, poly, idata) != 0) {
  455. goto skipping;
  456. }
  457. if (poly->method == TMPDIR) {
  458. if (sizeof(poly->instance_prefix) - strlen(poly->instance_prefix) < 7) {
  459. pam_syslog(idata->pamh, LOG_NOTICE, "Pathnames too long");
  460. goto skipping;
  461. }
  462. strcat(poly->instance_prefix, "XXXXXX");
  463. }
  464. /*
  465. * Ensure that all pathnames are absolute path names.
  466. */
  467. if ((poly->dir[0] != '/') || (poly->method != TMPFS && poly->instance_prefix[0] != '/')) {
  468. pam_syslog(idata->pamh, LOG_NOTICE, "Pathnames must start with '/'");
  469. goto skipping;
  470. }
  471. if (strstr(dir, "..") || strstr(poly->instance_prefix, "..")) {
  472. pam_syslog(idata->pamh, LOG_NOTICE, "Pathnames must not contain '..'");
  473. goto skipping;
  474. }
  475. /*
  476. * If the line in namespace.conf for a directory to polyinstantiate
  477. * contains a list of override users (users for whom polyinstantiation
  478. * is not performed), read the user ids, convert names into uids, and
  479. * add to polyinstantiated directory structure.
  480. */
  481. if (uids) {
  482. uid_t *uidptr;
  483. const char *ustr, *sstr;
  484. int count, i;
  485. if (*uids == '~') {
  486. poly->flags |= POLYDIR_EXCLUSIVE;
  487. uids++;
  488. }
  489. for (count = 0, ustr = sstr = uids; sstr; ustr = sstr + 1, count++)
  490. sstr = strchr(ustr, ',');
  491. poly->num_uids = count;
  492. poly->uid = (uid_t *) malloc(count * sizeof (uid_t));
  493. uidptr = poly->uid;
  494. if (uidptr == NULL) {
  495. goto erralloc;
  496. }
  497. ustr = uids;
  498. for (i = 0; i < count; i++) {
  499. struct passwd *pwd;
  500. tptr = strchr(ustr, ',');
  501. if (tptr)
  502. *tptr = '\0';
  503. pwd = pam_modutil_getpwnam(idata->pamh, ustr);
  504. if (pwd == NULL) {
  505. pam_syslog(idata->pamh, LOG_ERR, "Unknown user %s in configuration", ustr);
  506. poly->num_uids--;
  507. } else {
  508. *uidptr = pwd->pw_uid;
  509. uidptr++;
  510. }
  511. ustr = tptr + 1;
  512. }
  513. }
  514. /*
  515. * Add polyinstantiated directory structure to the linked list
  516. * of all polyinstantiated directory structures.
  517. */
  518. add_polydir_entry(idata, poly);
  519. goto out;
  520. erralloc:
  521. pam_syslog(idata->pamh, LOG_CRIT, "Memory allocation error");
  522. skipping:
  523. if (idata->flags & PAMNS_IGN_CONFIG_ERR)
  524. retval = 0;
  525. else
  526. retval = PAM_SERVICE_ERR;
  527. del_polydir(poly);
  528. out:
  529. free(rdir);
  530. free(dir);
  531. free(instance_prefix);
  532. argv_free(config_options);
  533. return retval;
  534. }
  535. /*
  536. * Parses /etc/security/namespace.conf file to build a linked list of
  537. * polyinstantiated directory structures of type polydir_s. Each entry
  538. * in the linked list contains information needed to polyinstantiate
  539. * one directory.
  540. */
  541. static int parse_config_file(struct instance_data *idata)
  542. {
  543. FILE *fil;
  544. char *home, *rhome;
  545. const char *confname;
  546. struct passwd *cpwd;
  547. char *line;
  548. int retval;
  549. size_t len = 0;
  550. glob_t globbuf;
  551. const char *oldlocale;
  552. size_t n;
  553. /*
  554. * Extract the user's home directory to resolve $HOME entries
  555. * in the namespace configuration file.
  556. */
  557. cpwd = pam_modutil_getpwnam(idata->pamh, idata->user);
  558. if (!cpwd) {
  559. pam_syslog(idata->pamh, LOG_ERR,
  560. "Error getting home dir for '%s'", idata->user);
  561. return PAM_SESSION_ERR;
  562. }
  563. if ((home=strdup(cpwd->pw_dir)) == NULL) {
  564. pam_syslog(idata->pamh, LOG_CRIT,
  565. "Memory allocation error");
  566. return PAM_SESSION_ERR;
  567. }
  568. cpwd = pam_modutil_getpwnam(idata->pamh, idata->ruser);
  569. if (!cpwd) {
  570. pam_syslog(idata->pamh, LOG_ERR,
  571. "Error getting home dir for '%s'", idata->ruser);
  572. free(home);
  573. return PAM_SESSION_ERR;
  574. }
  575. if ((rhome=strdup(cpwd->pw_dir)) == NULL) {
  576. pam_syslog(idata->pamh, LOG_CRIT,
  577. "Memory allocation error");
  578. free(home);
  579. return PAM_SESSION_ERR;
  580. }
  581. /*
  582. * Open configuration file, read one line at a time and call
  583. * process_line to process each line.
  584. */
  585. memset(&globbuf, '\0', sizeof(globbuf));
  586. oldlocale = setlocale(LC_COLLATE, "C");
  587. glob(NAMESPACE_D_GLOB, 0, NULL, &globbuf);
  588. if (oldlocale != NULL)
  589. setlocale(LC_COLLATE, oldlocale);
  590. confname = PAM_NAMESPACE_CONFIG;
  591. n = 0;
  592. for (;;) {
  593. if (idata->flags & PAMNS_DEBUG)
  594. pam_syslog(idata->pamh, LOG_DEBUG, "Parsing config file %s",
  595. confname);
  596. fil = fopen(confname, "r");
  597. if (fil == NULL) {
  598. pam_syslog(idata->pamh, LOG_ERR, "Error opening config file %s",
  599. confname);
  600. globfree(&globbuf);
  601. free(rhome);
  602. free(home);
  603. return PAM_SERVICE_ERR;
  604. }
  605. /* Use unlocked IO */
  606. __fsetlocking(fil, FSETLOCKING_BYCALLER);
  607. line = NULL;
  608. /* loop reading the file */
  609. while (getline(&line, &len, fil) > 0) {
  610. retval = process_line(line, home, rhome, idata);
  611. if (retval) {
  612. pam_syslog(idata->pamh, LOG_ERR,
  613. "Error processing conf file %s line %s", confname, line);
  614. fclose(fil);
  615. free(line);
  616. globfree(&globbuf);
  617. free(rhome);
  618. free(home);
  619. return PAM_SERVICE_ERR;
  620. }
  621. }
  622. fclose(fil);
  623. free(line);
  624. if (n >= globbuf.gl_pathc)
  625. break;
  626. confname = globbuf.gl_pathv[n];
  627. n++;
  628. }
  629. globfree(&globbuf);
  630. free(rhome);
  631. free(home);
  632. /* All done...just some debug stuff */
  633. if (idata->flags & PAMNS_DEBUG) {
  634. struct polydir_s *dptr = idata->polydirs_ptr;
  635. uid_t *iptr;
  636. uid_t i;
  637. pam_syslog(idata->pamh, LOG_DEBUG,
  638. dptr?"Configured poly dirs:":"No configured poly dirs");
  639. while (dptr) {
  640. pam_syslog(idata->pamh, LOG_DEBUG, "dir='%s' iprefix='%s' meth=%d",
  641. dptr->dir, dptr->instance_prefix, dptr->method);
  642. for (i = 0, iptr = dptr->uid; i < dptr->num_uids; i++, iptr++)
  643. pam_syslog(idata->pamh, LOG_DEBUG, "override user %d ", *iptr);
  644. dptr = dptr->next;
  645. }
  646. }
  647. return PAM_SUCCESS;
  648. }
  649. /*
  650. * This function returns true if a given uid is present in the polyinstantiated
  651. * directory's list of override uids. If the uid is one of the override
  652. * uids for the polyinstantiated directory, polyinstantiation is not
  653. * performed for that user for that directory.
  654. * If exclusive is set the returned values are opposite.
  655. */
  656. static int ns_override(struct polydir_s *polyptr, struct instance_data *idata,
  657. uid_t uid)
  658. {
  659. unsigned int i;
  660. if (idata->flags & PAMNS_DEBUG)
  661. pam_syslog(idata->pamh, LOG_DEBUG,
  662. "Checking for ns override in dir %s for uid %d",
  663. polyptr->dir, uid);
  664. for (i = 0; i < polyptr->num_uids; i++) {
  665. if (uid == polyptr->uid[i]) {
  666. return !(polyptr->flags & POLYDIR_EXCLUSIVE);
  667. }
  668. }
  669. return !!(polyptr->flags & POLYDIR_EXCLUSIVE);
  670. }
  671. /*
  672. * md5hash generates a hash of the passed in instance directory name.
  673. */
  674. static char *md5hash(const char *instname, struct instance_data *idata)
  675. {
  676. int i;
  677. char *md5inst = NULL;
  678. char *to;
  679. unsigned char inst_digest[MD5_DIGEST_LENGTH];
  680. /*
  681. * Create MD5 hashes for instance pathname.
  682. */
  683. MD5((const unsigned char *)instname, strlen(instname), inst_digest);
  684. if ((md5inst = malloc(MD5_DIGEST_LENGTH * 2 + 1)) == NULL) {
  685. pam_syslog(idata->pamh, LOG_CRIT, "Unable to allocate buffer");
  686. return NULL;
  687. }
  688. to = md5inst;
  689. for (i = 0; i < MD5_DIGEST_LENGTH; i++) {
  690. snprintf(to, 3, "%02x", (unsigned int)inst_digest[i]);
  691. to += 2;
  692. }
  693. return md5inst;
  694. }
  695. #ifdef WITH_SELINUX
  696. static int form_context(const struct polydir_s *polyptr,
  697. char **i_context, char **origcon,
  698. struct instance_data *idata)
  699. {
  700. int rc = PAM_SUCCESS;
  701. char *scon = NULL;
  702. security_class_t tclass;
  703. /*
  704. * Get the security context of the directory to polyinstantiate.
  705. */
  706. rc = getfilecon(polyptr->dir, origcon);
  707. if (rc < 0 || *origcon == NULL) {
  708. pam_syslog(idata->pamh, LOG_ERR,
  709. "Error getting poly dir context, %m");
  710. return PAM_SESSION_ERR;
  711. }
  712. if (polyptr->method == USER) return PAM_SUCCESS;
  713. if (idata->flags & PAMNS_USE_CURRENT_CONTEXT) {
  714. rc = getcon(&scon);
  715. } else if (idata->flags & PAMNS_USE_DEFAULT_CONTEXT) {
  716. char *seuser = NULL, *level = NULL;
  717. if ((rc=getseuserbyname(idata->user, &seuser, &level)) == 0) {
  718. rc = get_default_context_with_level(seuser, level, NULL, &scon);
  719. free(seuser);
  720. free(level);
  721. }
  722. } else {
  723. rc = getexeccon(&scon);
  724. }
  725. if (rc < 0 || scon == NULL) {
  726. pam_syslog(idata->pamh, LOG_ERR,
  727. "Error getting exec context, %m");
  728. return PAM_SESSION_ERR;
  729. }
  730. /*
  731. * If polyinstantiating based on security context, get current
  732. * process security context, get security class for directories,
  733. * and ask the policy to provide security context of the
  734. * polyinstantiated instance directory.
  735. */
  736. if (polyptr->method == CONTEXT) {
  737. tclass = string_to_security_class("dir");
  738. if (tclass == 0) {
  739. pam_syslog(idata->pamh, LOG_ERR,
  740. "Error getting dir security class");
  741. freecon(scon);
  742. return PAM_SESSION_ERR;
  743. }
  744. if (security_compute_member(scon, *origcon, tclass,
  745. i_context) < 0) {
  746. pam_syslog(idata->pamh, LOG_ERR,
  747. "Error computing poly dir member context");
  748. freecon(scon);
  749. return PAM_SESSION_ERR;
  750. } else if (idata->flags & PAMNS_DEBUG)
  751. pam_syslog(idata->pamh, LOG_DEBUG,
  752. "member context returned by policy %s", *i_context);
  753. freecon(scon);
  754. return PAM_SUCCESS;
  755. }
  756. /*
  757. * If polyinstantiating based on security level, get current
  758. * process security context, get security class for directories,
  759. * and change the directories MLS Level to match process.
  760. */
  761. if (polyptr->method == LEVEL) {
  762. context_t scontext = NULL;
  763. context_t fcontext = NULL;
  764. rc = PAM_SESSION_ERR;
  765. scontext = context_new(scon);
  766. if (! scontext) {
  767. pam_syslog(idata->pamh, LOG_CRIT, "out of memory");
  768. goto fail;
  769. }
  770. fcontext = context_new(*origcon);
  771. if (! fcontext) {
  772. pam_syslog(idata->pamh, LOG_CRIT, "out of memory");
  773. goto fail;
  774. }
  775. if (context_range_set(fcontext, context_range_get(scontext)) != 0) {
  776. pam_syslog(idata->pamh, LOG_ERR, "Unable to set MLS Component of context");
  777. goto fail;
  778. }
  779. *i_context=strdup(context_str(fcontext));
  780. if (! *i_context) {
  781. pam_syslog(idata->pamh, LOG_CRIT, "out of memory");
  782. goto fail;
  783. }
  784. rc = PAM_SUCCESS;
  785. fail:
  786. context_free(scontext);
  787. context_free(fcontext);
  788. freecon(scon);
  789. return rc;
  790. }
  791. /* Should never get here */
  792. return PAM_SUCCESS;
  793. }
  794. #endif
  795. /*
  796. * poly_name returns the name of the polyinstantiated instance directory
  797. * based on the method used for polyinstantiation (user, context or level)
  798. * In addition, the function also returns the security contexts of the
  799. * original directory to polyinstantiate and the polyinstantiated instance
  800. * directory.
  801. */
  802. #ifdef WITH_SELINUX
  803. static int poly_name(const struct polydir_s *polyptr, char **i_name,
  804. char **i_context, char **origcon,
  805. struct instance_data *idata)
  806. #else
  807. static int poly_name(const struct polydir_s *polyptr, char **i_name,
  808. struct instance_data *idata)
  809. #endif
  810. {
  811. int rc;
  812. char *hash = NULL;
  813. enum polymethod pm;
  814. #ifdef WITH_SELINUX
  815. char *rawcon = NULL;
  816. #endif
  817. *i_name = NULL;
  818. #ifdef WITH_SELINUX
  819. *i_context = NULL;
  820. *origcon = NULL;
  821. if ((idata->flags & PAMNS_SELINUX_ENABLED) &&
  822. (rc=form_context(polyptr, i_context, origcon, idata)) != PAM_SUCCESS) {
  823. return rc;
  824. }
  825. #endif
  826. rc = PAM_SESSION_ERR;
  827. /*
  828. * Set the name of the polyinstantiated instance dir based on the
  829. * polyinstantiation method.
  830. */
  831. pm = polyptr->method;
  832. if (pm == LEVEL || pm == CONTEXT)
  833. #ifdef WITH_SELINUX
  834. if (!(idata->flags & PAMNS_CTXT_BASED_INST)) {
  835. #else
  836. {
  837. pam_syslog(idata->pamh, LOG_NOTICE,
  838. "Context and level methods not available, using user method");
  839. #endif
  840. if (polyptr->flags & POLYDIR_SHARED) {
  841. rc = PAM_IGNORE;
  842. goto fail;
  843. }
  844. pm = USER;
  845. }
  846. switch (pm) {
  847. case USER:
  848. if (asprintf(i_name, "%s", idata->user) < 0) {
  849. *i_name = NULL;
  850. goto fail;
  851. }
  852. break;
  853. #ifdef WITH_SELINUX
  854. case LEVEL:
  855. case CONTEXT:
  856. if (selinux_trans_to_raw_context(*i_context, &rawcon) < 0) {
  857. pam_syslog(idata->pamh, LOG_ERR, "Error translating directory context");
  858. goto fail;
  859. }
  860. if (polyptr->flags & POLYDIR_SHARED) {
  861. if (asprintf(i_name, "%s", rawcon) < 0) {
  862. *i_name = NULL;
  863. goto fail;
  864. }
  865. } else {
  866. if (asprintf(i_name, "%s_%s", rawcon, idata->user) < 0) {
  867. *i_name = NULL;
  868. goto fail;
  869. }
  870. }
  871. break;
  872. #endif /* WITH_SELINUX */
  873. case TMPDIR:
  874. case TMPFS:
  875. if ((*i_name=strdup("")) == NULL)
  876. goto fail;
  877. return PAM_SUCCESS;
  878. default:
  879. if (idata->flags & PAMNS_DEBUG)
  880. pam_syslog(idata->pamh, LOG_ERR, "Unknown method");
  881. goto fail;
  882. }
  883. if (idata->flags & PAMNS_DEBUG)
  884. pam_syslog(idata->pamh, LOG_DEBUG, "poly_name %s", *i_name);
  885. if ((idata->flags & PAMNS_GEN_HASH) || strlen(*i_name) > NAMESPACE_MAX_DIR_LEN) {
  886. hash = md5hash(*i_name, idata);
  887. if (hash == NULL) {
  888. goto fail;
  889. }
  890. if (idata->flags & PAMNS_GEN_HASH) {
  891. free(*i_name);
  892. *i_name = hash;
  893. hash = NULL;
  894. } else {
  895. char *newname;
  896. if (asprintf(&newname, "%.*s_%s", NAMESPACE_MAX_DIR_LEN-1-(int)strlen(hash),
  897. *i_name, hash) < 0) {
  898. goto fail;
  899. }
  900. free(*i_name);
  901. *i_name = newname;
  902. }
  903. }
  904. rc = PAM_SUCCESS;
  905. fail:
  906. free(hash);
  907. #ifdef WITH_SELINUX
  908. freecon(rawcon);
  909. #endif
  910. if (rc != PAM_SUCCESS) {
  911. #ifdef WITH_SELINUX
  912. freecon(*i_context);
  913. *i_context = NULL;
  914. freecon(*origcon);
  915. *origcon = NULL;
  916. #endif
  917. free(*i_name);
  918. *i_name = NULL;
  919. }
  920. return rc;
  921. }
  922. static int protect_mount(int dfd, const char *path, struct instance_data *idata)
  923. {
  924. struct protect_dir_s *dir = idata->protect_dirs;
  925. char tmpbuf[64];
  926. while (dir != NULL) {
  927. if (strcmp(path, dir->dir) == 0) {
  928. return 0;
  929. }
  930. dir = dir->next;
  931. }
  932. dir = calloc(1, sizeof(*dir));
  933. if (dir == NULL) {
  934. return -1;
  935. }
  936. dir->dir = strdup(path);
  937. if (dir->dir == NULL) {
  938. free(dir);
  939. return -1;
  940. }
  941. snprintf(tmpbuf, sizeof(tmpbuf), "/proc/self/fd/%d", dfd);
  942. if (idata->flags & PAMNS_DEBUG) {
  943. pam_syslog(idata->pamh, LOG_INFO,
  944. "Protect mount of %s over itself", path);
  945. }
  946. if (mount(tmpbuf, tmpbuf, NULL, MS_BIND, NULL) != 0) {
  947. int save_errno = errno;
  948. pam_syslog(idata->pamh, LOG_ERR,
  949. "Protect mount of %s failed: %m", tmpbuf);
  950. free(dir->dir);
  951. free(dir);
  952. errno = save_errno;
  953. return -1;
  954. }
  955. dir->next = idata->protect_dirs;
  956. idata->protect_dirs = dir;
  957. return 0;
  958. }
  959. static int protect_dir(const char *path, mode_t mode, int do_mkdir,
  960. struct instance_data *idata)
  961. {
  962. char *p = strdup(path);
  963. char *d;
  964. char *dir = p;
  965. int dfd = AT_FDCWD;
  966. int dfd_next;
  967. int save_errno;
  968. int flags = O_RDONLY;
  969. int rv = -1;
  970. struct stat st;
  971. if (p == NULL) {
  972. goto error;
  973. }
  974. if (*dir == '/') {
  975. dfd = open("/", flags);
  976. if (dfd == -1) {
  977. goto error;
  978. }
  979. dir++; /* assume / is safe */
  980. }
  981. while ((d=strchr(dir, '/')) != NULL) {
  982. *d = '\0';
  983. dfd_next = openat(dfd, dir, flags);
  984. if (dfd_next == -1) {
  985. goto error;
  986. }
  987. if (dfd != AT_FDCWD)
  988. close(dfd);
  989. dfd = dfd_next;
  990. if (fstat(dfd, &st) != 0) {
  991. goto error;
  992. }
  993. if (flags & O_NOFOLLOW) {
  994. /* we are inside user-owned dir - protect */
  995. if (protect_mount(dfd, p, idata) == -1)
  996. goto error;
  997. } else if (st.st_uid != 0 || st.st_gid != 0 ||
  998. (st.st_mode & S_IWOTH)) {
  999. /* do not follow symlinks on subdirectories */
  1000. flags |= O_NOFOLLOW;
  1001. }
  1002. *d = '/';
  1003. dir = d + 1;
  1004. }
  1005. rv = openat(dfd, dir, flags);
  1006. if (rv == -1) {
  1007. if (!do_mkdir || mkdirat(dfd, dir, mode) != 0) {
  1008. goto error;
  1009. }
  1010. rv = openat(dfd, dir, flags);
  1011. }
  1012. if (rv != -1) {
  1013. if (fstat(rv, &st) != 0) {
  1014. save_errno = errno;
  1015. close(rv);
  1016. rv = -1;
  1017. errno = save_errno;
  1018. goto error;
  1019. }
  1020. if (!S_ISDIR(st.st_mode)) {
  1021. close(rv);
  1022. errno = ENOTDIR;
  1023. rv = -1;
  1024. goto error;
  1025. }
  1026. }
  1027. if (flags & O_NOFOLLOW) {
  1028. /* we are inside user-owned dir - protect */
  1029. if (protect_mount(rv, p, idata) == -1) {
  1030. save_errno = errno;
  1031. close(rv);
  1032. rv = -1;
  1033. errno = save_errno;
  1034. }
  1035. }
  1036. error:
  1037. save_errno = errno;
  1038. free(p);
  1039. if (dfd != AT_FDCWD && dfd >= 0)
  1040. close(dfd);
  1041. errno = save_errno;
  1042. return rv;
  1043. }
  1044. static int check_inst_parent(char *ipath, struct instance_data *idata)
  1045. {
  1046. struct stat instpbuf;
  1047. char *inst_parent, *trailing_slash;
  1048. int dfd;
  1049. /*
  1050. * stat the instance parent path to make sure it exists
  1051. * and is a directory. Check that its mode is 000 (unless the
  1052. * admin explicitly instructs to ignore the instance parent
  1053. * mode by the "ignore_instance_parent_mode" argument).
  1054. */
  1055. inst_parent = (char *) malloc(strlen(ipath)+1);
  1056. if (!inst_parent) {
  1057. pam_syslog(idata->pamh, LOG_CRIT, "Error allocating pathname string");
  1058. return PAM_SESSION_ERR;
  1059. }
  1060. strcpy(inst_parent, ipath);
  1061. trailing_slash = strrchr(inst_parent, '/');
  1062. if (trailing_slash)
  1063. *trailing_slash = '\0';
  1064. dfd = protect_dir(inst_parent, 0, 1, idata);
  1065. if (dfd == -1 || fstat(dfd, &instpbuf) < 0) {
  1066. pam_syslog(idata->pamh, LOG_ERR,
  1067. "Error creating or accessing instance parent %s, %m", inst_parent);
  1068. if (dfd != -1)
  1069. close(dfd);
  1070. free(inst_parent);
  1071. return PAM_SESSION_ERR;
  1072. }
  1073. if ((idata->flags & PAMNS_IGN_INST_PARENT_MODE) == 0) {
  1074. if ((instpbuf.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) || instpbuf.st_uid != 0) {
  1075. pam_syslog(idata->pamh, LOG_ERR, "Mode of inst parent %s not 000 or owner not root",
  1076. inst_parent);
  1077. close(dfd);
  1078. free(inst_parent);
  1079. return PAM_SESSION_ERR;
  1080. }
  1081. }
  1082. close(dfd);
  1083. free(inst_parent);
  1084. return PAM_SUCCESS;
  1085. }
  1086. /*
  1087. * Check to see if there is a namespace initialization script in
  1088. * the /etc/security directory. If such a script exists
  1089. * execute it and pass directory to polyinstantiate and instance
  1090. * directory as arguments.
  1091. */
  1092. static int inst_init(const struct polydir_s *polyptr, const char *ipath,
  1093. struct instance_data *idata, int newdir)
  1094. {
  1095. pid_t rc, pid;
  1096. struct sigaction newsa, oldsa;
  1097. int status;
  1098. const char *init_script = NAMESPACE_INIT_SCRIPT;
  1099. memset(&newsa, '\0', sizeof(newsa));
  1100. newsa.sa_handler = SIG_DFL;
  1101. if (sigaction(SIGCHLD, &newsa, &oldsa) == -1) {
  1102. pam_syslog(idata->pamh, LOG_ERR, "Cannot set signal value");
  1103. return PAM_SESSION_ERR;
  1104. }
  1105. if ((polyptr->flags & POLYDIR_ISCRIPT) && polyptr->init_script)
  1106. init_script = polyptr->init_script;
  1107. if (access(init_script, F_OK) == 0) {
  1108. if (access(init_script, X_OK) < 0) {
  1109. if (idata->flags & PAMNS_DEBUG)
  1110. pam_syslog(idata->pamh, LOG_ERR,
  1111. "Namespace init script not executable");
  1112. rc = PAM_SESSION_ERR;
  1113. goto out;
  1114. } else {
  1115. pid = fork();
  1116. if (pid == 0) {
  1117. static char *envp[] = { NULL };
  1118. #ifdef WITH_SELINUX
  1119. if (idata->flags & PAMNS_SELINUX_ENABLED) {
  1120. if (setexeccon(NULL) < 0)
  1121. _exit(1);
  1122. }
  1123. #endif
  1124. /* Pass maximum privs when we exec() */
  1125. if (setuid(geteuid()) < 0) {
  1126. /* ignore failures, they don't matter */
  1127. }
  1128. if (execle(init_script, init_script,
  1129. polyptr->dir, ipath, newdir?"1":"0", idata->user, NULL, envp) < 0)
  1130. _exit(1);
  1131. } else if (pid > 0) {
  1132. while (((rc = waitpid(pid, &status, 0)) == (pid_t)-1) &&
  1133. (errno == EINTR));
  1134. if (rc == (pid_t)-1) {
  1135. pam_syslog(idata->pamh, LOG_ERR, "waitpid failed- %m");
  1136. rc = PAM_SESSION_ERR;
  1137. goto out;
  1138. }
  1139. if (!WIFEXITED(status) || WIFSIGNALED(status) > 0) {
  1140. pam_syslog(idata->pamh, LOG_ERR,
  1141. "Error initializing instance");
  1142. rc = PAM_SESSION_ERR;
  1143. goto out;
  1144. }
  1145. } else if (pid < 0) {
  1146. pam_syslog(idata->pamh, LOG_ERR,
  1147. "Cannot fork to run namespace init script, %m");
  1148. rc = PAM_SESSION_ERR;
  1149. goto out;
  1150. }
  1151. }
  1152. }
  1153. rc = PAM_SUCCESS;
  1154. out:
  1155. (void) sigaction(SIGCHLD, &oldsa, NULL);
  1156. return rc;
  1157. }
  1158. static int create_polydir(struct polydir_s *polyptr,
  1159. struct instance_data *idata)
  1160. {
  1161. mode_t mode;
  1162. int rc;
  1163. #ifdef WITH_SELINUX
  1164. char *dircon_raw, *oldcon_raw = NULL;
  1165. struct selabel_handle *label_handle;
  1166. #endif
  1167. const char *dir = polyptr->dir;
  1168. uid_t uid;
  1169. gid_t gid;
  1170. if (polyptr->mode != (mode_t)ULONG_MAX)
  1171. mode = polyptr->mode;
  1172. else
  1173. mode = 0777;
  1174. #ifdef WITH_SELINUX
  1175. if (idata->flags & PAMNS_SELINUX_ENABLED) {
  1176. getfscreatecon_raw(&oldcon_raw);
  1177. label_handle = selabel_open(SELABEL_CTX_FILE, NULL, 0);
  1178. if (!label_handle) {
  1179. pam_syslog(idata->pamh, LOG_NOTICE,
  1180. "Unable to initialize SELinux labeling handle: %m");
  1181. } else {
  1182. rc = selabel_lookup_raw(label_handle, &dircon_raw, dir, S_IFDIR);
  1183. if (rc) {
  1184. pam_syslog(idata->pamh, LOG_NOTICE,
  1185. "Unable to get default context for directory %s, check your policy: %m", dir);
  1186. } else {
  1187. if (idata->flags & PAMNS_DEBUG)
  1188. pam_syslog(idata->pamh, LOG_DEBUG,
  1189. "Polydir %s context: %s", dir, dircon_raw);
  1190. if (setfscreatecon_raw(dircon_raw) != 0)
  1191. pam_syslog(idata->pamh, LOG_NOTICE,
  1192. "Error setting context for directory %s: %m", dir);
  1193. freecon(dircon_raw);
  1194. }
  1195. selabel_close(label_handle);
  1196. }
  1197. }
  1198. #endif
  1199. rc = protect_dir(dir, mode, 1, idata);
  1200. if (rc == -1) {
  1201. pam_syslog(idata->pamh, LOG_ERR,
  1202. "Error creating directory %s: %m", dir);
  1203. return PAM_SESSION_ERR;
  1204. }
  1205. #ifdef WITH_SELINUX
  1206. if (idata->flags & PAMNS_SELINUX_ENABLED) {
  1207. if (setfscreatecon_raw(oldcon_raw) != 0)
  1208. pam_syslog(idata->pamh, LOG_NOTICE,
  1209. "Error resetting fs create context: %m");
  1210. freecon(oldcon_raw);
  1211. }
  1212. #endif
  1213. if (idata->flags & PAMNS_DEBUG)
  1214. pam_syslog(idata->pamh, LOG_DEBUG, "Created polydir %s", dir);
  1215. if (polyptr->mode != (mode_t)ULONG_MAX) {
  1216. /* explicit mode requested */
  1217. if (fchmod(rc, mode) != 0) {
  1218. pam_syslog(idata->pamh, LOG_ERR,
  1219. "Error changing mode of directory %s: %m", dir);
  1220. close(rc);
  1221. umount(dir); /* undo the eventual protection bind mount */
  1222. rmdir(dir);
  1223. return PAM_SESSION_ERR;
  1224. }
  1225. }
  1226. if (polyptr->owner != (uid_t)ULONG_MAX)
  1227. uid = polyptr->owner;
  1228. else
  1229. uid = idata->uid;
  1230. if (polyptr->group != (gid_t)ULONG_MAX)
  1231. gid = polyptr->group;
  1232. else
  1233. gid = idata->gid;
  1234. if (fchown(rc, uid, gid) != 0) {
  1235. pam_syslog(idata->pamh, LOG_ERR,
  1236. "Unable to change owner on directory %s: %m", dir);
  1237. close(rc);
  1238. umount(dir); /* undo the eventual protection bind mount */
  1239. rmdir(dir);
  1240. return PAM_SESSION_ERR;
  1241. }
  1242. close(rc);
  1243. if (idata->flags & PAMNS_DEBUG)
  1244. pam_syslog(idata->pamh, LOG_DEBUG,
  1245. "Polydir owner %u group %u", uid, gid);
  1246. return PAM_SUCCESS;
  1247. }
  1248. /*
  1249. * Create polyinstantiated instance directory (ipath).
  1250. */
  1251. #ifdef WITH_SELINUX
  1252. static int create_instance(struct polydir_s *polyptr, char *ipath, struct stat *statbuf,
  1253. const char *icontext, const char *ocontext,
  1254. struct instance_data *idata)
  1255. #else
  1256. static int create_instance(struct polydir_s *polyptr, char *ipath, struct stat *statbuf,
  1257. struct instance_data *idata)
  1258. #endif
  1259. {
  1260. struct stat newstatbuf;
  1261. int fd;
  1262. /*
  1263. * Check to make sure instance parent is valid.
  1264. */
  1265. if (check_inst_parent(ipath, idata))
  1266. return PAM_SESSION_ERR;
  1267. /*
  1268. * Create instance directory and set its security context to the context
  1269. * returned by the security policy. Set its mode and ownership
  1270. * attributes to match that of the original directory that is being
  1271. * polyinstantiated.
  1272. */
  1273. if (polyptr->method == TMPDIR) {
  1274. if (mkdtemp(polyptr->instance_prefix) == NULL) {
  1275. pam_syslog(idata->pamh, LOG_ERR, "Error creating temporary instance %s, %m",
  1276. polyptr->instance_prefix);
  1277. polyptr->method = NONE; /* do not clean up! */
  1278. return PAM_SESSION_ERR;
  1279. }
  1280. /* copy the actual directory name to ipath */
  1281. strcpy(ipath, polyptr->instance_prefix);
  1282. } else if (mkdir(ipath, S_IRUSR) < 0) {
  1283. if (errno == EEXIST)
  1284. return PAM_IGNORE;
  1285. else {
  1286. pam_syslog(idata->pamh, LOG_ERR, "Error creating %s, %m",
  1287. ipath);
  1288. return PAM_SESSION_ERR;
  1289. }
  1290. }
  1291. /* Open a descriptor to it to prevent races */
  1292. fd = open(ipath, O_DIRECTORY | O_RDONLY);
  1293. if (fd < 0) {
  1294. pam_syslog(idata->pamh, LOG_ERR, "Error opening %s, %m", ipath);
  1295. rmdir(ipath);
  1296. return PAM_SESSION_ERR;
  1297. }
  1298. #ifdef WITH_SELINUX
  1299. /* If SE Linux is disabled, no need to label it */
  1300. if (idata->flags & PAMNS_SELINUX_ENABLED) {
  1301. /* If method is USER, icontext is NULL */
  1302. if (icontext) {
  1303. if (fsetfilecon(fd, icontext) < 0) {
  1304. pam_syslog(idata->pamh, LOG_ERR,
  1305. "Error setting context of %s to %s", ipath, icontext);
  1306. close(fd);
  1307. rmdir(ipath);
  1308. return PAM_SESSION_ERR;
  1309. }
  1310. } else {
  1311. if (fsetfilecon(fd, ocontext) < 0) {
  1312. pam_syslog(idata->pamh, LOG_ERR,
  1313. "Error setting context of %s to %s", ipath, ocontext);
  1314. close(fd);
  1315. rmdir(ipath);
  1316. return PAM_SESSION_ERR;
  1317. }
  1318. }
  1319. }
  1320. #endif
  1321. if (fstat(fd, &newstatbuf) < 0) {
  1322. pam_syslog(idata->pamh, LOG_ERR, "Error stating %s, %m",
  1323. ipath);
  1324. close(fd);
  1325. rmdir(ipath);
  1326. return PAM_SESSION_ERR;
  1327. }
  1328. if (newstatbuf.st_uid != statbuf->st_uid ||
  1329. newstatbuf.st_gid != statbuf->st_gid) {
  1330. if (fchown(fd, statbuf->st_uid, statbuf->st_gid) < 0) {
  1331. pam_syslog(idata->pamh, LOG_ERR,
  1332. "Error changing owner for %s, %m",
  1333. ipath);
  1334. close(fd);
  1335. rmdir(ipath);
  1336. return PAM_SESSION_ERR;
  1337. }
  1338. }
  1339. if (fchmod(fd, statbuf->st_mode & 07777) < 0) {
  1340. pam_syslog(idata->pamh, LOG_ERR, "Error changing mode for %s, %m",
  1341. ipath);
  1342. close(fd);
  1343. rmdir(ipath);
  1344. return PAM_SESSION_ERR;
  1345. }
  1346. close(fd);
  1347. return PAM_SUCCESS;
  1348. }
  1349. /*
  1350. * This function performs the namespace setup for a particular directory
  1351. * that is being polyinstantiated. It calls poly_name to create name of instance
  1352. * directory, calls create_instance to mkdir it with appropriate
  1353. * security attributes, and performs bind mount to setup the process
  1354. * namespace.
  1355. */
  1356. static int ns_setup(struct polydir_s *polyptr,
  1357. struct instance_data *idata)
  1358. {
  1359. int retval;
  1360. int newdir = 1;
  1361. char *inst_dir = NULL;
  1362. char *instname = NULL;
  1363. struct stat statbuf;
  1364. #ifdef WITH_SELINUX
  1365. char *instcontext = NULL, *origcontext = NULL;
  1366. #endif
  1367. if (idata->flags & PAMNS_DEBUG)
  1368. pam_syslog(idata->pamh, LOG_DEBUG,
  1369. "Set namespace for directory %s", polyptr->dir);
  1370. retval = protect_dir(polyptr->dir, 0, 0, idata);
  1371. if (retval < 0 && errno != ENOENT) {
  1372. pam_syslog(idata->pamh, LOG_ERR, "Polydir %s access error: %m",
  1373. polyptr->dir);
  1374. return PAM_SESSION_ERR;
  1375. }
  1376. if (retval < 0) {
  1377. if ((polyptr->flags & POLYDIR_CREATE) &&
  1378. create_polydir(polyptr, idata) != PAM_SUCCESS)
  1379. return PAM_SESSION_ERR;
  1380. } else {
  1381. close(retval);
  1382. }
  1383. if (polyptr->method == TMPFS) {
  1384. if (mount("tmpfs", polyptr->dir, "tmpfs", polyptr->mount_flags, polyptr->mount_opts) < 0) {
  1385. pam_syslog(idata->pamh, LOG_ERR, "Error mounting tmpfs on %s, %m",
  1386. polyptr->dir);
  1387. return PAM_SESSION_ERR;
  1388. }
  1389. if (polyptr->flags & POLYDIR_NOINIT)
  1390. return PAM_SUCCESS;
  1391. return inst_init(polyptr, "tmpfs", idata, 1);
  1392. }
  1393. if (stat(polyptr->dir, &statbuf) < 0) {
  1394. pam_syslog(idata->pamh, LOG_ERR, "Error stating %s: %m",
  1395. polyptr->dir);
  1396. return PAM_SESSION_ERR;
  1397. }
  1398. /*
  1399. * Obtain the name of instance pathname based on the
  1400. * polyinstantiation method and instance context returned by
  1401. * security policy.
  1402. */
  1403. #ifdef WITH_SELINUX
  1404. retval = poly_name(polyptr, &instname, &instcontext,
  1405. &origcontext, idata);
  1406. #else
  1407. retval = poly_name(polyptr, &instname, idata);
  1408. #endif
  1409. if (retval != PAM_SUCCESS) {
  1410. if (retval != PAM_IGNORE)
  1411. pam_syslog(idata->pamh, LOG_ERR, "Error getting instance name");
  1412. goto cleanup;
  1413. } else {
  1414. #ifdef WITH_SELINUX
  1415. if ((idata->flags & PAMNS_DEBUG) &&
  1416. (idata->flags & PAMNS_SELINUX_ENABLED))
  1417. pam_syslog(idata->pamh, LOG_DEBUG, "Inst ctxt %s Orig ctxt %s",
  1418. instcontext, origcontext);
  1419. #endif
  1420. }
  1421. if (asprintf(&inst_dir, "%s%s", polyptr->instance_prefix, instname) < 0)
  1422. goto error_out;
  1423. if (idata->flags & PAMNS_DEBUG)
  1424. pam_syslog(idata->pamh, LOG_DEBUG, "instance_dir %s",
  1425. inst_dir);
  1426. /*
  1427. * Create instance directory with appropriate security
  1428. * contexts, owner, group and mode bits.
  1429. */
  1430. #ifdef WITH_SELINUX
  1431. retval = create_instance(polyptr, inst_dir, &statbuf, instcontext,
  1432. origcontext, idata);
  1433. #else
  1434. retval = create_instance(polyptr, inst_dir, &statbuf, idata);
  1435. #endif
  1436. if (retval == PAM_IGNORE) {
  1437. newdir = 0;
  1438. retval = PAM_SUCCESS;
  1439. }
  1440. if (retval != PAM_SUCCESS) {
  1441. goto error_out;
  1442. }
  1443. /*
  1444. * Bind mount instance directory on top of the polyinstantiated
  1445. * directory to provide an instance of polyinstantiated directory
  1446. * based on polyinstantiated method.
  1447. */
  1448. if (mount(inst_dir, polyptr->dir, NULL, MS_BIND, NULL) < 0) {
  1449. pam_syslog(idata->pamh, LOG_ERR, "Error mounting %s on %s, %m",
  1450. inst_dir, polyptr->dir);
  1451. goto error_out;
  1452. }
  1453. if (!(polyptr->flags & POLYDIR_NOINIT))
  1454. retval = inst_init(polyptr, inst_dir, idata, newdir);
  1455. goto cleanup;
  1456. /*
  1457. * various error exit points. Free allocated memory and set return
  1458. * value to indicate a pam session error.
  1459. */
  1460. error_out:
  1461. retval = PAM_SESSION_ERR;
  1462. cleanup:
  1463. free(inst_dir);
  1464. free(instname);
  1465. #ifdef WITH_SELINUX
  1466. freecon(instcontext);
  1467. freecon(origcontext);
  1468. #endif
  1469. return retval;
  1470. }
  1471. /*
  1472. * This function checks to see if the current working directory is
  1473. * inside the directory passed in as the first argument.
  1474. */
  1475. static int cwd_in(char *dir, struct instance_data *idata)
  1476. {
  1477. int retval = 0;
  1478. char cwd[PATH_MAX];
  1479. if (getcwd(cwd, PATH_MAX) == NULL) {
  1480. pam_syslog(idata->pamh, LOG_ERR, "Can't get current dir, %m");
  1481. return -1;
  1482. }
  1483. if (strncmp(cwd, dir, strlen(dir)) == 0) {
  1484. if (idata->flags & PAMNS_DEBUG)
  1485. pam_syslog(idata->pamh, LOG_DEBUG, "cwd is inside %s", dir);
  1486. retval = 1;
  1487. } else {
  1488. if (idata->flags & PAMNS_DEBUG)
  1489. pam_syslog(idata->pamh, LOG_DEBUG, "cwd is outside %s", dir);
  1490. }
  1491. return retval;
  1492. }
  1493. static int cleanup_tmpdirs(struct instance_data *idata)
  1494. {
  1495. struct polydir_s *pptr;
  1496. pid_t rc, pid;
  1497. struct sigaction newsa, oldsa;
  1498. int status;
  1499. memset(&newsa, '\0', sizeof(newsa));
  1500. newsa.sa_handler = SIG_DFL;
  1501. if (sigaction(SIGCHLD, &newsa, &oldsa) == -1) {
  1502. pam_syslog(idata->pamh, LOG_ERR, "Cannot set signal value");
  1503. return PAM_SESSION_ERR;
  1504. }
  1505. for (pptr = idata->polydirs_ptr; pptr; pptr = pptr->next) {
  1506. if (pptr->method == TMPDIR && access(pptr->instance_prefix, F_OK) == 0) {
  1507. pid = fork();
  1508. if (pid == 0) {
  1509. static char *envp[] = { NULL };
  1510. #ifdef WITH_SELINUX
  1511. if (idata->flags & PAMNS_SELINUX_ENABLED) {
  1512. if (setexeccon(NULL) < 0)
  1513. _exit(1);
  1514. }
  1515. #endif
  1516. if (execle("/bin/rm", "/bin/rm", "-rf", pptr->instance_prefix, NULL, envp) < 0)
  1517. _exit(1);
  1518. } else if (pid > 0) {
  1519. while (((rc = waitpid(pid, &status, 0)) == (pid_t)-1) &&
  1520. (errno == EINTR));
  1521. if (rc == (pid_t)-1) {
  1522. pam_syslog(idata->pamh, LOG_ERR, "waitpid failed: %m");
  1523. rc = PAM_SESSION_ERR;
  1524. goto out;
  1525. }
  1526. if (!WIFEXITED(status) || WIFSIGNALED(status) > 0) {
  1527. pam_syslog(idata->pamh, LOG_ERR,
  1528. "Error removing %s", pptr->instance_prefix);
  1529. }
  1530. } else if (pid < 0) {
  1531. pam_syslog(idata->pamh, LOG_ERR,
  1532. "Cannot fork to run namespace init script, %m");
  1533. rc = PAM_SESSION_ERR;
  1534. goto out;
  1535. }
  1536. }
  1537. }
  1538. rc = PAM_SUCCESS;
  1539. out:
  1540. sigaction(SIGCHLD, &oldsa, NULL);
  1541. return rc;
  1542. }
  1543. /*
  1544. * This function checks to see if polyinstantiation is needed for any
  1545. * of the directories listed in the configuration file. If needed,
  1546. * cycles through all polyinstantiated directory entries and calls
  1547. * ns_setup to setup polyinstantiation for each one of them.
  1548. */
  1549. static int setup_namespace(struct instance_data *idata, enum unmnt_op unmnt)
  1550. {
  1551. int retval = 0, need_poly = 0, changing_dir = 0;
  1552. char *cptr, *fptr, poly_parent[PATH_MAX];
  1553. struct polydir_s *pptr;
  1554. if (idata->flags & PAMNS_DEBUG)
  1555. pam_syslog(idata->pamh, LOG_DEBUG, "Set up namespace for pid %d",
  1556. getpid());
  1557. /*
  1558. * Cycle through all polyinstantiated directory entries to see if
  1559. * polyinstantiation is needed at all.
  1560. */
  1561. for (pptr = idata->polydirs_ptr; pptr; pptr = pptr->next) {
  1562. if (ns_override(pptr, idata, idata->uid)) {
  1563. if (unmnt == NO_UNMNT || ns_override(pptr, idata, idata->ruid)) {
  1564. if (idata->flags & PAMNS_DEBUG)
  1565. pam_syslog(idata->pamh, LOG_DEBUG,
  1566. "Overriding poly for user %d for dir %s",
  1567. idata->uid, pptr->dir);
  1568. } else {
  1569. if (idata->flags & PAMNS_DEBUG)
  1570. pam_syslog(idata->pamh, LOG_DEBUG,
  1571. "Need unmount ns for user %d for dir %s",
  1572. idata->ruid, pptr->dir);
  1573. need_poly = 1;
  1574. break;
  1575. }
  1576. continue;
  1577. } else {
  1578. if (idata->flags & PAMNS_DEBUG)
  1579. pam_syslog(idata->pamh, LOG_DEBUG,
  1580. "Need poly ns for user %d for dir %s",
  1581. idata->uid, pptr->dir);
  1582. need_poly = 1;
  1583. break;
  1584. }
  1585. }
  1586. /*
  1587. * If polyinstantiation is needed, call the unshare system call to
  1588. * disassociate from the parent namespace.
  1589. */
  1590. if (need_poly) {
  1591. if (unshare(CLONE_NEWNS) < 0) {
  1592. pam_syslog(idata->pamh, LOG_ERR,
  1593. "Unable to unshare from parent namespace, %m");
  1594. return PAM_SESSION_ERR;
  1595. }
  1596. if (idata->flags & PAMNS_MOUNT_PRIVATE) {
  1597. /*
  1598. * Remount / as SLAVE so that nothing mounted in the namespace
  1599. * shows up in the parent
  1600. */
  1601. if (mount("/", "/", NULL, MS_SLAVE | MS_REC , NULL) < 0) {
  1602. pam_syslog(idata->pamh, LOG_ERR,
  1603. "Failed to mark / as a slave mount point, %m");
  1604. return PAM_SESSION_ERR;
  1605. }
  1606. if (idata->flags & PAMNS_DEBUG)
  1607. pam_syslog(idata->pamh, LOG_DEBUG,
  1608. "The / mount point was marked as slave");
  1609. }
  1610. } else {
  1611. del_polydir_list(idata->polydirs_ptr);
  1612. return PAM_SUCCESS;
  1613. }
  1614. /*
  1615. * Again cycle through all polyinstantiated directories, this time,
  1616. * call ns_setup to setup polyinstantiation for a particular entry.
  1617. */
  1618. for (pptr = idata->polydirs_ptr; pptr; pptr = pptr->next) {
  1619. enum unmnt_op dir_unmnt = unmnt;
  1620. if (ns_override(pptr, idata, idata->ruid)) {
  1621. dir_unmnt = NO_UNMNT;
  1622. }
  1623. if (ns_override(pptr, idata, idata->uid)) {
  1624. if (dir_unmnt == NO_UNMNT) {
  1625. continue;
  1626. } else {
  1627. dir_unmnt = UNMNT_ONLY;
  1628. }
  1629. }
  1630. if (idata->flags & PAMNS_DEBUG)
  1631. pam_syslog(idata->pamh, LOG_DEBUG,
  1632. "Setting poly ns for user %d for dir %s",
  1633. idata->uid, pptr->dir);
  1634. if ((dir_unmnt == UNMNT_REMNT) || (dir_unmnt == UNMNT_ONLY)) {
  1635. /*
  1636. * Check to see if process current directory is in the
  1637. * bind mounted instance_parent directory that we are trying to
  1638. * umount
  1639. */
  1640. if ((changing_dir = cwd_in(pptr->rdir, idata)) < 0) {
  1641. retval = PAM_SESSION_ERR;
  1642. goto out;
  1643. } else if (changing_dir) {
  1644. if (idata->flags & PAMNS_DEBUG)
  1645. pam_syslog(idata->pamh, LOG_DEBUG, "changing cwd");
  1646. /*
  1647. * Change current working directory to the parent of
  1648. * the mount point, that is parent of the orig
  1649. * directory where original contents of the polydir
  1650. * are available from
  1651. */
  1652. strcpy(poly_parent, pptr->rdir);
  1653. fptr = strchr(poly_parent, '/');
  1654. cptr = strrchr(poly_parent, '/');
  1655. if (fptr && cptr && (fptr == cptr))
  1656. strcpy(poly_parent, "/");
  1657. else if (cptr)
  1658. *cptr = '\0';
  1659. if (chdir(poly_parent) < 0) {
  1660. pam_syslog(idata->pamh, LOG_ERR,
  1661. "Can't chdir to %s, %m", poly_parent);
  1662. }
  1663. }
  1664. if (umount(pptr->rdir) < 0) {
  1665. int saved_errno = errno;
  1666. pam_syslog(idata->pamh, LOG_ERR, "Unmount of %s failed, %m",
  1667. pptr->rdir);
  1668. if (saved_errno != EINVAL) {
  1669. retval = PAM_SESSION_ERR;
  1670. goto out;
  1671. }
  1672. } else if (idata->flags & PAMNS_DEBUG)
  1673. pam_syslog(idata->pamh, LOG_DEBUG, "Umount succeeded %s",
  1674. pptr->rdir);
  1675. }
  1676. if (dir_unmnt != UNMNT_ONLY) {
  1677. retval = ns_setup(pptr, idata);
  1678. if (retval == PAM_IGNORE)
  1679. retval = PAM_SUCCESS;
  1680. if (retval != PAM_SUCCESS)
  1681. break;
  1682. }
  1683. }
  1684. out:
  1685. if (retval != PAM_SUCCESS) {
  1686. cleanup_tmpdirs(idata);
  1687. unprotect_dirs(idata->protect_dirs);
  1688. } else if (pam_set_data(idata->pamh, NAMESPACE_PROTECT_DATA, idata->protect_dirs,
  1689. cleanup_protect_data) != PAM_SUCCESS) {
  1690. pam_syslog(idata->pamh, LOG_ERR, "Unable to set namespace protect data");
  1691. cleanup_tmpdirs(idata);
  1692. unprotect_dirs(idata->protect_dirs);
  1693. return PAM_SYSTEM_ERR;
  1694. } else if (pam_set_data(idata->pamh, NAMESPACE_POLYDIR_DATA, idata->polydirs_ptr,
  1695. cleanup_polydir_data) != PAM_SUCCESS) {
  1696. pam_syslog(idata->pamh, LOG_ERR, "Unable to set namespace polydir data");
  1697. cleanup_tmpdirs(idata);
  1698. pam_set_data(idata->pamh, NAMESPACE_PROTECT_DATA, NULL, NULL);
  1699. idata->protect_dirs = NULL;
  1700. return PAM_SYSTEM_ERR;
  1701. }
  1702. return retval;
  1703. }
  1704. /*
  1705. * Orig namespace. This function is called from when closing a pam
  1706. * session. If authorized, it unmounts instance directory.
  1707. */
  1708. static int orig_namespace(struct instance_data *idata)
  1709. {
  1710. struct polydir_s *pptr;
  1711. if (idata->flags & PAMNS_DEBUG)
  1712. pam_syslog(idata->pamh, LOG_DEBUG, "orig namespace for pid %d",
  1713. getpid());
  1714. /*
  1715. * Cycle through all polyinstantiated directories from the namespace
  1716. * configuration file to see if polyinstantiation was performed for
  1717. * this user for each of the entry. If it was, try and unmount
  1718. * appropriate polyinstantiated instance directories.
  1719. */
  1720. for (pptr = idata->polydirs_ptr; pptr; pptr = pptr->next) {
  1721. if (ns_override(pptr, idata, idata->uid))
  1722. continue;
  1723. else {
  1724. if (idata->flags & PAMNS_DEBUG)
  1725. pam_syslog(idata->pamh, LOG_DEBUG,
  1726. "Unmounting instance dir for user %d & dir %s",
  1727. idata->uid, pptr->dir);
  1728. if (umount(pptr->dir) < 0) {
  1729. pam_syslog(idata->pamh, LOG_ERR, "Unmount of %s failed, %m",
  1730. pptr->dir);
  1731. return PAM_SESSION_ERR;
  1732. } else if (idata->flags & PAMNS_DEBUG)
  1733. pam_syslog(idata->pamh, LOG_DEBUG, "Unmount of %s succeeded",
  1734. pptr->dir);
  1735. }
  1736. }
  1737. cleanup_tmpdirs(idata);
  1738. return 0;
  1739. }
  1740. #ifdef WITH_SELINUX
  1741. /*
  1742. * This function checks if the calling program has requested context
  1743. * change by calling setexeccon(). If context change is not requested
  1744. * then it does not make sense to polyinstantiate based on context.
  1745. * The return value from this function is used when selecting the
  1746. * polyinstantiation method. If context change is not requested then
  1747. * the polyinstantiation method is set to USER, even if the configuration
  1748. * file lists the method as "context" or "level".
  1749. */
  1750. static int ctxt_based_inst_needed(void)
  1751. {
  1752. char *scon = NULL;
  1753. int rc = 0;
  1754. rc = getexeccon(&scon);
  1755. if (rc < 0 || scon == NULL)
  1756. return 0;
  1757. else {
  1758. freecon(scon);
  1759. return 1;
  1760. }
  1761. }
  1762. #endif
  1763. static int root_shared(void)
  1764. {
  1765. FILE *f;
  1766. char *line = NULL;
  1767. size_t n = 0;
  1768. int rv = 0;
  1769. f = fopen("/proc/self/mountinfo", "r");
  1770. if (f == NULL)
  1771. return 0;
  1772. while(getline(&line, &n, f) != -1) {
  1773. char *l;
  1774. char *sptr;
  1775. int i;
  1776. l = line;
  1777. sptr = NULL;
  1778. for (i = 0; i < 7; i++) {
  1779. char *tok;
  1780. tok = strtok_r(l, " ", &sptr);
  1781. l = NULL;
  1782. if (tok == NULL)
  1783. /* next mountinfo line */
  1784. break;
  1785. if (i == 4 && strcmp(tok, "/") != 0)
  1786. /* next mountinfo line */
  1787. break;
  1788. if (i == 6) {
  1789. if (pam_str_skip_prefix(tok, "shared:") != NULL)
  1790. /* there might be more / mounts, the last one counts */
  1791. rv = 1;
  1792. else
  1793. rv = 0;
  1794. }
  1795. }
  1796. }
  1797. free(line);
  1798. fclose(f);
  1799. return rv;
  1800. }
  1801. static int get_user_data(struct instance_data *idata)
  1802. {
  1803. int retval;
  1804. char *user_name;
  1805. struct passwd *pwd;
  1806. /*
  1807. * Lookup user and fill struct items
  1808. */
  1809. retval = pam_get_item(idata->pamh, PAM_USER, (void*) &user_name );
  1810. if ( user_name == NULL || retval != PAM_SUCCESS ) {
  1811. pam_syslog(idata->pamh, LOG_ERR, "Error recovering pam user name");
  1812. return PAM_SESSION_ERR;
  1813. }
  1814. pwd = pam_modutil_getpwnam(idata->pamh, user_name);
  1815. if (!pwd) {
  1816. pam_syslog(idata->pamh, LOG_ERR, "user unknown '%s'", user_name);
  1817. return PAM_USER_UNKNOWN;
  1818. }
  1819. /*
  1820. * Add the user info to the instance data so we can refer to them later.
  1821. */
  1822. idata->user[0] = 0;
  1823. strncat(idata->user, user_name, sizeof(idata->user) - 1);
  1824. idata->uid = pwd->pw_uid;
  1825. idata->gid = pwd->pw_gid;
  1826. /* Fill in RUSER too */
  1827. retval = pam_get_item(idata->pamh, PAM_RUSER, (void*) &user_name );
  1828. if ( user_name != NULL && retval == PAM_SUCCESS && user_name[0] != '\0' ) {
  1829. strncat(idata->ruser, user_name, sizeof(idata->ruser) - 1);
  1830. pwd = pam_modutil_getpwnam(idata->pamh, user_name);
  1831. } else {
  1832. pwd = pam_modutil_getpwuid(idata->pamh, getuid());
  1833. }
  1834. if (!pwd) {
  1835. pam_syslog(idata->pamh, LOG_ERR, "user unknown '%s'", user_name);
  1836. return PAM_USER_UNKNOWN;
  1837. }
  1838. user_name = pwd->pw_name;
  1839. idata->ruser[0] = 0;
  1840. strncat(idata->ruser, user_name, sizeof(idata->ruser) - 1);
  1841. idata->ruid = pwd->pw_uid;
  1842. return PAM_SUCCESS;
  1843. }
  1844. /*
  1845. * Entry point from pam_open_session call.
  1846. */
  1847. int pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED,
  1848. int argc, const char **argv)
  1849. {
  1850. int i, retval;
  1851. struct instance_data idata;
  1852. enum unmnt_op unmnt = NO_UNMNT;
  1853. /* init instance data */
  1854. idata.flags = 0;
  1855. idata.polydirs_ptr = NULL;
  1856. idata.protect_dirs = NULL;
  1857. idata.pamh = pamh;
  1858. #ifdef WITH_SELINUX
  1859. if (is_selinux_enabled())
  1860. idata.flags |= PAMNS_SELINUX_ENABLED;
  1861. if (ctxt_based_inst_needed())
  1862. idata.flags |= PAMNS_CTXT_BASED_INST;
  1863. #endif
  1864. /* Parse arguments. */
  1865. for (i = 0; i < argc; i++) {
  1866. if (strcmp(argv[i], "debug") == 0)
  1867. idata.flags |= PAMNS_DEBUG;
  1868. if (strcmp(argv[i], "gen_hash") == 0)
  1869. idata.flags |= PAMNS_GEN_HASH;
  1870. if (strcmp(argv[i], "ignore_config_error") == 0)
  1871. idata.flags |= PAMNS_IGN_CONFIG_ERR;
  1872. if (strcmp(argv[i], "ignore_instance_parent_mode") == 0)
  1873. idata.flags |= PAMNS_IGN_INST_PARENT_MODE;
  1874. if (strcmp(argv[i], "use_current_context") == 0) {
  1875. idata.flags |= PAMNS_USE_CURRENT_CONTEXT;
  1876. idata.flags |= PAMNS_CTXT_BASED_INST;
  1877. }
  1878. if (strcmp(argv[i], "use_default_context") == 0) {
  1879. idata.flags |= PAMNS_USE_DEFAULT_CONTEXT;
  1880. idata.flags |= PAMNS_CTXT_BASED_INST;
  1881. }
  1882. if (strcmp(argv[i], "mount_private") == 0) {
  1883. idata.flags |= PAMNS_MOUNT_PRIVATE;
  1884. }
  1885. if (strcmp(argv[i], "unmnt_remnt") == 0)
  1886. unmnt = UNMNT_REMNT;
  1887. if (strcmp(argv[i], "unmnt_only") == 0)
  1888. unmnt = UNMNT_ONLY;
  1889. if (strcmp(argv[i], "require_selinux") == 0) {
  1890. if (!(idata.flags & PAMNS_SELINUX_ENABLED)) {
  1891. pam_syslog(idata.pamh, LOG_ERR,
  1892. "selinux_required option given and selinux is disabled");
  1893. return PAM_SESSION_ERR;
  1894. }
  1895. }
  1896. }
  1897. if (idata.flags & PAMNS_DEBUG)
  1898. pam_syslog(idata.pamh, LOG_DEBUG, "open_session - start");
  1899. retval = get_user_data(&idata);
  1900. if (retval != PAM_SUCCESS)
  1901. return retval;
  1902. if (root_shared()) {
  1903. idata.flags |= PAMNS_MOUNT_PRIVATE;
  1904. }
  1905. /*
  1906. * Parse namespace configuration file which lists directories to
  1907. * polyinstantiate, directory where instance directories are to
  1908. * be created and the method used for polyinstantiation.
  1909. */
  1910. retval = parse_config_file(&idata);
  1911. if (retval != PAM_SUCCESS) {
  1912. del_polydir_list(idata.polydirs_ptr);
  1913. return PAM_SESSION_ERR;
  1914. }
  1915. if (idata.polydirs_ptr) {
  1916. retval = setup_namespace(&idata, unmnt);
  1917. if (idata.flags & PAMNS_DEBUG) {
  1918. if (retval)
  1919. pam_syslog(idata.pamh, LOG_DEBUG,
  1920. "namespace setup failed for pid %d", getpid());
  1921. else
  1922. pam_syslog(idata.pamh, LOG_DEBUG,
  1923. "namespace setup ok for pid %d", getpid());
  1924. }
  1925. } else if (idata.flags & PAMNS_DEBUG)
  1926. pam_syslog(idata.pamh, LOG_DEBUG, "Nothing to polyinstantiate");
  1927. if (retval != PAM_SUCCESS)
  1928. del_polydir_list(idata.polydirs_ptr);
  1929. return retval;
  1930. }
  1931. /*
  1932. * Entry point from pam_close_session call.
  1933. */
  1934. int pam_sm_close_session(pam_handle_t *pamh, int flags UNUSED,
  1935. int argc, const char **argv)
  1936. {
  1937. int i, retval;
  1938. struct instance_data idata;
  1939. const void *polyptr;
  1940. /* init instance data */
  1941. idata.flags = 0;
  1942. idata.polydirs_ptr = NULL;
  1943. idata.pamh = pamh;
  1944. #ifdef WITH_SELINUX
  1945. if (is_selinux_enabled())
  1946. idata.flags |= PAMNS_SELINUX_ENABLED;
  1947. if (ctxt_based_inst_needed())
  1948. idata.flags |= PAMNS_CTXT_BASED_INST;
  1949. #endif
  1950. /* Parse arguments. */
  1951. for (i = 0; i < argc; i++) {
  1952. if (strcmp(argv[i], "debug") == 0)
  1953. idata.flags |= PAMNS_DEBUG;
  1954. if (strcmp(argv[i], "ignore_config_error") == 0)
  1955. idata.flags |= PAMNS_IGN_CONFIG_ERR;
  1956. if (strcmp(argv[i], "unmount_on_close") == 0)
  1957. idata.flags |= PAMNS_UNMOUNT_ON_CLOSE;
  1958. }
  1959. if (idata.flags & PAMNS_DEBUG)
  1960. pam_syslog(idata.pamh, LOG_DEBUG, "close_session - start");
  1961. /*
  1962. * Normally the unmount is implicitly done when the last
  1963. * process in the private namespace exits.
  1964. * If it is ensured that there are no child processes left in
  1965. * the private namespace by other means and if there are
  1966. * multiple sessions opened and closed sequentially by the
  1967. * same process, the "unmount_on_close" option might be
  1968. * used to unmount the polydirs explicitly.
  1969. */
  1970. if (!(idata.flags & PAMNS_UNMOUNT_ON_CLOSE)) {
  1971. pam_set_data(idata.pamh, NAMESPACE_POLYDIR_DATA, NULL, NULL);
  1972. pam_set_data(idata.pamh, NAMESPACE_PROTECT_DATA, NULL, NULL);
  1973. if (idata.flags & PAMNS_DEBUG)
  1974. pam_syslog(idata.pamh, LOG_DEBUG, "close_session - successful");
  1975. return PAM_SUCCESS;
  1976. }
  1977. retval = get_user_data(&idata);
  1978. if (retval != PAM_SUCCESS)
  1979. return retval;
  1980. retval = pam_get_data(idata.pamh, NAMESPACE_POLYDIR_DATA, &polyptr);
  1981. if (retval != PAM_SUCCESS || polyptr == NULL)
  1982. /* nothing to reset */
  1983. return PAM_SUCCESS;
  1984. DIAG_PUSH_IGNORE_CAST_QUAL;
  1985. idata.polydirs_ptr = (void *)polyptr;
  1986. DIAG_POP_IGNORE_CAST_QUAL;
  1987. if (idata.flags & PAMNS_DEBUG)
  1988. pam_syslog(idata.pamh, LOG_DEBUG, "Resetting namespace for pid %d",
  1989. getpid());
  1990. retval = orig_namespace(&idata);
  1991. if (idata.flags & PAMNS_DEBUG) {
  1992. if (retval)
  1993. pam_syslog(idata.pamh, LOG_DEBUG,
  1994. "resetting namespace failed for pid %d", getpid());
  1995. else
  1996. pam_syslog(idata.pamh, LOG_DEBUG,
  1997. "resetting namespace ok for pid %d", getpid());
  1998. }
  1999. pam_set_data(idata.pamh, NAMESPACE_POLYDIR_DATA, NULL, NULL);
  2000. pam_set_data(idata.pamh, NAMESPACE_PROTECT_DATA, NULL, NULL);
  2001. return PAM_SUCCESS;
  2002. }