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 */
112 } else if (!strcasecmp("auth", tok)) {
113 module_type = PAM_T_AUTH;
114 } else if (!strcasecmp("session", tok)) {
115 module_type = PAM_T_SESS;
116 } else if (!strcasecmp("account", tok)) {
117 module_type = PAM_T_ACCT;
118 } else if (!strcasecmp("password", tok)) {
119 module_type = PAM_T_PASS;
121 /* Illegal module type */
122 D(("_pam_init_handlers: bad module type: %s", tok));
123 pam_syslog(pamh, LOG_ERR, "(%s) illegal module type: %s",
125 module_type = (requested_module_type != PAM_T_ANY) ?
126 requested_module_type : PAM_T_AUTH; /* most sensitive */
127 handler_type = PAM_HT_MUST_FAIL; /* install as normal but fail when dispatched */
129 D(("Using %s config entry: %s", handler_type?"BAD ":"", tok));
130 if (requested_module_type != PAM_T_ANY &&
131 module_type != requested_module_type) {
132 D(("Skipping config entry: %s (requested=%d, found=%d)",
133 tok, requested_module_type, module_type));
137 /* reset the actions to .._UNDEF's -- this is so that
138 we can work out which entries are not yet set (for default). */
141 for (i=0; i<_PAM_RETURN_VALUES;
142 actions[i++] = _PAM_ACTION_UNDEF);
144 tok = _pam_StrTok(NULL, " \n\t", &nexttok);
146 /* no module name given */
147 D(("_pam_init_handlers: no control flag supplied"));
148 pam_syslog(pamh, LOG_ERR,
149 "(%s) no control flag supplied", this_service);
150 _pam_set_default_control(actions, _PAM_ACTION_BAD);
151 handler_type = PAM_HT_MUST_FAIL;
152 } else if (!strcasecmp("required", tok)) {
153 D(("*PAM_F_REQUIRED*"));
154 actions[PAM_SUCCESS] = _PAM_ACTION_OK;
155 actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
156 actions[PAM_IGNORE] = _PAM_ACTION_IGNORE;
157 _pam_set_default_control(actions, _PAM_ACTION_BAD);
158 } else if (!strcasecmp("requisite", tok)) {
159 D(("*PAM_F_REQUISITE*"));
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_DIE);
164 } else if (!strcasecmp("optional", tok)) {
165 D(("*PAM_F_OPTIONAL*"));
166 actions[PAM_SUCCESS] = _PAM_ACTION_OK;
167 actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
168 _pam_set_default_control(actions, _PAM_ACTION_IGNORE);
169 } else if (!strcasecmp("sufficient", tok)) {
170 D(("*PAM_F_SUFFICIENT*"));
171 actions[PAM_SUCCESS] = _PAM_ACTION_DONE;
172 actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_DONE;
173 _pam_set_default_control(actions, _PAM_ACTION_IGNORE);
174 } else if (!strcasecmp("include", tok)) {
175 D(("*PAM_F_INCLUDE*"));
178 } else if (!strcasecmp("substack", tok)) {
179 D(("*PAM_F_SUBSTACK*"));
183 D(("will need to parse %s", tok));
184 _pam_parse_control(actions, tok);
185 /* by default the default is to treat as failure */
186 _pam_set_default_control(actions, _PAM_ACTION_BAD);
189 tok = _pam_StrTok(NULL, " \n\t", &nexttok);
192 res = _pam_add_handler(pamh, PAM_HT_SUBSTACK, other,
193 stack_level, module_type, actions, tok,
195 if (res != PAM_SUCCESS) {
196 pam_syslog(pamh, LOG_ERR, "error adding substack %s", tok);
197 D(("failed to load module - aborting"));
201 if (_pam_load_conf_file(pamh, tok, this_service, module_type,
202 stack_level + substack
203 #ifdef PAM_READ_BOTH_CONFS
205 #endif /* PAM_READ_BOTH_CONFS */
208 _pam_set_default_control(actions, _PAM_ACTION_BAD);
210 handler_type = PAM_HT_MUST_FAIL;
212 } else if (tok != NULL) {
214 D(("mod_path = %s",mod_path));
216 /* no module name given */
217 D(("_pam_init_handlers: no module name supplied"));
218 pam_syslog(pamh, LOG_ERR,
219 "(%s) no module name supplied", this_service);
221 handler_type = PAM_HT_MUST_FAIL;
224 /* nexttok points to remaining arguments... */
226 if (nexttok != NULL) {
227 D(("list: %s",nexttok));
228 argvlen = _pam_mkargv(nexttok, &argv, &argc);
229 D(("argvlen = %d",argvlen));
230 } else { /* there are no arguments so fix by hand */
231 D(("_pam_init_handlers: empty argument list"));
240 D(("CONF%s: %s%s %d %s %d"
241 , handler_type==PAM_HT_MUST_FAIL?"<*will fail*>":""
242 , this_service, other ? "(backup)":""
245 for (y = 0; y < argc; y++) {
246 D(("CONF: %s", argv[y]));
248 for (y = 0; y<_PAM_RETURN_VALUES; ++y) {
249 D(("RETURN %s(%d) -> %d %s",
250 _pam_token_returns[y], y, actions[y],
251 actions[y]>0 ? "jump":
252 _pam_token_actions[-actions[y]]));
257 res = _pam_add_handler(pamh, handler_type, other, stack_level
258 , module_type, actions, mod_path
259 , argc, argv, argvlen);
260 if (res != PAM_SUCCESS) {
261 pam_syslog(pamh, LOG_ERR, "error loading %s", mod_path);
262 D(("failed to load module - aborting"));
268 return ( (x < 0) ? PAM_ABORT:PAM_SUCCESS );
271 static int _pam_load_conf_file(pam_handle_t *pamh, const char *config_name
272 , const char *service /* specific file */
273 , int module_type /* specific type */
274 , int stack_level /* level of substack */
275 #ifdef PAM_READ_BOTH_CONFS
277 #endif /* PAM_READ_BOTH_CONFS */
281 char *config_path = NULL;
282 int retval = PAM_ABORT;
284 D(("_pam_load_conf_file called"));
286 if (stack_level >= PAM_SUBSTACK_MAX_LEVEL) {
287 D(("maximum level of substacks reached"));
288 pam_syslog(pamh, LOG_ERR, "maximum level of substacks reached");
292 if (config_name == NULL) {
293 D(("no config file supplied"));
294 pam_syslog(pamh, LOG_ERR, "(%s) no config file supplied", service);
298 if (config_name[0] != '/') {
299 if (asprintf (&config_path, PAM_CONFIG_DF, config_name) < 0) {
300 pam_syslog(pamh, LOG_CRIT, "asprintf failed");
303 config_name = config_path;
306 D(("opening %s", config_name));
307 f = fopen(config_name, "r");
309 retval = _pam_parse_conf_file(pamh, f, service, module_type, stack_level
310 #ifdef PAM_READ_BOTH_CONFS
312 #endif /* PAM_READ_BOTH_CONFS */
315 if (retval != PAM_SUCCESS)
316 pam_syslog(pamh, LOG_ERR,
317 "_pam_load_conf_file: error reading %s: %s",
318 config_name, pam_strerror(pamh, retval));
320 D(("unable to open %s", config_name));
321 pam_syslog(pamh, LOG_ERR,
322 "_pam_load_conf_file: unable to open %s",
326 _pam_drop(config_path);
330 /* Parse config file, allocate handler structures, dlopen() */
331 int _pam_init_handlers(pam_handle_t *pamh)
336 D(("_pam_init_handlers called"));
337 IF_NO_PAMH("_pam_init_handlers",pamh,PAM_SYSTEM_ERR);
339 /* Return immediately if everything is already loaded */
340 if (pamh->handlers.handlers_loaded) {
344 D(("_pam_init_handlers: initializing"));
346 /* First clean the service structure */
348 _pam_free_handlers(pamh);
349 if (! pamh->handlers.module) {
350 if ((pamh->handlers.module =
351 malloc(MODULE_CHUNK * sizeof(struct loaded_module))) == NULL) {
352 pam_syslog(pamh, LOG_CRIT,
353 "_pam_init_handlers: no memory loading module");
356 pamh->handlers.modules_allocated = MODULE_CHUNK;
357 pamh->handlers.modules_used = 0;
360 if (pamh->service_name == NULL) {
361 return PAM_BAD_ITEM; /* XXX - better error? */
365 /* Is the PAM subsystem locked? */
369 if ((fd_tmp = open( PAM_LOCK_FILE, O_RDONLY )) != -1) {
370 pam_syslog(pamh, LOG_ERR,
371 "_pam_init_handlers: PAM lockfile ("
372 PAM_LOCK_FILE ") exists - aborting");
373 (void) close(fd_tmp);
375 * to avoid swamping the system with requests
377 _pam_start_timer(pamh);
378 pam_fail_delay(pamh, 5000000);
379 _pam_await_timer(pamh, PAM_ABORT);
384 #endif /* PAM_LOCKING */
387 * Now parse the config file(s) and add handlers
392 /* Is there a PAM_CONFIG_D directory? */
393 if ( stat(PAM_CONFIG_D, &test_d) == 0 && S_ISDIR(test_d.st_mode) ) {
395 int read_something=0;
397 D(("searching " PAM_CONFIG_D " for config files"));
398 if (asprintf(&filename, PAM_CONFIG_DF, pamh->service_name) < 0) {
399 pam_syslog(pamh, LOG_ERR,
400 "_pam_init_handlers: no memory; service %s",
404 D(("opening %s", filename));
405 f = fopen(filename, "r");
407 /* would test magic here? */
408 retval = _pam_parse_conf_file(pamh, f, pamh->service_name,
410 #ifdef PAM_READ_BOTH_CONFS
412 #endif /* PAM_READ_BOTH_CONFS */
415 if (retval != PAM_SUCCESS) {
416 pam_syslog(pamh, LOG_ERR,
417 "_pam_init_handlers: error reading %s",
419 pam_syslog(pamh, LOG_ERR, "_pam_init_handlers: [%s]",
420 pam_strerror(pamh, retval));
425 D(("unable to open %s", filename));
426 #ifdef PAM_READ_BOTH_CONFS
427 D(("checking %s", PAM_CONFIG));
429 if ((f = fopen(PAM_CONFIG,"r")) != NULL) {
430 retval = _pam_parse_conf_file(pamh, f, NULL, PAM_T_ANY, 0, 1);
433 #endif /* PAM_READ_BOTH_CONFS */
434 retval = PAM_SUCCESS;
436 * XXX - should we log an error? Some people want to always
442 if (retval == PAM_SUCCESS) {
443 /* now parse the PAM_DEFAULT_SERVICE_FILE */
445 D(("opening %s", PAM_DEFAULT_SERVICE_FILE));
446 f = fopen(PAM_DEFAULT_SERVICE_FILE, "r");
448 /* would test magic here? */
449 retval = _pam_parse_conf_file(pamh, f, PAM_DEFAULT_SERVICE,
451 #ifdef PAM_READ_BOTH_CONFS
453 #endif /* PAM_READ_BOTH_CONFS */
456 if (retval != PAM_SUCCESS) {
457 pam_syslog(pamh, LOG_ERR,
458 "_pam_init_handlers: error reading %s",
459 PAM_DEFAULT_SERVICE_FILE);
460 pam_syslog(pamh, LOG_ERR,
461 "_pam_init_handlers: [%s]",
462 pam_strerror(pamh, retval));
467 D(("unable to open %s", PAM_DEFAULT_SERVICE_FILE));
468 pam_syslog(pamh, LOG_ERR,
469 "_pam_init_handlers: no default config %s",
470 PAM_DEFAULT_SERVICE_FILE);
472 if (!read_something) { /* nothing read successfully */
477 if ((f = fopen(PAM_CONFIG, "r")) == NULL) {
478 pam_syslog(pamh, LOG_ERR, "_pam_init_handlers: could not open "
483 retval = _pam_parse_conf_file(pamh, f, NULL, PAM_T_ANY, 0
484 #ifdef PAM_READ_BOTH_CONFS
486 #endif /* PAM_READ_BOTH_CONFS */
489 D(("closing configuration file"));
494 if (retval != PAM_SUCCESS) {
496 pam_syslog(pamh, LOG_ERR, "error reading PAM configuration file");
500 pamh->handlers.handlers_loaded = 1;
502 D(("_pam_init_handlers exiting"));
507 * This is where we read a line of the PAM config file. The line may be
508 * preceeded by lines of comments and also extended with "\\\n"
511 static int _pam_assemble_line(FILE *f, char *buffer, int buf_len)
517 /* loop broken with a 'break' when a non-'\\n' ended line is read */
521 if (used >= buf_len) {
523 D(("_pam_assemble_line: overflow"));
526 if (fgets(p, buf_len - used, f) == NULL) {
528 /* Incomplete read */
536 /* skip leading spaces --- line may be blank */
538 s = p + strspn(p, " \n\t");
539 if (*s && (*s != '#')) {
543 * we are only interested in characters before the first '#'
547 while (*s && *s != '#')
552 break; /* the line has been read */
558 * Check for backslash by scanning back from the end of
559 * the entered line, the '\n' has been included since
560 * normally a line is terminated with this
561 * character. fgets() should only return one though!
565 while (s > os && ((*--s == ' ') || (*s == '\t')
568 /* check if it ends with a backslash */
570 *s++ = ' '; /* replace backslash with ' ' */
571 *s = '\0'; /* truncate the line here */
573 p = s; /* there is more ... */
575 /* End of the line! */
577 break; /* this is the complete line */
581 /* Nothing in this line */
590 extract_modulename(const char *mod_path)
592 const char *p = strrchr (mod_path, '/');
600 if ((retval = _pam_strdup (p)) == NULL)
603 dot = strrchr (retval, '.');
610 static struct loaded_module *
611 _pam_load_module(pam_handle_t *pamh, const char *mod_path)
616 char *mod_full_isa_path=NULL, *isa=NULL;
618 struct loaded_module *mod;
620 D(("_pam_load_module: loading module `%s'", mod_path));
622 mod = pamh->handlers.module;
624 /* First, ensure the module is loaded */
625 while (x < pamh->handlers.modules_used) {
626 if (!strcmp(mod[x].name, mod_path)) { /* case sensitive ! */
631 if (x == pamh->handlers.modules_used) {
633 if (pamh->handlers.modules_allocated == pamh->handlers.modules_used) {
634 /* will need more memory */
635 void *tmp = realloc(pamh->handlers.module,
636 (pamh->handlers.modules_allocated+MODULE_CHUNK)
637 *sizeof(struct loaded_module));
639 D(("cannot enlarge module pointer memory"));
640 pam_syslog(pamh, LOG_ERR,
641 "realloc returned NULL in _pam_load_module");
644 pamh->handlers.module = tmp;
645 pamh->handlers.modules_allocated += MODULE_CHUNK;
647 mod = &(pamh->handlers.module[x]);
648 /* Be pessimistic... */
652 /* Only load static function if function was not found dynamically.
653 * This code should work even if no dynamic loading is available. */
654 if (success != PAM_SUCCESS) {
655 D(("_pam_load_module: open static handler %s", mod_path));
656 mod->dl_handle = _pam_open_static_handler(pamh, mod_path);
657 if (mod->dl_handle == NULL) {
658 D(("_pam_load_module: unable to find static handler %s",
660 pam_syslog(pamh, LOG_ERR,
661 "unable to open static handler %s", mod_path);
662 /* Didn't find module in dynamic or static..will mark bad */
664 D(("static module added successfully"));
665 success = PAM_SUCCESS;
666 mod->type = PAM_MT_STATIC_MOD;
667 pamh->handlers.modules_used++;
671 D(("_pam_load_module: _pam_dlopen(%s)", mod_path));
672 mod->dl_handle = _pam_dlopen(mod_path);
673 D(("_pam_load_module: _pam_dlopen'ed"));
674 D(("_pam_load_module: dlopen'ed"));
675 if (mod->dl_handle == NULL) {
676 if (strstr(mod_path, "$ISA")) {
677 mod_full_isa_path = malloc(strlen(mod_path) + strlen(_PAM_ISA) + 1);
678 if (mod_full_isa_path == NULL) {
679 D(("_pam_load_module: couldn't get memory for mod_path"));
680 pam_syslog(pamh, LOG_ERR, "no memory for module path");
683 strcpy(mod_full_isa_path, mod_path);
684 isa = strstr(mod_full_isa_path, "$ISA");
686 memmove(isa + strlen(_PAM_ISA), isa + 4, strlen(isa + 4) + 1);
687 memmove(isa, _PAM_ISA, strlen(_PAM_ISA));
689 mod->dl_handle = _pam_dlopen(mod_full_isa_path);
690 _pam_drop(mod_full_isa_path);
694 if (mod->dl_handle == NULL) {
695 D(("_pam_load_module: _pam_dlopen(%s) failed", mod_path));
696 pam_syslog(pamh, LOG_ERR, "unable to dlopen(%s): %s", mod_path,
698 /* Don't abort yet; static code may be able to find function.
699 * But defaults to abort if nothing found below... */
701 D(("module added successfully"));
702 success = PAM_SUCCESS;
703 mod->type = PAM_MT_DYNAMIC_MOD;
704 pamh->handlers.modules_used++;
708 if (success != PAM_SUCCESS) { /* add a malformed module */
709 mod->dl_handle = NULL;
710 mod->type = PAM_MT_FAULTY_MOD;
711 pamh->handlers.modules_used++;
712 pam_syslog(pamh, LOG_ERR, "adding faulty module: %s", mod_path);
713 success = PAM_SUCCESS; /* We have successfully added a module */
716 /* indicate its name - later we will search for it by this */
717 if ((mod->name = _pam_strdup(mod_path)) == NULL) {
718 D(("_pam_load_module: couldn't get memory for mod_path"));
719 pam_syslog(pamh, LOG_ERR, "no memory for module path");
723 } else { /* x != pamh->handlers.modules_used */
724 mod += x; /* the located module */
725 success = PAM_SUCCESS;
727 return success == PAM_SUCCESS ? mod : NULL;
730 int _pam_add_handler(pam_handle_t *pamh
731 , int handler_type, int other, int stack_level, int type
732 , int *actions, const char *mod_path
733 , int argc, char **argv, int argvlen)
735 struct loaded_module *mod = NULL;
736 struct handler **handler_p;
737 struct handler **handler_p2;
738 struct handlers *the_handlers;
739 const char *sym, *sym2;
741 servicefn func, func2;
742 int mod_type = PAM_MT_FAULTY_MOD;
745 IF_NO_PAMH("_pam_add_handler",pamh,PAM_SYSTEM_ERR);
747 D(("_pam_add_handler: adding type %d, handler_type %d, module `%s'",
748 type, handler_type, mod_path));
750 if (handler_type == PAM_HT_MODULE && mod_path != NULL) {
751 if (mod_path[0] == '/') {
752 mod = _pam_load_module(pamh, mod_path);
753 } else if (asprintf(&mod_full_path, "%s%s",
754 DEFAULT_MODULE_PATH, mod_path) >= 0) {
755 mod = _pam_load_module(pamh, mod_full_path);
756 _pam_drop(mod_full_path);
758 pam_syslog(pamh, LOG_CRIT, "cannot malloc full mod path");
763 /* if we get here with NULL it means allocation error */
767 mod_type = mod->type;
770 if (mod_path == NULL)
771 mod_path = UNKNOWN_MODULE;
774 * At this point 'mod' points to the stored/loaded module.
777 /* Now define the handler(s) based on mod->dlhandle and type */
779 /* decide which list of handlers to use */
780 the_handlers = (other) ? &pamh->handlers.other : &pamh->handlers.conf;
782 handler_p = handler_p2 = NULL;
786 /* point handler_p's at the root addresses of the function stacks */
789 handler_p = &the_handlers->authenticate;
790 sym = "pam_sm_authenticate";
791 handler_p2 = &the_handlers->setcred;
792 sym2 = "pam_sm_setcred";
795 handler_p = &the_handlers->open_session;
796 sym = "pam_sm_open_session";
797 handler_p2 = &the_handlers->close_session;
798 sym2 = "pam_sm_close_session";
801 handler_p = &the_handlers->acct_mgmt;
802 sym = "pam_sm_acct_mgmt";
805 handler_p = &the_handlers->chauthtok;
806 sym = "pam_sm_chauthtok";
809 /* Illegal module type */
810 D(("_pam_add_handler: illegal module type %d", type));
814 /* are the modules reliable? */
817 mod_type != PAM_MT_STATIC_MOD
820 mod_type != PAM_MT_DYNAMIC_MOD
823 mod_type != PAM_MT_FAULTY_MOD
825 D(("_pam_add_handlers: illegal module library type; %d", mod_type));
826 pam_syslog(pamh, LOG_ERR,
827 "internal error: module library type not known: %s;%d",
832 /* now identify this module's functions - for non-faulty modules */
835 if ((mod_type == PAM_MT_STATIC_MOD) &&
836 (func = (servicefn)_pam_get_static_sym(mod->dl_handle, sym)) == NULL) {
837 pam_syslog(pamh, LOG_ERR, "unable to resolve static symbol: %s", sym);
840 if ((mod_type == PAM_MT_DYNAMIC_MOD) &&
841 !(func = _pam_dlsym(mod->dl_handle, sym)) ) {
842 pam_syslog(pamh, LOG_ERR, "unable to resolve symbol: %s", sym);
847 if ((mod_type == PAM_MT_STATIC_MOD) &&
848 (func2 = (servicefn)_pam_get_static_sym(mod->dl_handle, sym2))
850 pam_syslog(pamh, LOG_ERR, "unable to resolve symbol: %s", sym2);
853 if ((mod_type == PAM_MT_DYNAMIC_MOD) &&
854 !(func2 = _pam_dlsym(mod->dl_handle, sym2)) ) {
855 pam_syslog(pamh, LOG_ERR, "unable to resolve symbol: %s", sym2);
860 /* here func (and perhaps func2) point to the appropriate functions */
862 /* add new handler to end of existing list */
863 while (*handler_p != NULL) {
864 handler_p = &((*handler_p)->next);
867 if ((*handler_p = malloc(sizeof(struct handler))) == NULL) {
868 pam_syslog(pamh, LOG_CRIT, "cannot malloc struct handler #1");
872 (*handler_p)->handler_type = handler_type;
873 (*handler_p)->stack_level = stack_level;
874 (*handler_p)->func = func;
875 memcpy((*handler_p)->actions,actions,sizeof((*handler_p)->actions));
876 (*handler_p)->cached_retval = _PAM_INVALID_RETVAL;
877 (*handler_p)->cached_retval_p = &((*handler_p)->cached_retval);
878 (*handler_p)->argc = argc;
879 (*handler_p)->argv = argv; /* not a copy */
880 (*handler_p)->mod_name = extract_modulename(mod_path);
881 (*handler_p)->next = NULL;
883 /* some of the modules have a second calling function */
885 /* add new handler to end of existing list */
886 while (*handler_p2) {
887 handler_p2 = &((*handler_p2)->next);
890 if ((*handler_p2 = malloc(sizeof(struct handler))) == NULL) {
891 pam_syslog(pamh, LOG_CRIT, "cannot malloc struct handler #2");
895 (*handler_p2)->handler_type = handler_type;
896 (*handler_p2)->stack_level = stack_level;
897 (*handler_p2)->func = func2;
898 memcpy((*handler_p2)->actions,actions,sizeof((*handler_p2)->actions));
899 (*handler_p2)->cached_retval = _PAM_INVALID_RETVAL; /* ignored */
900 /* Note, this next entry points to the handler_p value! */
901 (*handler_p2)->cached_retval_p = &((*handler_p)->cached_retval);
902 (*handler_p2)->argc = argc;
904 if (((*handler_p2)->argv = malloc(argvlen)) == NULL) {
905 pam_syslog(pamh, LOG_CRIT, "cannot malloc argv for handler #2");
908 memcpy((*handler_p2)->argv, argv, argvlen);
910 (*handler_p2)->argv = NULL; /* no arguments */
912 (*handler_p2)->mod_name = extract_modulename(mod_path);
913 (*handler_p2)->next = NULL;
916 D(("_pam_add_handler: returning successfully"));
921 /* Free various allocated structures and dlclose() the libs */
922 int _pam_free_handlers(pam_handle_t *pamh)
924 struct loaded_module *mod;
927 IF_NO_PAMH("_pam_free_handlers",pamh,PAM_SYSTEM_ERR);
929 mod = pamh->handlers.module;
931 /* Close all loaded modules */
933 while (pamh->handlers.modules_used) {
934 D(("_pam_free_handlers: dlclose(%s)", mod->name));
937 if (mod->type == PAM_MT_DYNAMIC_MOD) {
938 _pam_dlclose(mod->dl_handle);
942 pamh->handlers.modules_used--;
945 /* Free all the handlers */
947 _pam_free_handlers_aux(&(pamh->handlers.conf.authenticate));
948 _pam_free_handlers_aux(&(pamh->handlers.conf.setcred));
949 _pam_free_handlers_aux(&(pamh->handlers.conf.acct_mgmt));
950 _pam_free_handlers_aux(&(pamh->handlers.conf.open_session));
951 _pam_free_handlers_aux(&(pamh->handlers.conf.close_session));
952 _pam_free_handlers_aux(&(pamh->handlers.conf.chauthtok));
954 _pam_free_handlers_aux(&(pamh->handlers.other.authenticate));
955 _pam_free_handlers_aux(&(pamh->handlers.other.setcred));
956 _pam_free_handlers_aux(&(pamh->handlers.other.acct_mgmt));
957 _pam_free_handlers_aux(&(pamh->handlers.other.open_session));
958 _pam_free_handlers_aux(&(pamh->handlers.other.close_session));
959 _pam_free_handlers_aux(&(pamh->handlers.other.chauthtok));
961 /* no more loaded modules */
963 _pam_drop(pamh->handlers.module);
965 /* Indicate that handlers are not initialized for this pamh */
967 pamh->handlers.handlers_loaded = 0;
972 void _pam_start_handlers(pam_handle_t *pamh)
975 /* NB. There is no check for a NULL pamh here, since no return
976 * value to communicate the fact! */
978 /* Indicate that handlers are not initialized for this pamh */
979 pamh->handlers.handlers_loaded = 0;
981 pamh->handlers.modules_allocated = 0;
982 pamh->handlers.modules_used = 0;
983 pamh->handlers.module = NULL;
985 /* initialize the .conf and .other entries */
987 pamh->handlers.conf.authenticate = NULL;
988 pamh->handlers.conf.setcred = NULL;
989 pamh->handlers.conf.acct_mgmt = NULL;
990 pamh->handlers.conf.open_session = NULL;
991 pamh->handlers.conf.close_session = NULL;
992 pamh->handlers.conf.chauthtok = NULL;
994 pamh->handlers.other.authenticate = NULL;
995 pamh->handlers.other.setcred = NULL;
996 pamh->handlers.other.acct_mgmt = NULL;
997 pamh->handlers.other.open_session = NULL;
998 pamh->handlers.other.close_session = NULL;
999 pamh->handlers.other.chauthtok = NULL;
1002 void _pam_free_handlers_aux(struct handler **hp)
1004 struct handler *h = *hp;
1005 struct handler *last;
1010 _pam_drop(h->argv); /* This is all alocated in a single chunk */
1011 _pam_drop(h->mod_name);
1013 memset(last, 0, sizeof(*last));