1 /* pam_handlers.c -- pam config file parsing and module loading */
4 * created by Marc Ewing.
5 * Currently maintained by Andrew G. Morgan <morgan@kernel.org>
9 #include "pam_private.h"
14 #include <sys/types.h>
20 #define MODULE_CHUNK 4
21 #define UNKNOWN_MODULE "<*unknown module*>"
26 static int _pam_assemble_line(FILE *f, char *buf, int buf_len);
28 static void _pam_free_handlers_aux(struct handler **hp);
30 static int _pam_add_handler(pam_handle_t *pamh
31 , int must_fail, int other, int stack_level, int type
32 , int *actions, const char *mod_path
33 , int argc, char **argv, int argvlen);
35 /* Values for module type */
43 static int _pam_load_conf_file(pam_handle_t *pamh, const char *config_name
44 , const char *service /* specific file */
45 , int module_type /* specific type */
46 , int stack_level /* level of substack */
47 #ifdef PAM_READ_BOTH_CONFS
49 #endif /* PAM_READ_BOTH_CONFS */
52 static int _pam_parse_conf_file(pam_handle_t *pamh, FILE *f
53 , const char *known_service /* specific file */
54 , int requested_module_type /* specific type */
55 , int stack_level /* level of substack */
56 #ifdef PAM_READ_BOTH_CONFS
58 #endif /* PAM_READ_BOTH_CONFS */
62 int x; /* read a line from the FILE *f ? */
64 * read a line from the configuration (FILE *) f
66 while ((x = _pam_assemble_line(f, buf, BUF_SIZE)) > 0) {
67 char *tok, *nexttok=NULL;
68 const char *this_service;
70 int module_type, actions[_PAM_RETURN_VALUES];
71 int other; /* set if module is for PAM_DEFAULT_SERVICE */
72 int res; /* module added successfully? */
73 int handler_type = PAM_HT_MODULE; /* regular handler from a module */
78 D(("_pam_init_handler: LINE: %s", buf));
79 if (known_service != NULL) {
81 /* No service field: all lines are for the known service. */
82 this_service = known_service;
84 this_service = tok = _pam_StrTok(buf, " \n\t", &nexttok);
87 #ifdef PAM_READ_BOTH_CONFS
91 #endif /* PAM_READ_BOTH_CONFS */
92 other = !strcasecmp(this_service, PAM_DEFAULT_SERVICE);
94 /* accept "service name" or PAM_DEFAULT_SERVICE modules */
95 if (!strcasecmp(this_service, pamh->service_name) || other) {
99 /* This is a service we are looking for */
100 D(("_pam_init_handlers: Found PAM config entry for: %s"
103 tok = _pam_StrTok(NULL, " \n\t", &nexttok);
105 /* module type does not exist */
106 D(("_pam_init_handlers: empty module type for %s", this_service));
107 pam_syslog(pamh, LOG_ERR,
108 "(%s) empty module type", this_service);
109 module_type = (requested_module_type != PAM_T_ANY) ?
110 requested_module_type : PAM_T_AUTH; /* most sensitive */
111 handler_type = PAM_HT_MUST_FAIL; /* install as normal but fail when dispatched */
113 if (tok[0] == '-') { /* do not log module load errors */
114 handler_type = PAM_HT_SILENT_MODULE;
117 if (!strcasecmp("auth", tok)) {
118 module_type = PAM_T_AUTH;
119 } else if (!strcasecmp("session", tok)) {
120 module_type = PAM_T_SESS;
121 } else if (!strcasecmp("account", tok)) {
122 module_type = PAM_T_ACCT;
123 } else if (!strcasecmp("password", tok)) {
124 module_type = PAM_T_PASS;
126 /* Illegal module type */
127 D(("_pam_init_handlers: bad module type: %s", tok));
128 pam_syslog(pamh, LOG_ERR, "(%s) illegal module type: %s",
130 module_type = (requested_module_type != PAM_T_ANY) ?
131 requested_module_type : PAM_T_AUTH; /* most sensitive */
132 handler_type = PAM_HT_MUST_FAIL; /* install as normal but fail when dispatched */
135 D(("Using %s config entry: %s", handler_type?"BAD ":"", tok));
136 if (requested_module_type != PAM_T_ANY &&
137 module_type != requested_module_type) {
138 D(("Skipping config entry: %s (requested=%d, found=%d)",
139 tok, requested_module_type, module_type));
143 /* reset the actions to .._UNDEF's -- this is so that
144 we can work out which entries are not yet set (for default). */
147 for (i=0; i<_PAM_RETURN_VALUES;
148 actions[i++] = _PAM_ACTION_UNDEF);
150 tok = _pam_StrTok(NULL, " \n\t", &nexttok);
152 /* no module name given */
153 D(("_pam_init_handlers: no control flag supplied"));
154 pam_syslog(pamh, LOG_ERR,
155 "(%s) no control flag supplied", this_service);
156 _pam_set_default_control(actions, _PAM_ACTION_BAD);
157 handler_type = PAM_HT_MUST_FAIL;
158 } else if (!strcasecmp("required", tok)) {
159 D(("*PAM_F_REQUIRED*"));
160 actions[PAM_SUCCESS] = _PAM_ACTION_OK;
161 actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
162 actions[PAM_IGNORE] = _PAM_ACTION_IGNORE;
163 _pam_set_default_control(actions, _PAM_ACTION_BAD);
164 } else if (!strcasecmp("requisite", tok)) {
165 D(("*PAM_F_REQUISITE*"));
166 actions[PAM_SUCCESS] = _PAM_ACTION_OK;
167 actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
168 actions[PAM_IGNORE] = _PAM_ACTION_IGNORE;
169 _pam_set_default_control(actions, _PAM_ACTION_DIE);
170 } else if (!strcasecmp("optional", tok)) {
171 D(("*PAM_F_OPTIONAL*"));
172 actions[PAM_SUCCESS] = _PAM_ACTION_OK;
173 actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
174 _pam_set_default_control(actions, _PAM_ACTION_IGNORE);
175 } else if (!strcasecmp("sufficient", tok)) {
176 D(("*PAM_F_SUFFICIENT*"));
177 actions[PAM_SUCCESS] = _PAM_ACTION_DONE;
178 actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_DONE;
179 _pam_set_default_control(actions, _PAM_ACTION_IGNORE);
180 } else if (!strcasecmp("include", tok)) {
181 D(("*PAM_F_INCLUDE*"));
184 } else if (!strcasecmp("substack", tok)) {
185 D(("*PAM_F_SUBSTACK*"));
189 D(("will need to parse %s", tok));
190 _pam_parse_control(actions, tok);
191 /* by default the default is to treat as failure */
192 _pam_set_default_control(actions, _PAM_ACTION_BAD);
195 tok = _pam_StrTok(NULL, " \n\t", &nexttok);
198 res = _pam_add_handler(pamh, PAM_HT_SUBSTACK, other,
199 stack_level, module_type, actions, tok,
201 if (res != PAM_SUCCESS) {
202 pam_syslog(pamh, LOG_ERR, "error adding substack %s", tok);
203 D(("failed to load module - aborting"));
207 if (_pam_load_conf_file(pamh, tok, this_service, module_type,
208 stack_level + substack
209 #ifdef PAM_READ_BOTH_CONFS
211 #endif /* PAM_READ_BOTH_CONFS */
214 _pam_set_default_control(actions, _PAM_ACTION_BAD);
216 handler_type = PAM_HT_MUST_FAIL;
218 } else if (tok != NULL) {
220 D(("mod_path = %s",mod_path));
222 /* no module name given */
223 D(("_pam_init_handlers: no module name supplied"));
224 pam_syslog(pamh, LOG_ERR,
225 "(%s) no module name supplied", this_service);
227 handler_type = PAM_HT_MUST_FAIL;
230 /* nexttok points to remaining arguments... */
232 if (nexttok != NULL) {
233 D(("list: %s",nexttok));
234 argvlen = _pam_mkargv(nexttok, &argv, &argc);
235 D(("argvlen = %d",argvlen));
236 } else { /* there are no arguments so fix by hand */
237 D(("_pam_init_handlers: empty argument list"));
246 D(("CONF%s: %s%s %d %s %d"
247 , handler_type==PAM_HT_MUST_FAIL?"<*will fail*>":""
248 , this_service, other ? "(backup)":""
251 for (y = 0; y < argc; y++) {
252 D(("CONF: %s", argv[y]));
254 for (y = 0; y<_PAM_RETURN_VALUES; ++y) {
255 D(("RETURN %s(%d) -> %d %s",
256 _pam_token_returns[y], y, actions[y],
257 actions[y]>0 ? "jump":
258 _pam_token_actions[-actions[y]]));
263 res = _pam_add_handler(pamh, handler_type, other, stack_level
264 , module_type, actions, mod_path
265 , argc, argv, argvlen);
266 if (res != PAM_SUCCESS) {
267 pam_syslog(pamh, LOG_ERR, "error loading %s", mod_path);
268 D(("failed to load module - aborting"));
274 return ( (x < 0) ? PAM_ABORT:PAM_SUCCESS );
277 static int _pam_load_conf_file(pam_handle_t *pamh, const char *config_name
278 , const char *service /* specific file */
279 , int module_type /* specific type */
280 , int stack_level /* level of substack */
281 #ifdef PAM_READ_BOTH_CONFS
283 #endif /* PAM_READ_BOTH_CONFS */
287 char *config_path = NULL;
288 int retval = PAM_ABORT;
290 D(("_pam_load_conf_file called"));
292 if (stack_level >= PAM_SUBSTACK_MAX_LEVEL) {
293 D(("maximum level of substacks reached"));
294 pam_syslog(pamh, LOG_ERR, "maximum level of substacks reached");
298 if (config_name == NULL) {
299 D(("no config file supplied"));
300 pam_syslog(pamh, LOG_ERR, "(%s) no config file supplied", service);
304 if (config_name[0] != '/') {
305 if (asprintf (&config_path, PAM_CONFIG_DF, config_name) < 0) {
306 pam_syslog(pamh, LOG_CRIT, "asprintf failed");
309 config_name = config_path;
312 D(("opening %s", config_name));
313 f = fopen(config_name, "r");
315 retval = _pam_parse_conf_file(pamh, f, service, module_type, stack_level
316 #ifdef PAM_READ_BOTH_CONFS
318 #endif /* PAM_READ_BOTH_CONFS */
321 if (retval != PAM_SUCCESS)
322 pam_syslog(pamh, LOG_ERR,
323 "_pam_load_conf_file: error reading %s: %s",
324 config_name, pam_strerror(pamh, retval));
326 D(("unable to open %s", config_name));
327 pam_syslog(pamh, LOG_ERR,
328 "_pam_load_conf_file: unable to open %s",
332 _pam_drop(config_path);
336 /* Parse config file, allocate handler structures, dlopen() */
337 int _pam_init_handlers(pam_handle_t *pamh)
342 D(("_pam_init_handlers called"));
343 IF_NO_PAMH("_pam_init_handlers",pamh,PAM_SYSTEM_ERR);
345 /* Return immediately if everything is already loaded */
346 if (pamh->handlers.handlers_loaded) {
350 D(("_pam_init_handlers: initializing"));
352 /* First clean the service structure */
354 _pam_free_handlers(pamh);
355 if (! pamh->handlers.module) {
356 if ((pamh->handlers.module =
357 malloc(MODULE_CHUNK * sizeof(struct loaded_module))) == NULL) {
358 pam_syslog(pamh, LOG_CRIT,
359 "_pam_init_handlers: no memory loading module");
362 pamh->handlers.modules_allocated = MODULE_CHUNK;
363 pamh->handlers.modules_used = 0;
366 if (pamh->service_name == NULL) {
367 return PAM_BAD_ITEM; /* XXX - better error? */
371 /* Is the PAM subsystem locked? */
375 if ((fd_tmp = open( PAM_LOCK_FILE, O_RDONLY )) != -1) {
376 pam_syslog(pamh, LOG_ERR,
377 "_pam_init_handlers: PAM lockfile ("
378 PAM_LOCK_FILE ") exists - aborting");
379 (void) close(fd_tmp);
381 * to avoid swamping the system with requests
383 _pam_start_timer(pamh);
384 pam_fail_delay(pamh, 5000000);
385 _pam_await_timer(pamh, PAM_ABORT);
390 #endif /* PAM_LOCKING */
393 * Now parse the config file(s) and add handlers
398 /* Is there a PAM_CONFIG_D directory? */
399 if ( stat(PAM_CONFIG_D, &test_d) == 0 && S_ISDIR(test_d.st_mode) ) {
401 int read_something=0;
403 D(("searching " PAM_CONFIG_D " for config files"));
404 if (asprintf(&filename, PAM_CONFIG_DF, pamh->service_name) < 0) {
405 pam_syslog(pamh, LOG_ERR,
406 "_pam_init_handlers: no memory; service %s",
410 D(("opening %s", filename));
411 f = fopen(filename, "r");
413 /* would test magic here? */
414 retval = _pam_parse_conf_file(pamh, f, pamh->service_name,
416 #ifdef PAM_READ_BOTH_CONFS
418 #endif /* PAM_READ_BOTH_CONFS */
421 if (retval != PAM_SUCCESS) {
422 pam_syslog(pamh, LOG_ERR,
423 "_pam_init_handlers: error reading %s",
425 pam_syslog(pamh, LOG_ERR, "_pam_init_handlers: [%s]",
426 pam_strerror(pamh, retval));
431 D(("unable to open %s", filename));
432 #ifdef PAM_READ_BOTH_CONFS
433 D(("checking %s", PAM_CONFIG));
435 if ((f = fopen(PAM_CONFIG,"r")) != NULL) {
436 retval = _pam_parse_conf_file(pamh, f, NULL, PAM_T_ANY, 0, 1);
439 #endif /* PAM_READ_BOTH_CONFS */
440 retval = PAM_SUCCESS;
442 * XXX - should we log an error? Some people want to always
448 if (retval == PAM_SUCCESS) {
449 /* now parse the PAM_DEFAULT_SERVICE_FILE */
451 D(("opening %s", PAM_DEFAULT_SERVICE_FILE));
452 f = fopen(PAM_DEFAULT_SERVICE_FILE, "r");
454 /* would test magic here? */
455 retval = _pam_parse_conf_file(pamh, f, PAM_DEFAULT_SERVICE,
457 #ifdef PAM_READ_BOTH_CONFS
459 #endif /* PAM_READ_BOTH_CONFS */
462 if (retval != PAM_SUCCESS) {
463 pam_syslog(pamh, LOG_ERR,
464 "_pam_init_handlers: error reading %s",
465 PAM_DEFAULT_SERVICE_FILE);
466 pam_syslog(pamh, LOG_ERR,
467 "_pam_init_handlers: [%s]",
468 pam_strerror(pamh, retval));
473 D(("unable to open %s", PAM_DEFAULT_SERVICE_FILE));
474 pam_syslog(pamh, LOG_ERR,
475 "_pam_init_handlers: no default config %s",
476 PAM_DEFAULT_SERVICE_FILE);
478 if (!read_something) { /* nothing read successfully */
483 if ((f = fopen(PAM_CONFIG, "r")) == NULL) {
484 pam_syslog(pamh, LOG_ERR, "_pam_init_handlers: could not open "
489 retval = _pam_parse_conf_file(pamh, f, NULL, PAM_T_ANY, 0
490 #ifdef PAM_READ_BOTH_CONFS
492 #endif /* PAM_READ_BOTH_CONFS */
495 D(("closing configuration file"));
500 if (retval != PAM_SUCCESS) {
502 pam_syslog(pamh, LOG_ERR, "error reading PAM configuration file");
506 pamh->handlers.handlers_loaded = 1;
508 D(("_pam_init_handlers exiting"));
513 * This is where we read a line of the PAM config file. The line may be
514 * preceeded by lines of comments and also extended with "\\\n"
517 static int _pam_assemble_line(FILE *f, char *buffer, int buf_len)
520 char *endp = buffer + buf_len;
524 /* loop broken with a 'break' when a non-'\\n' ended line is read */
530 D(("_pam_assemble_line: overflow"));
533 if (fgets(p, endp - p, f) == NULL) {
535 /* Incomplete read */
543 /* skip leading spaces --- line may be blank */
545 s = p + strspn(p, " \n\t");
546 if (*s && (*s != '#')) {
550 * we are only interested in characters before the first '#'
554 while (*s && *s != '#')
559 break; /* the line has been read */
565 * Check for backslash by scanning back from the end of
566 * the entered line, the '\n' has been included since
567 * normally a line is terminated with this
568 * character. fgets() should only return one though!
572 while (s > os && ((*--s == ' ') || (*s == '\t')
575 /* check if it ends with a backslash */
577 *s++ = ' '; /* replace backslash with ' ' */
578 *s = '\0'; /* truncate the line here */
580 p = s; /* there is more ... */
582 /* End of the line! */
584 break; /* this is the complete line */
588 /* Nothing in this line */
597 extract_modulename(const char *mod_path)
599 const char *p = strrchr (mod_path, '/');
607 if ((retval = _pam_strdup (p)) == NULL)
610 dot = strrchr (retval, '.');
617 static struct loaded_module *
618 _pam_load_module(pam_handle_t *pamh, const char *mod_path, int handler_type)
623 char *mod_full_isa_path=NULL, *isa=NULL;
625 struct loaded_module *mod;
627 D(("_pam_load_module: loading module `%s'", mod_path));
629 mod = pamh->handlers.module;
631 /* First, ensure the module is loaded */
632 while (x < pamh->handlers.modules_used) {
633 if (!strcmp(mod[x].name, mod_path)) { /* case sensitive ! */
638 if (x == pamh->handlers.modules_used) {
640 if (pamh->handlers.modules_allocated == pamh->handlers.modules_used) {
641 /* will need more memory */
642 void *tmp = realloc(pamh->handlers.module,
643 (pamh->handlers.modules_allocated+MODULE_CHUNK)
644 *sizeof(struct loaded_module));
646 D(("cannot enlarge module pointer memory"));
647 pam_syslog(pamh, LOG_ERR,
648 "realloc returned NULL in _pam_load_module");
651 pamh->handlers.module = tmp;
652 pamh->handlers.modules_allocated += MODULE_CHUNK;
654 mod = &(pamh->handlers.module[x]);
655 /* Be pessimistic... */
659 /* Only load static function if function was not found dynamically.
660 * This code should work even if no dynamic loading is available. */
661 if (success != PAM_SUCCESS) {
662 D(("_pam_load_module: open static handler %s", mod_path));
663 mod->dl_handle = _pam_open_static_handler(pamh, mod_path);
664 if (mod->dl_handle == NULL) {
665 D(("_pam_load_module: unable to find static handler %s",
667 if (handler_type != PAM_HT_SILENT_MODULE)
668 pam_syslog(pamh, LOG_ERR,
669 "unable to open static handler %s", mod_path);
670 /* Didn't find module in dynamic or static..will mark bad */
672 D(("static module added successfully"));
673 success = PAM_SUCCESS;
674 mod->type = PAM_MT_STATIC_MOD;
675 pamh->handlers.modules_used++;
679 D(("_pam_load_module: _pam_dlopen(%s)", mod_path));
680 mod->dl_handle = _pam_dlopen(mod_path);
681 D(("_pam_load_module: _pam_dlopen'ed"));
682 D(("_pam_load_module: dlopen'ed"));
683 if (mod->dl_handle == NULL) {
684 if (strstr(mod_path, "$ISA")) {
685 mod_full_isa_path = malloc(strlen(mod_path) + strlen(_PAM_ISA) + 1);
686 if (mod_full_isa_path == NULL) {
687 D(("_pam_load_module: couldn't get memory for mod_path"));
688 pam_syslog(pamh, LOG_ERR, "no memory for module path");
691 strcpy(mod_full_isa_path, mod_path);
692 isa = strstr(mod_full_isa_path, "$ISA");
694 memmove(isa + strlen(_PAM_ISA), isa + 4, strlen(isa + 4) + 1);
695 memmove(isa, _PAM_ISA, strlen(_PAM_ISA));
697 mod->dl_handle = _pam_dlopen(mod_full_isa_path);
698 _pam_drop(mod_full_isa_path);
702 if (mod->dl_handle == NULL) {
703 D(("_pam_load_module: _pam_dlopen(%s) failed", mod_path));
704 if (handler_type != PAM_HT_SILENT_MODULE)
705 pam_syslog(pamh, LOG_ERR, "unable to dlopen(%s): %s", mod_path,
707 /* Don't abort yet; static code may be able to find function.
708 * But defaults to abort if nothing found below... */
710 D(("module added successfully"));
711 success = PAM_SUCCESS;
712 mod->type = PAM_MT_DYNAMIC_MOD;
713 pamh->handlers.modules_used++;
717 if (success != PAM_SUCCESS) { /* add a malformed module */
718 mod->dl_handle = NULL;
719 mod->type = PAM_MT_FAULTY_MOD;
720 pamh->handlers.modules_used++;
721 if (handler_type != PAM_HT_SILENT_MODULE)
722 pam_syslog(pamh, LOG_ERR, "adding faulty module: %s", mod_path);
723 success = PAM_SUCCESS; /* We have successfully added a module */
726 /* indicate its name - later we will search for it by this */
727 if ((mod->name = _pam_strdup(mod_path)) == NULL) {
728 D(("_pam_load_module: couldn't get memory for mod_path"));
729 pam_syslog(pamh, LOG_ERR, "no memory for module path");
733 } else { /* x != pamh->handlers.modules_used */
734 mod += x; /* the located module */
735 success = PAM_SUCCESS;
737 return success == PAM_SUCCESS ? mod : NULL;
740 int _pam_add_handler(pam_handle_t *pamh
741 , int handler_type, int other, int stack_level, int type
742 , int *actions, const char *mod_path
743 , int argc, char **argv, int argvlen)
745 struct loaded_module *mod = NULL;
746 struct handler **handler_p;
747 struct handler **handler_p2;
748 struct handlers *the_handlers;
749 const char *sym, *sym2;
751 servicefn func, func2;
752 int mod_type = PAM_MT_FAULTY_MOD;
755 IF_NO_PAMH("_pam_add_handler",pamh,PAM_SYSTEM_ERR);
757 D(("_pam_add_handler: adding type %d, handler_type %d, module `%s'",
758 type, handler_type, mod_path));
760 if ((handler_type == PAM_HT_MODULE || handler_type == PAM_HT_SILENT_MODULE) &&
762 if (mod_path[0] == '/') {
763 mod = _pam_load_module(pamh, mod_path, handler_type);
764 } else if (asprintf(&mod_full_path, "%s%s",
765 DEFAULT_MODULE_PATH, mod_path) >= 0) {
766 mod = _pam_load_module(pamh, mod_full_path, handler_type);
767 _pam_drop(mod_full_path);
769 pam_syslog(pamh, LOG_CRIT, "cannot malloc full mod path");
774 /* if we get here with NULL it means allocation error */
778 mod_type = mod->type;
781 if (mod_path == NULL)
782 mod_path = UNKNOWN_MODULE;
785 * At this point 'mod' points to the stored/loaded module.
788 /* Now define the handler(s) based on mod->dlhandle and type */
790 /* decide which list of handlers to use */
791 the_handlers = (other) ? &pamh->handlers.other : &pamh->handlers.conf;
793 handler_p = handler_p2 = NULL;
797 /* point handler_p's at the root addresses of the function stacks */
800 handler_p = &the_handlers->authenticate;
801 sym = "pam_sm_authenticate";
802 handler_p2 = &the_handlers->setcred;
803 sym2 = "pam_sm_setcred";
806 handler_p = &the_handlers->open_session;
807 sym = "pam_sm_open_session";
808 handler_p2 = &the_handlers->close_session;
809 sym2 = "pam_sm_close_session";
812 handler_p = &the_handlers->acct_mgmt;
813 sym = "pam_sm_acct_mgmt";
816 handler_p = &the_handlers->chauthtok;
817 sym = "pam_sm_chauthtok";
820 /* Illegal module type */
821 D(("_pam_add_handler: illegal module type %d", type));
825 /* are the modules reliable? */
828 mod_type != PAM_MT_STATIC_MOD
831 mod_type != PAM_MT_DYNAMIC_MOD
834 mod_type != PAM_MT_FAULTY_MOD
836 D(("_pam_add_handlers: illegal module library type; %d", mod_type));
837 pam_syslog(pamh, LOG_ERR,
838 "internal error: module library type not known: %s;%d",
843 /* now identify this module's functions - for non-faulty modules */
846 if ((mod_type == PAM_MT_STATIC_MOD) &&
847 (func = (servicefn)_pam_get_static_sym(mod->dl_handle, sym)) == NULL) {
848 pam_syslog(pamh, LOG_ERR, "unable to resolve static symbol: %s", sym);
851 if ((mod_type == PAM_MT_DYNAMIC_MOD) &&
852 !(func = _pam_dlsym(mod->dl_handle, sym)) ) {
853 pam_syslog(pamh, LOG_ERR, "unable to resolve symbol: %s", sym);
858 if ((mod_type == PAM_MT_STATIC_MOD) &&
859 (func2 = (servicefn)_pam_get_static_sym(mod->dl_handle, sym2))
861 pam_syslog(pamh, LOG_ERR, "unable to resolve symbol: %s", sym2);
864 if ((mod_type == PAM_MT_DYNAMIC_MOD) &&
865 !(func2 = _pam_dlsym(mod->dl_handle, sym2)) ) {
866 pam_syslog(pamh, LOG_ERR, "unable to resolve symbol: %s", sym2);
871 /* here func (and perhaps func2) point to the appropriate functions */
873 /* add new handler to end of existing list */
874 while (*handler_p != NULL) {
875 handler_p = &((*handler_p)->next);
878 if ((*handler_p = malloc(sizeof(struct handler))) == NULL) {
879 pam_syslog(pamh, LOG_CRIT, "cannot malloc struct handler #1");
883 (*handler_p)->handler_type = handler_type;
884 (*handler_p)->stack_level = stack_level;
885 (*handler_p)->func = func;
886 memcpy((*handler_p)->actions,actions,sizeof((*handler_p)->actions));
887 (*handler_p)->cached_retval = _PAM_INVALID_RETVAL;
888 (*handler_p)->cached_retval_p = &((*handler_p)->cached_retval);
889 (*handler_p)->argc = argc;
890 (*handler_p)->argv = argv; /* not a copy */
891 (*handler_p)->mod_name = extract_modulename(mod_path);
892 (*handler_p)->next = NULL;
894 /* some of the modules have a second calling function */
896 /* add new handler to end of existing list */
897 while (*handler_p2) {
898 handler_p2 = &((*handler_p2)->next);
901 if ((*handler_p2 = malloc(sizeof(struct handler))) == NULL) {
902 pam_syslog(pamh, LOG_CRIT, "cannot malloc struct handler #2");
906 (*handler_p2)->handler_type = handler_type;
907 (*handler_p2)->stack_level = stack_level;
908 (*handler_p2)->func = func2;
909 memcpy((*handler_p2)->actions,actions,sizeof((*handler_p2)->actions));
910 (*handler_p2)->cached_retval = _PAM_INVALID_RETVAL; /* ignored */
911 /* Note, this next entry points to the handler_p value! */
912 (*handler_p2)->cached_retval_p = &((*handler_p)->cached_retval);
913 (*handler_p2)->argc = argc;
915 if (((*handler_p2)->argv = malloc(argvlen)) == NULL) {
916 pam_syslog(pamh, LOG_CRIT, "cannot malloc argv for handler #2");
919 memcpy((*handler_p2)->argv, argv, argvlen);
921 (*handler_p2)->argv = NULL; /* no arguments */
923 (*handler_p2)->mod_name = extract_modulename(mod_path);
924 (*handler_p2)->next = NULL;
927 D(("_pam_add_handler: returning successfully"));
932 /* Free various allocated structures and dlclose() the libs */
933 int _pam_free_handlers(pam_handle_t *pamh)
935 struct loaded_module *mod;
938 IF_NO_PAMH("_pam_free_handlers",pamh,PAM_SYSTEM_ERR);
940 mod = pamh->handlers.module;
942 /* Close all loaded modules */
944 while (pamh->handlers.modules_used) {
945 D(("_pam_free_handlers: dlclose(%s)", mod->name));
948 if (mod->type == PAM_MT_DYNAMIC_MOD) {
949 _pam_dlclose(mod->dl_handle);
953 pamh->handlers.modules_used--;
956 /* Free all the handlers */
958 _pam_free_handlers_aux(&(pamh->handlers.conf.authenticate));
959 _pam_free_handlers_aux(&(pamh->handlers.conf.setcred));
960 _pam_free_handlers_aux(&(pamh->handlers.conf.acct_mgmt));
961 _pam_free_handlers_aux(&(pamh->handlers.conf.open_session));
962 _pam_free_handlers_aux(&(pamh->handlers.conf.close_session));
963 _pam_free_handlers_aux(&(pamh->handlers.conf.chauthtok));
965 _pam_free_handlers_aux(&(pamh->handlers.other.authenticate));
966 _pam_free_handlers_aux(&(pamh->handlers.other.setcred));
967 _pam_free_handlers_aux(&(pamh->handlers.other.acct_mgmt));
968 _pam_free_handlers_aux(&(pamh->handlers.other.open_session));
969 _pam_free_handlers_aux(&(pamh->handlers.other.close_session));
970 _pam_free_handlers_aux(&(pamh->handlers.other.chauthtok));
972 /* no more loaded modules */
974 _pam_drop(pamh->handlers.module);
976 /* Indicate that handlers are not initialized for this pamh */
978 pamh->handlers.handlers_loaded = 0;
983 void _pam_start_handlers(pam_handle_t *pamh)
986 /* NB. There is no check for a NULL pamh here, since no return
987 * value to communicate the fact! */
989 /* Indicate that handlers are not initialized for this pamh */
990 pamh->handlers.handlers_loaded = 0;
992 pamh->handlers.modules_allocated = 0;
993 pamh->handlers.modules_used = 0;
994 pamh->handlers.module = NULL;
996 /* initialize the .conf and .other entries */
998 pamh->handlers.conf.authenticate = NULL;
999 pamh->handlers.conf.setcred = NULL;
1000 pamh->handlers.conf.acct_mgmt = NULL;
1001 pamh->handlers.conf.open_session = NULL;
1002 pamh->handlers.conf.close_session = NULL;
1003 pamh->handlers.conf.chauthtok = NULL;
1005 pamh->handlers.other.authenticate = NULL;
1006 pamh->handlers.other.setcred = NULL;
1007 pamh->handlers.other.acct_mgmt = NULL;
1008 pamh->handlers.other.open_session = NULL;
1009 pamh->handlers.other.close_session = NULL;
1010 pamh->handlers.other.chauthtok = NULL;
1013 void _pam_free_handlers_aux(struct handler **hp)
1015 struct handler *h = *hp;
1016 struct handler *last;
1021 _pam_drop(h->argv); /* This is all alocated in a single chunk */
1022 _pam_drop(h->mod_name);
1024 memset(last, 0, sizeof(*last));