pam_handlers.c 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045
  1. /* pam_handlers.c -- pam config file parsing and module loading */
  2. /*
  3. * created by Marc Ewing.
  4. * Currently maintained by Andrew G. Morgan <morgan@kernel.org>
  5. *
  6. */
  7. #include "pam_private.h"
  8. #include "pam_inline.h"
  9. #include <stdlib.h>
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include <sys/types.h>
  13. #include <sys/stat.h>
  14. #include <fcntl.h>
  15. #include <unistd.h>
  16. #define BUF_SIZE 1024
  17. #define MODULE_CHUNK 4
  18. #define UNKNOWN_MODULE "<*unknown module*>"
  19. #ifndef _PAM_ISA
  20. #define _PAM_ISA "."
  21. #endif
  22. static int _pam_assemble_line(FILE *f, char *buf, int buf_len);
  23. static void _pam_free_handlers_aux(struct handler **hp);
  24. static int _pam_add_handler(pam_handle_t *pamh
  25. , int must_fail, int other, int stack_level, int type
  26. , int *actions, const char *mod_path
  27. , int argc, char **argv, int argvlen);
  28. /* Values for module type */
  29. #define PAM_T_ANY 0
  30. #define PAM_T_AUTH 1
  31. #define PAM_T_SESS 2
  32. #define PAM_T_ACCT 4
  33. #define PAM_T_PASS 8
  34. static int _pam_load_conf_file(pam_handle_t *pamh, const char *config_name
  35. , const char *service /* specific file */
  36. , int module_type /* specific type */
  37. , int stack_level /* level of substack */
  38. #ifdef PAM_READ_BOTH_CONFS
  39. , int not_other
  40. #endif /* PAM_READ_BOTH_CONFS */
  41. );
  42. static int _pam_parse_conf_file(pam_handle_t *pamh, FILE *f
  43. , const char *known_service /* specific file */
  44. , int requested_module_type /* specific type */
  45. , int stack_level /* level of substack */
  46. #ifdef PAM_READ_BOTH_CONFS
  47. , int not_other
  48. #endif /* PAM_READ_BOTH_CONFS */
  49. )
  50. {
  51. char buf[BUF_SIZE];
  52. int x; /* read a line from the FILE *f ? */
  53. /*
  54. * read a line from the configuration (FILE *) f
  55. */
  56. while ((x = _pam_assemble_line(f, buf, BUF_SIZE)) > 0) {
  57. char *tok, *nexttok=NULL;
  58. const char *this_service;
  59. const char *mod_path;
  60. int module_type, actions[_PAM_RETURN_VALUES];
  61. int other; /* set if module is for PAM_DEFAULT_SERVICE */
  62. int res; /* module added successfully? */
  63. int handler_type = PAM_HT_MODULE; /* regular handler from a module */
  64. int argc;
  65. char **argv;
  66. int argvlen;
  67. D(("_pam_init_handler: LINE: %s", buf));
  68. if (known_service != NULL) {
  69. nexttok = buf;
  70. /* No service field: all lines are for the known service. */
  71. this_service = known_service;
  72. } else {
  73. this_service = tok = _pam_StrTok(buf, " \n\t", &nexttok);
  74. }
  75. #ifdef PAM_READ_BOTH_CONFS
  76. if (not_other)
  77. other = 0;
  78. else
  79. #endif /* PAM_READ_BOTH_CONFS */
  80. other = !strcasecmp(this_service, PAM_DEFAULT_SERVICE);
  81. /* accept "service name" or PAM_DEFAULT_SERVICE modules */
  82. if (!strcasecmp(this_service, pamh->service_name) || other) {
  83. int pam_include = 0;
  84. int substack = 0;
  85. /* This is a service we are looking for */
  86. D(("_pam_init_handlers: Found PAM config entry for: %s"
  87. , this_service));
  88. tok = _pam_StrTok(NULL, " \n\t", &nexttok);
  89. if (tok == NULL) {
  90. /* module type does not exist */
  91. D(("_pam_init_handlers: empty module type for %s", this_service));
  92. pam_syslog(pamh, LOG_ERR,
  93. "(%s) empty module type", this_service);
  94. module_type = (requested_module_type != PAM_T_ANY) ?
  95. requested_module_type : PAM_T_AUTH; /* most sensitive */
  96. handler_type = PAM_HT_MUST_FAIL; /* install as normal but fail when dispatched */
  97. } else {
  98. if (tok[0] == '-') { /* do not log module load errors */
  99. handler_type = PAM_HT_SILENT_MODULE;
  100. ++tok;
  101. }
  102. if (!strcasecmp("auth", tok)) {
  103. module_type = PAM_T_AUTH;
  104. } else if (!strcasecmp("session", tok)) {
  105. module_type = PAM_T_SESS;
  106. } else if (!strcasecmp("account", tok)) {
  107. module_type = PAM_T_ACCT;
  108. } else if (!strcasecmp("password", tok)) {
  109. module_type = PAM_T_PASS;
  110. } else {
  111. /* Illegal module type */
  112. D(("_pam_init_handlers: bad module type: %s", tok));
  113. pam_syslog(pamh, LOG_ERR, "(%s) illegal module type: %s",
  114. this_service, tok);
  115. module_type = (requested_module_type != PAM_T_ANY) ?
  116. requested_module_type : PAM_T_AUTH; /* most sensitive */
  117. handler_type = PAM_HT_MUST_FAIL; /* install as normal but fail when dispatched */
  118. }
  119. }
  120. D(("Using %s config entry: %s", handler_type?"BAD ":"", tok));
  121. if (requested_module_type != PAM_T_ANY &&
  122. module_type != requested_module_type) {
  123. D(("Skipping config entry: %s (requested=%d, found=%d)",
  124. tok, requested_module_type, module_type));
  125. continue;
  126. }
  127. /* reset the actions to .._UNDEF's -- this is so that
  128. we can work out which entries are not yet set (for default). */
  129. {
  130. int i;
  131. for (i=0; i<_PAM_RETURN_VALUES;
  132. actions[i++] = _PAM_ACTION_UNDEF);
  133. }
  134. tok = _pam_StrTok(NULL, " \n\t", &nexttok);
  135. if (tok == NULL) {
  136. /* no module name given */
  137. D(("_pam_init_handlers: no control flag supplied"));
  138. pam_syslog(pamh, LOG_ERR,
  139. "(%s) no control flag supplied", this_service);
  140. _pam_set_default_control(actions, _PAM_ACTION_BAD);
  141. handler_type = PAM_HT_MUST_FAIL;
  142. } else if (!strcasecmp("required", tok)) {
  143. D(("*PAM_F_REQUIRED*"));
  144. actions[PAM_SUCCESS] = _PAM_ACTION_OK;
  145. actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
  146. actions[PAM_IGNORE] = _PAM_ACTION_IGNORE;
  147. _pam_set_default_control(actions, _PAM_ACTION_BAD);
  148. } else if (!strcasecmp("requisite", tok)) {
  149. D(("*PAM_F_REQUISITE*"));
  150. actions[PAM_SUCCESS] = _PAM_ACTION_OK;
  151. actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
  152. actions[PAM_IGNORE] = _PAM_ACTION_IGNORE;
  153. _pam_set_default_control(actions, _PAM_ACTION_DIE);
  154. } else if (!strcasecmp("optional", tok)) {
  155. D(("*PAM_F_OPTIONAL*"));
  156. actions[PAM_SUCCESS] = _PAM_ACTION_OK;
  157. actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
  158. _pam_set_default_control(actions, _PAM_ACTION_IGNORE);
  159. } else if (!strcasecmp("sufficient", tok)) {
  160. D(("*PAM_F_SUFFICIENT*"));
  161. actions[PAM_SUCCESS] = _PAM_ACTION_DONE;
  162. actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_DONE;
  163. _pam_set_default_control(actions, _PAM_ACTION_IGNORE);
  164. } else if (!strcasecmp("include", tok)) {
  165. D(("*PAM_F_INCLUDE*"));
  166. pam_include = 1;
  167. substack = 0;
  168. } else if (!strcasecmp("substack", tok)) {
  169. D(("*PAM_F_SUBSTACK*"));
  170. pam_include = 1;
  171. substack = 1;
  172. } else {
  173. D(("will need to parse %s", tok));
  174. _pam_parse_control(actions, tok);
  175. /* by default the default is to treat as failure */
  176. _pam_set_default_control(actions, _PAM_ACTION_BAD);
  177. }
  178. tok = _pam_StrTok(NULL, " \n\t", &nexttok);
  179. if (pam_include) {
  180. if (substack) {
  181. res = _pam_add_handler(pamh, PAM_HT_SUBSTACK, other,
  182. stack_level, module_type, actions, tok,
  183. 0, NULL, 0);
  184. if (res != PAM_SUCCESS) {
  185. pam_syslog(pamh, LOG_ERR, "error adding substack %s", tok);
  186. D(("failed to load module - aborting"));
  187. return PAM_ABORT;
  188. }
  189. }
  190. if (_pam_load_conf_file(pamh, tok, this_service, module_type,
  191. stack_level + substack
  192. #ifdef PAM_READ_BOTH_CONFS
  193. , !other
  194. #endif /* PAM_READ_BOTH_CONFS */
  195. ) == PAM_SUCCESS)
  196. continue;
  197. _pam_set_default_control(actions, _PAM_ACTION_BAD);
  198. mod_path = NULL;
  199. handler_type = PAM_HT_MUST_FAIL;
  200. nexttok = NULL;
  201. } else if (tok != NULL) {
  202. mod_path = tok;
  203. D(("mod_path = %s",mod_path));
  204. } else {
  205. /* no module name given */
  206. D(("_pam_init_handlers: no module name supplied"));
  207. pam_syslog(pamh, LOG_ERR,
  208. "(%s) no module name supplied", this_service);
  209. mod_path = NULL;
  210. handler_type = PAM_HT_MUST_FAIL;
  211. }
  212. /* nexttok points to remaining arguments... */
  213. if (nexttok != NULL) {
  214. D(("list: %s",nexttok));
  215. argvlen = _pam_mkargv(nexttok, &argv, &argc);
  216. D(("argvlen = %d",argvlen));
  217. } else { /* there are no arguments so fix by hand */
  218. D(("_pam_init_handlers: empty argument list"));
  219. argvlen = argc = 0;
  220. argv = NULL;
  221. }
  222. #ifdef PAM_DEBUG
  223. {
  224. int y;
  225. D(("CONF%s: %s%s %d %s %d"
  226. , handler_type==PAM_HT_MUST_FAIL?"<*will fail*>":""
  227. , this_service, other ? "(backup)":""
  228. , module_type
  229. , mod_path, argc));
  230. for (y = 0; y < argc; y++) {
  231. D(("CONF: %s", argv[y]));
  232. }
  233. for (y = 0; y<_PAM_RETURN_VALUES; ++y) {
  234. D(("RETURN %s(%d) -> %d %s",
  235. _pam_token_returns[y], y, actions[y],
  236. actions[y]>0 ? "jump":
  237. _pam_token_actions[-actions[y]]));
  238. }
  239. }
  240. #endif
  241. res = _pam_add_handler(pamh, handler_type, other, stack_level
  242. , module_type, actions, mod_path
  243. , argc, argv, argvlen);
  244. if (res != PAM_SUCCESS) {
  245. pam_syslog(pamh, LOG_ERR, "error loading %s", mod_path);
  246. D(("failed to load module - aborting"));
  247. return PAM_ABORT;
  248. }
  249. }
  250. }
  251. return ( (x < 0) ? PAM_ABORT:PAM_SUCCESS );
  252. }
  253. static int
  254. _pam_open_config_file(pam_handle_t *pamh
  255. , const char *service
  256. , char **path
  257. , FILE **file)
  258. {
  259. const char *pamd_dirs[] = { PAM_CONFIG_DF, PAM_CONFIG_DIST_DF
  260. #ifdef VENDORDIR
  261. , PAM_CONFIG_DIST2_DF
  262. #endif
  263. };
  264. char *p = NULL;
  265. FILE *f;
  266. size_t i;
  267. /* Absolute path */
  268. if (service[0] == '/') {
  269. p = _pam_strdup(service);
  270. if (p == NULL) {
  271. pam_syslog(pamh, LOG_CRIT, "strdup failed");
  272. return PAM_BUF_ERR;
  273. }
  274. } else if (pamh->confdir != NULL) {
  275. if (asprintf (&p, "%s/%s", pamh->confdir, service) < 0) {
  276. pam_syslog(pamh, LOG_CRIT, "asprintf failed");
  277. return PAM_BUF_ERR;
  278. }
  279. }
  280. if (p != NULL) {
  281. D(("opening %s", p));
  282. f = fopen(p, "r");
  283. if (f != NULL) {
  284. *path = p;
  285. *file = f;
  286. return PAM_SUCCESS;
  287. }
  288. _pam_drop(p);
  289. return PAM_ABORT;
  290. }
  291. for (i = 0; i < PAM_ARRAY_SIZE(pamd_dirs); i++) {
  292. if (asprintf (&p, pamd_dirs[i], service) < 0) {
  293. pam_syslog(pamh, LOG_CRIT, "asprintf failed");
  294. return PAM_BUF_ERR;
  295. }
  296. D(("opening %s", p));
  297. f = fopen(p, "r");
  298. if (f != NULL) {
  299. *path = p;
  300. *file = f;
  301. return PAM_SUCCESS;
  302. }
  303. _pam_drop(p);
  304. }
  305. return PAM_ABORT;
  306. }
  307. static int _pam_load_conf_file(pam_handle_t *pamh, const char *config_name
  308. , const char *service /* specific file */
  309. , int module_type /* specific type */
  310. , int stack_level /* level of substack */
  311. #ifdef PAM_READ_BOTH_CONFS
  312. , int not_other
  313. #endif /* PAM_READ_BOTH_CONFS */
  314. )
  315. {
  316. FILE *f;
  317. char *path = NULL;
  318. int retval = PAM_ABORT;
  319. D(("_pam_load_conf_file called"));
  320. if (stack_level >= PAM_SUBSTACK_MAX_LEVEL) {
  321. D(("maximum level of substacks reached"));
  322. pam_syslog(pamh, LOG_ERR, "maximum level of substacks reached");
  323. return PAM_ABORT;
  324. }
  325. if (config_name == NULL) {
  326. D(("no config file supplied"));
  327. pam_syslog(pamh, LOG_ERR, "(%s) no config name supplied", service);
  328. return PAM_ABORT;
  329. }
  330. if (_pam_open_config_file(pamh, config_name, &path, &f) == PAM_SUCCESS) {
  331. retval = _pam_parse_conf_file(pamh, f, service, module_type, stack_level
  332. #ifdef PAM_READ_BOTH_CONFS
  333. , not_other
  334. #endif /* PAM_READ_BOTH_CONFS */
  335. );
  336. if (retval != PAM_SUCCESS)
  337. pam_syslog(pamh, LOG_ERR,
  338. "_pam_load_conf_file: error reading %s: %s",
  339. path, pam_strerror(pamh, retval));
  340. _pam_drop(path);
  341. fclose(f);
  342. } else {
  343. D(("unable to open %s", config_name));
  344. pam_syslog(pamh, LOG_ERR,
  345. "_pam_load_conf_file: unable to open config for %s",
  346. config_name);
  347. }
  348. return retval;
  349. }
  350. /* Parse config file, allocate handler structures, dlopen() */
  351. int _pam_init_handlers(pam_handle_t *pamh)
  352. {
  353. FILE *f;
  354. int retval;
  355. D(("_pam_init_handlers called"));
  356. IF_NO_PAMH("_pam_init_handlers",pamh,PAM_SYSTEM_ERR);
  357. /* Return immediately if everything is already loaded */
  358. if (pamh->handlers.handlers_loaded) {
  359. return PAM_SUCCESS;
  360. }
  361. D(("_pam_init_handlers: initializing"));
  362. /* First clean the service structure */
  363. _pam_free_handlers(pamh);
  364. if (! pamh->handlers.module) {
  365. if ((pamh->handlers.module =
  366. malloc(MODULE_CHUNK * sizeof(struct loaded_module))) == NULL) {
  367. pam_syslog(pamh, LOG_CRIT,
  368. "_pam_init_handlers: no memory loading module");
  369. return PAM_BUF_ERR;
  370. }
  371. pamh->handlers.modules_allocated = MODULE_CHUNK;
  372. pamh->handlers.modules_used = 0;
  373. }
  374. if (pamh->service_name == NULL) {
  375. return PAM_BAD_ITEM; /* XXX - better error? */
  376. }
  377. #ifdef PAM_LOCKING
  378. /* Is the PAM subsystem locked? */
  379. {
  380. int fd_tmp;
  381. if ((fd_tmp = open( PAM_LOCK_FILE, O_RDONLY )) != -1) {
  382. pam_syslog(pamh, LOG_ERR,
  383. "_pam_init_handlers: PAM lockfile ("
  384. PAM_LOCK_FILE ") exists - aborting");
  385. (void) close(fd_tmp);
  386. /*
  387. * to avoid swamping the system with requests
  388. */
  389. _pam_start_timer(pamh);
  390. pam_fail_delay(pamh, 5000000);
  391. _pam_await_timer(pamh, PAM_ABORT);
  392. return PAM_ABORT;
  393. }
  394. }
  395. #endif /* PAM_LOCKING */
  396. /*
  397. * Now parse the config file(s) and add handlers
  398. */
  399. {
  400. struct stat test_d;
  401. /* Is there a PAM_CONFIG_D directory? */
  402. if (pamh->confdir != NULL ||
  403. (stat(PAM_CONFIG_D, &test_d) == 0 && S_ISDIR(test_d.st_mode)) ||
  404. (stat(PAM_CONFIG_DIST_D, &test_d) == 0 && S_ISDIR(test_d.st_mode))
  405. #ifdef PAM_CONFIG_DIST2_D
  406. || (stat(PAM_CONFIG_DIST2_D, &test_d) == 0
  407. && S_ISDIR(test_d.st_mode))
  408. #endif
  409. ) {
  410. char *path = NULL;
  411. int read_something=0;
  412. if (_pam_open_config_file(pamh, pamh->service_name, &path, &f) == PAM_SUCCESS) {
  413. retval = _pam_parse_conf_file(pamh, f, pamh->service_name,
  414. PAM_T_ANY, 0
  415. #ifdef PAM_READ_BOTH_CONFS
  416. , 0
  417. #endif /* PAM_READ_BOTH_CONFS */
  418. );
  419. if (retval != PAM_SUCCESS) {
  420. pam_syslog(pamh, LOG_ERR,
  421. "_pam_init_handlers: error reading %s",
  422. path);
  423. pam_syslog(pamh, LOG_ERR, "_pam_init_handlers: [%s]",
  424. pam_strerror(pamh, retval));
  425. } else {
  426. read_something = 1;
  427. }
  428. _pam_drop(path);
  429. fclose(f);
  430. } else {
  431. D(("unable to open configuration for %s", pamh->service_name));
  432. #ifdef PAM_READ_BOTH_CONFS
  433. D(("checking %s", PAM_CONFIG));
  434. if (pamh->confdir == NULL
  435. && (f = fopen(PAM_CONFIG,"r")) != NULL) {
  436. retval = _pam_parse_conf_file(pamh, f, NULL, PAM_T_ANY, 0, 1);
  437. fclose(f);
  438. } else
  439. #endif /* PAM_READ_BOTH_CONFS */
  440. retval = PAM_SUCCESS;
  441. /*
  442. * XXX - should we log an error? Some people want to always
  443. * use "other"
  444. */
  445. }
  446. if (retval == PAM_SUCCESS) {
  447. /* now parse the PAM_DEFAULT_SERVICE */
  448. if (_pam_open_config_file(pamh, PAM_DEFAULT_SERVICE, &path, &f) == PAM_SUCCESS) {
  449. /* would test magic here? */
  450. retval = _pam_parse_conf_file(pamh, f, PAM_DEFAULT_SERVICE,
  451. PAM_T_ANY, 0
  452. #ifdef PAM_READ_BOTH_CONFS
  453. , 0
  454. #endif /* PAM_READ_BOTH_CONFS */
  455. );
  456. if (retval != PAM_SUCCESS) {
  457. pam_syslog(pamh, LOG_ERR,
  458. "_pam_init_handlers: error reading %s",
  459. path);
  460. pam_syslog(pamh, LOG_ERR,
  461. "_pam_init_handlers: [%s]",
  462. pam_strerror(pamh, retval));
  463. } else {
  464. read_something = 1;
  465. }
  466. _pam_drop(path);
  467. fclose(f);
  468. } else {
  469. D(("unable to open %s", PAM_DEFAULT_SERVICE));
  470. pam_syslog(pamh, LOG_ERR,
  471. "_pam_init_handlers: no default config %s",
  472. PAM_DEFAULT_SERVICE);
  473. }
  474. if (!read_something) { /* nothing read successfully */
  475. retval = PAM_ABORT;
  476. }
  477. }
  478. } else {
  479. if ((f = fopen(PAM_CONFIG, "r")) == NULL) {
  480. pam_syslog(pamh, LOG_ERR, "_pam_init_handlers: could not open "
  481. PAM_CONFIG );
  482. return PAM_ABORT;
  483. }
  484. retval = _pam_parse_conf_file(pamh, f, NULL, PAM_T_ANY, 0
  485. #ifdef PAM_READ_BOTH_CONFS
  486. , 0
  487. #endif /* PAM_READ_BOTH_CONFS */
  488. );
  489. D(("closing configuration file"));
  490. fclose(f);
  491. }
  492. }
  493. if (retval != PAM_SUCCESS) {
  494. /* Read error */
  495. pam_syslog(pamh, LOG_ERR, "error reading PAM configuration file");
  496. return PAM_ABORT;
  497. }
  498. pamh->handlers.handlers_loaded = 1;
  499. D(("_pam_init_handlers exiting"));
  500. return PAM_SUCCESS;
  501. }
  502. /*
  503. * This is where we read a line of the PAM config file. The line may be
  504. * preceded by lines of comments and also extended with "\\\n"
  505. */
  506. static int _pam_assemble_line(FILE *f, char *buffer, int buf_len)
  507. {
  508. char *p = buffer;
  509. char *endp = buffer + buf_len;
  510. char *s, *os;
  511. int used = 0;
  512. /* loop broken with a 'break' when a non-'\\n' ended line is read */
  513. D(("called."));
  514. for (;;) {
  515. if (p >= endp) {
  516. /* Overflow */
  517. D(("_pam_assemble_line: overflow"));
  518. return -1;
  519. }
  520. if (fgets(p, endp - p, f) == NULL) {
  521. if (used) {
  522. /* Incomplete read */
  523. return -1;
  524. } else {
  525. /* EOF */
  526. return 0;
  527. }
  528. }
  529. /* skip leading spaces --- line may be blank */
  530. s = p + strspn(p, " \n\t");
  531. if (*s && (*s != '#')) {
  532. os = s;
  533. /*
  534. * we are only interested in characters before the first '#'
  535. * character
  536. */
  537. while (*s && *s != '#')
  538. ++s;
  539. if (*s == '#') {
  540. *s = '\0';
  541. used += strlen(os);
  542. break; /* the line has been read */
  543. }
  544. s = os;
  545. /*
  546. * Check for backslash by scanning back from the end of
  547. * the entered line, the '\n' has been included since
  548. * normally a line is terminated with this
  549. * character. fgets() should only return one though!
  550. */
  551. s += strlen(s);
  552. while (s > os && ((*--s == ' ') || (*s == '\t')
  553. || (*s == '\n')));
  554. /* check if it ends with a backslash */
  555. if (*s == '\\') {
  556. *s++ = ' '; /* replace backslash with ' ' */
  557. *s = '\0'; /* truncate the line here */
  558. used += strlen(os);
  559. p = s; /* there is more ... */
  560. } else {
  561. /* End of the line! */
  562. used += strlen(os);
  563. break; /* this is the complete line */
  564. }
  565. } else {
  566. /* Nothing in this line */
  567. /* Don't move p */
  568. }
  569. }
  570. return used;
  571. }
  572. static char *
  573. extract_modulename(const char *mod_path)
  574. {
  575. const char *p = strrchr (mod_path, '/');
  576. char *dot, *retval;
  577. if (p == NULL)
  578. p = mod_path;
  579. else
  580. p++;
  581. if ((retval = _pam_strdup (p)) == NULL)
  582. return NULL;
  583. dot = strrchr (retval, '.');
  584. if (dot)
  585. *dot = '\0';
  586. if (*retval == '\0' || strcmp(retval, "?") == 0) {
  587. /* do not allow empty module name or "?" to avoid confusing audit trail */
  588. _pam_drop(retval);
  589. return NULL;
  590. }
  591. return retval;
  592. }
  593. static struct loaded_module *
  594. _pam_load_module(pam_handle_t *pamh, const char *mod_path, int handler_type)
  595. {
  596. int x = 0;
  597. int success;
  598. struct loaded_module *mod;
  599. D(("_pam_load_module: loading module `%s'", mod_path));
  600. mod = pamh->handlers.module;
  601. /* First, ensure the module is loaded */
  602. while (x < pamh->handlers.modules_used) {
  603. if (!strcmp(mod[x].name, mod_path)) { /* case sensitive ! */
  604. break;
  605. }
  606. x++;
  607. }
  608. if (x == pamh->handlers.modules_used) {
  609. /* Not found */
  610. if (pamh->handlers.modules_allocated == pamh->handlers.modules_used) {
  611. /* will need more memory */
  612. void *tmp = realloc(pamh->handlers.module,
  613. (pamh->handlers.modules_allocated+MODULE_CHUNK)
  614. *sizeof(struct loaded_module));
  615. if (tmp == NULL) {
  616. D(("cannot enlarge module pointer memory"));
  617. pam_syslog(pamh, LOG_CRIT,
  618. "realloc returned NULL in _pam_load_module");
  619. return NULL;
  620. }
  621. pamh->handlers.module = tmp;
  622. pamh->handlers.modules_allocated += MODULE_CHUNK;
  623. }
  624. mod = &(pamh->handlers.module[x]);
  625. /* Be pessimistic... */
  626. success = PAM_ABORT;
  627. D(("_pam_load_module: _pam_dlopen(%s)", mod_path));
  628. mod->dl_handle = _pam_dlopen(mod_path);
  629. D(("_pam_load_module: _pam_dlopen'ed"));
  630. D(("_pam_load_module: dlopen'ed"));
  631. if (mod->dl_handle == NULL) {
  632. const char *isa = strstr(mod_path, "$ISA");
  633. size_t isa_len = strlen("$ISA");
  634. if (isa != NULL) {
  635. size_t pam_isa_len = strlen(_PAM_ISA);
  636. char *mod_full_isa_path =
  637. malloc(strlen(mod_path) - isa_len + pam_isa_len + 1);
  638. if (mod_full_isa_path == NULL) {
  639. D(("_pam_load_module: couldn't get memory for mod_path"));
  640. pam_syslog(pamh, LOG_CRIT, "no memory for module path");
  641. success = PAM_ABORT;
  642. } else {
  643. char *p = mod_full_isa_path;
  644. memcpy(p, mod_path, isa - mod_path);
  645. p += isa - mod_path;
  646. memcpy(p, _PAM_ISA, pam_isa_len);
  647. p += pam_isa_len;
  648. strcpy(p, isa + isa_len);
  649. mod->dl_handle = _pam_dlopen(mod_full_isa_path);
  650. _pam_drop(mod_full_isa_path);
  651. }
  652. }
  653. }
  654. if (mod->dl_handle == NULL) {
  655. D(("_pam_load_module: _pam_dlopen(%s) failed", mod_path));
  656. if (handler_type != PAM_HT_SILENT_MODULE)
  657. pam_syslog(pamh, LOG_ERR, "unable to dlopen(%s): %s", mod_path,
  658. _pam_dlerror());
  659. /* Don't abort yet; static code may be able to find function.
  660. * But defaults to abort if nothing found below... */
  661. } else {
  662. D(("module added successfully"));
  663. success = PAM_SUCCESS;
  664. mod->type = PAM_MT_DYNAMIC_MOD;
  665. pamh->handlers.modules_used++;
  666. }
  667. if (success != PAM_SUCCESS) { /* add a malformed module */
  668. mod->dl_handle = NULL;
  669. mod->type = PAM_MT_FAULTY_MOD;
  670. pamh->handlers.modules_used++;
  671. if (handler_type != PAM_HT_SILENT_MODULE)
  672. pam_syslog(pamh, LOG_ERR, "adding faulty module: %s", mod_path);
  673. success = PAM_SUCCESS; /* We have successfully added a module */
  674. }
  675. /* indicate its name - later we will search for it by this */
  676. if ((mod->name = _pam_strdup(mod_path)) == NULL) {
  677. D(("_pam_load_module: couldn't get memory for mod_path"));
  678. pam_syslog(pamh, LOG_CRIT, "no memory for module path");
  679. success = PAM_ABORT;
  680. }
  681. } else { /* x != pamh->handlers.modules_used */
  682. mod += x; /* the located module */
  683. success = PAM_SUCCESS;
  684. }
  685. return success == PAM_SUCCESS ? mod : NULL;
  686. }
  687. int _pam_add_handler(pam_handle_t *pamh
  688. , int handler_type, int other, int stack_level, int type
  689. , int *actions, const char *mod_path
  690. , int argc, char **argv, int argvlen)
  691. {
  692. struct loaded_module *mod = NULL;
  693. struct handler **handler_p;
  694. struct handler **handler_p2;
  695. struct handlers *the_handlers;
  696. const char *sym, *sym2;
  697. char *mod_full_path;
  698. servicefn func, func2;
  699. int mod_type = PAM_MT_FAULTY_MOD;
  700. D(("called."));
  701. IF_NO_PAMH("_pam_add_handler",pamh,PAM_SYSTEM_ERR);
  702. D(("_pam_add_handler: adding type %d, handler_type %d, module `%s'",
  703. type, handler_type, mod_path));
  704. if ((handler_type == PAM_HT_MODULE || handler_type == PAM_HT_SILENT_MODULE) &&
  705. mod_path != NULL) {
  706. if (mod_path[0] == '/') {
  707. mod = _pam_load_module(pamh, mod_path, handler_type);
  708. } else if (asprintf(&mod_full_path, "%s%s",
  709. DEFAULT_MODULE_PATH, mod_path) >= 0) {
  710. mod = _pam_load_module(pamh, mod_full_path, handler_type);
  711. _pam_drop(mod_full_path);
  712. } else {
  713. pam_syslog(pamh, LOG_CRIT, "cannot malloc full mod path");
  714. return PAM_ABORT;
  715. }
  716. if (mod == NULL) {
  717. /* if we get here with NULL it means allocation error */
  718. return PAM_ABORT;
  719. }
  720. mod_type = mod->type;
  721. }
  722. if (mod_path == NULL)
  723. mod_path = UNKNOWN_MODULE;
  724. /*
  725. * At this point 'mod' points to the stored/loaded module.
  726. */
  727. /* Now define the handler(s) based on mod->dlhandle and type */
  728. /* decide which list of handlers to use */
  729. the_handlers = (other) ? &pamh->handlers.other : &pamh->handlers.conf;
  730. handler_p = handler_p2 = NULL;
  731. func = func2 = NULL;
  732. sym2 = NULL;
  733. /* point handler_p's at the root addresses of the function stacks */
  734. switch (type) {
  735. case PAM_T_AUTH:
  736. handler_p = &the_handlers->authenticate;
  737. sym = "pam_sm_authenticate";
  738. handler_p2 = &the_handlers->setcred;
  739. sym2 = "pam_sm_setcred";
  740. break;
  741. case PAM_T_SESS:
  742. handler_p = &the_handlers->open_session;
  743. sym = "pam_sm_open_session";
  744. handler_p2 = &the_handlers->close_session;
  745. sym2 = "pam_sm_close_session";
  746. break;
  747. case PAM_T_ACCT:
  748. handler_p = &the_handlers->acct_mgmt;
  749. sym = "pam_sm_acct_mgmt";
  750. break;
  751. case PAM_T_PASS:
  752. handler_p = &the_handlers->chauthtok;
  753. sym = "pam_sm_chauthtok";
  754. break;
  755. default:
  756. /* Illegal module type */
  757. D(("_pam_add_handler: illegal module type %d", type));
  758. return PAM_ABORT;
  759. }
  760. /* are the modules reliable? */
  761. if (mod_type != PAM_MT_DYNAMIC_MOD &&
  762. mod_type != PAM_MT_FAULTY_MOD) {
  763. D(("_pam_add_handlers: illegal module library type; %d", mod_type));
  764. pam_syslog(pamh, LOG_ERR,
  765. "internal error: module library type not known: %s;%d",
  766. sym, mod_type);
  767. return PAM_ABORT;
  768. }
  769. /* now identify this module's functions - for non-faulty modules */
  770. if ((mod_type == PAM_MT_DYNAMIC_MOD) &&
  771. !(func = _pam_dlsym(mod->dl_handle, sym)) ) {
  772. pam_syslog(pamh, LOG_ERR, "unable to resolve symbol: %s", sym);
  773. }
  774. if (sym2) {
  775. if ((mod_type == PAM_MT_DYNAMIC_MOD) &&
  776. !(func2 = _pam_dlsym(mod->dl_handle, sym2)) ) {
  777. pam_syslog(pamh, LOG_ERR, "unable to resolve symbol: %s", sym2);
  778. }
  779. }
  780. /* here func (and perhaps func2) point to the appropriate functions */
  781. /* add new handler to end of existing list */
  782. while (*handler_p != NULL) {
  783. handler_p = &((*handler_p)->next);
  784. }
  785. if ((*handler_p = malloc(sizeof(struct handler))) == NULL) {
  786. pam_syslog(pamh, LOG_CRIT, "cannot malloc struct handler #1");
  787. return (PAM_ABORT);
  788. }
  789. (*handler_p)->handler_type = handler_type;
  790. (*handler_p)->stack_level = stack_level;
  791. (*handler_p)->func = func;
  792. memcpy((*handler_p)->actions,actions,sizeof((*handler_p)->actions));
  793. (*handler_p)->cached_retval = _PAM_INVALID_RETVAL;
  794. (*handler_p)->cached_retval_p = &((*handler_p)->cached_retval);
  795. (*handler_p)->argc = argc;
  796. (*handler_p)->argv = argv; /* not a copy */
  797. if (((*handler_p)->mod_name = extract_modulename(mod_path)) == NULL)
  798. return PAM_ABORT;
  799. (*handler_p)->grantor = 0;
  800. (*handler_p)->next = NULL;
  801. /* some of the modules have a second calling function */
  802. if (handler_p2) {
  803. /* add new handler to end of existing list */
  804. while (*handler_p2) {
  805. handler_p2 = &((*handler_p2)->next);
  806. }
  807. if ((*handler_p2 = malloc(sizeof(struct handler))) == NULL) {
  808. pam_syslog(pamh, LOG_CRIT, "cannot malloc struct handler #2");
  809. return (PAM_ABORT);
  810. }
  811. (*handler_p2)->handler_type = handler_type;
  812. (*handler_p2)->stack_level = stack_level;
  813. (*handler_p2)->func = func2;
  814. memcpy((*handler_p2)->actions,actions,sizeof((*handler_p2)->actions));
  815. (*handler_p2)->cached_retval = _PAM_INVALID_RETVAL; /* ignored */
  816. /* Note, this next entry points to the handler_p value! */
  817. (*handler_p2)->cached_retval_p = &((*handler_p)->cached_retval);
  818. (*handler_p2)->argc = argc;
  819. if (argv) {
  820. if (((*handler_p2)->argv = malloc(argvlen)) == NULL) {
  821. pam_syslog(pamh, LOG_CRIT, "cannot malloc argv for handler #2");
  822. return (PAM_ABORT);
  823. }
  824. memcpy((*handler_p2)->argv, argv, argvlen);
  825. } else {
  826. (*handler_p2)->argv = NULL; /* no arguments */
  827. }
  828. if (((*handler_p2)->mod_name = extract_modulename(mod_path)) == NULL)
  829. return PAM_ABORT;
  830. (*handler_p2)->grantor = 0;
  831. (*handler_p2)->next = NULL;
  832. }
  833. D(("_pam_add_handler: returning successfully"));
  834. return PAM_SUCCESS;
  835. }
  836. /* Free various allocated structures and dlclose() the libs */
  837. int _pam_free_handlers(pam_handle_t *pamh)
  838. {
  839. struct loaded_module *mod;
  840. D(("called."));
  841. IF_NO_PAMH("_pam_free_handlers",pamh,PAM_SYSTEM_ERR);
  842. mod = pamh->handlers.module;
  843. /* Close all loaded modules */
  844. while (pamh->handlers.modules_used) {
  845. D(("_pam_free_handlers: dlclose(%s)", mod->name));
  846. free(mod->name);
  847. if (mod->type == PAM_MT_DYNAMIC_MOD) {
  848. _pam_dlclose(mod->dl_handle);
  849. }
  850. mod++;
  851. pamh->handlers.modules_used--;
  852. }
  853. /* Free all the handlers */
  854. _pam_free_handlers_aux(&(pamh->handlers.conf.authenticate));
  855. _pam_free_handlers_aux(&(pamh->handlers.conf.setcred));
  856. _pam_free_handlers_aux(&(pamh->handlers.conf.acct_mgmt));
  857. _pam_free_handlers_aux(&(pamh->handlers.conf.open_session));
  858. _pam_free_handlers_aux(&(pamh->handlers.conf.close_session));
  859. _pam_free_handlers_aux(&(pamh->handlers.conf.chauthtok));
  860. _pam_free_handlers_aux(&(pamh->handlers.other.authenticate));
  861. _pam_free_handlers_aux(&(pamh->handlers.other.setcred));
  862. _pam_free_handlers_aux(&(pamh->handlers.other.acct_mgmt));
  863. _pam_free_handlers_aux(&(pamh->handlers.other.open_session));
  864. _pam_free_handlers_aux(&(pamh->handlers.other.close_session));
  865. _pam_free_handlers_aux(&(pamh->handlers.other.chauthtok));
  866. /* no more loaded modules */
  867. _pam_drop(pamh->handlers.module);
  868. /* Indicate that handlers are not initialized for this pamh */
  869. pamh->handlers.handlers_loaded = 0;
  870. return PAM_SUCCESS;
  871. }
  872. void _pam_start_handlers(pam_handle_t *pamh)
  873. {
  874. D(("called."));
  875. /* NB. There is no check for a NULL pamh here, since no return
  876. * value to communicate the fact! */
  877. /* Indicate that handlers are not initialized for this pamh */
  878. pamh->handlers.handlers_loaded = 0;
  879. pamh->handlers.modules_allocated = 0;
  880. pamh->handlers.modules_used = 0;
  881. pamh->handlers.module = NULL;
  882. /* initialize the .conf and .other entries */
  883. pamh->handlers.conf.authenticate = NULL;
  884. pamh->handlers.conf.setcred = NULL;
  885. pamh->handlers.conf.acct_mgmt = NULL;
  886. pamh->handlers.conf.open_session = NULL;
  887. pamh->handlers.conf.close_session = NULL;
  888. pamh->handlers.conf.chauthtok = NULL;
  889. pamh->handlers.other.authenticate = NULL;
  890. pamh->handlers.other.setcred = NULL;
  891. pamh->handlers.other.acct_mgmt = NULL;
  892. pamh->handlers.other.open_session = NULL;
  893. pamh->handlers.other.close_session = NULL;
  894. pamh->handlers.other.chauthtok = NULL;
  895. }
  896. void _pam_free_handlers_aux(struct handler **hp)
  897. {
  898. struct handler *h = *hp;
  899. struct handler *last;
  900. D(("called."));
  901. while (h) {
  902. last = h;
  903. _pam_drop(h->argv); /* This is all allocated in a single chunk */
  904. _pam_drop(h->mod_name);
  905. h = h->next;
  906. memset(last, 0, sizeof(*last));
  907. free(last);
  908. }
  909. *hp = NULL;
  910. }