1 /* pam_handlers.c -- pam config file parsing and module loading */
4 * created by Marc Ewing.
5 * Currently maintained by Andrew G. Morgan <morgan@linux.kernel.org>
7 * $Id: pam_handlers.c,v 1.17 1997/04/05 06:55:24 morgan Exp morgan $
8 * $FreeBSD: src/contrib/libpam/libpam/pam_handlers.c,v 1.1.1.1.6.2 2001/06/11 15:28:12 markm Exp $
9 * $DragonFly: src/contrib/libpam/libpam/Attic/pam_handlers.c,v 1.2 2003/06/17 04:24:03 dillon Exp $
16 #include <sys/types.h>
26 #include "pam_private.h"
28 /* FreeBSD doesn't define this */
33 /* If not required, define as nothing - FreeBSD needs it to be "_"... */
34 #ifndef SHLIB_SYM_PREFIX
35 # define SHLIB_SYM_PREFIX ""
39 #define MODULE_CHUNK 4
41 static int _pam_assemble_line(FILE *f, char *buf, int buf_len);
43 static void _pam_free_handlers_aux(struct handler **hp);
45 static int _pam_add_handler(pam_handle_t *pamh
46 , int must_fail, int other, int type
47 , int *actions, const char *mod_path
48 , int argc, char **argv, int argvlen);
50 /* Values for module type */
57 static int _pam_parse_conf_file(pam_handle_t *pamh, FILE *f
58 , const char *known_service /* specific file */
59 #ifdef PAM_READ_BOTH_CONFS
61 #endif /* PAM_READ_BOTH_CONFS */
65 int x; /* read a line from the FILE *f ? */
67 * read a line from the configuration (FILE *) f
69 while ((x = _pam_assemble_line(f, buf, BUF_SIZE)) > 0) {
70 char *tok, *nexttok=NULL;
71 const char *this_service;
73 int module_type, actions[_PAM_RETURN_VALUES];
74 int other; /* set if module is for PAM_DEFAULT_SERVICE */
75 int res; /* module added successfully? */
76 int must_fail=0; /* a badly formatted line must fail when used */
81 D(("_pam_init_handler: LINE: %s", buf));
82 if (known_service != NULL) {
84 /* No service field: all lines are for the known service. */
85 this_service = known_service;
87 this_service = tok = _pam_StrTok(buf, " \n\t", &nexttok);
90 #ifdef PAM_READ_BOTH_CONFS
94 #endif /* PAM_READ_BOTH_CONFS */
95 other = !_pam_strCMP(this_service, PAM_DEFAULT_SERVICE);
97 /* accept "service name" or PAM_DEFAULT_SERVICE modules */
98 if (!_pam_strCMP(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);
104 if (!_pam_strCMP("auth", tok)) {
105 module_type = PAM_T_AUTH;
106 } else if (!_pam_strCMP("session", tok)) {
107 module_type = PAM_T_SESS;
108 } else if (!_pam_strCMP("account", tok)) {
109 module_type = PAM_T_ACCT;
110 } else if (!_pam_strCMP("password", tok)) {
111 module_type = PAM_T_PASS;
113 /* Illegal module type */
114 D(("_pam_init_handlers: bad module type: %s", tok));
115 pam_system_log(pamh, NULL, LOG_ERR,
116 "(%s) illegal module type: %s"
117 , this_service, tok);
118 module_type = PAM_T_AUTH; /* most sensitive */
119 must_fail = 1; /* install as normal but fail when dispatched */
121 D(("Using %s config entry: %s", must_fail?"BAD ":"", tok));
123 /* reset the actions to .._UNDEF's -- this is so that
124 we can work out which entries are not yet set (for default). */
127 for (i=0; i<_PAM_RETURN_VALUES;
128 actions[i++] = _PAM_ACTION_UNDEF);
130 tok = _pam_StrTok(NULL, " \n\t", &nexttok);
131 if (!_pam_strCMP("required", tok)) {
132 D(("*PAM_F_REQUIRED*"));
133 actions[PAM_SUCCESS] = _PAM_ACTION_OK;
134 actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
135 actions[PAM_IGNORE] = _PAM_ACTION_IGNORE;
136 _pam_set_default_control(actions, _PAM_ACTION_BAD);
137 } else if (!_pam_strCMP("requisite", tok)) {
138 D(("*PAM_F_REQUISITE*"));
139 actions[PAM_SUCCESS] = _PAM_ACTION_OK;
140 actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
141 actions[PAM_IGNORE] = _PAM_ACTION_IGNORE;
142 _pam_set_default_control(actions, _PAM_ACTION_DIE);
143 } else if (!_pam_strCMP("optional", tok)) {
144 D(("*PAM_F_OPTIONAL*"));
145 actions[PAM_SUCCESS] = _PAM_ACTION_OK;
146 actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
147 _pam_set_default_control(actions, _PAM_ACTION_IGNORE);
148 } else if (!_pam_strCMP("sufficient", tok)) {
149 D(("*PAM_F_SUFFICIENT*"));
150 actions[PAM_SUCCESS] = _PAM_ACTION_DONE;
151 actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_DONE;
152 _pam_set_default_control(actions, _PAM_ACTION_IGNORE);
154 D(("will need to parse %s", tok));
155 _pam_parse_control(actions, tok);
156 /* by default the default is to treat as failure */
157 _pam_set_default_control(actions, _PAM_ACTION_BAD);
160 tok = _pam_StrTok(NULL, " \n\t", &nexttok);
163 D(("mod_path = %s",mod_path));
165 /* no module name given */
166 D(("_pam_init_handlers: no module name supplied"));
167 pam_system_log(pamh, NULL, LOG_ERR,
168 "(%s) no module name supplied", this_service);
173 /* nexttok points to remaining arguments... */
175 if (nexttok != NULL) {
176 D(("list: %s",nexttok));
177 argvlen = _pam_mkargv(nexttok, &argv, &argc);
178 D(("argvlen = %d",argvlen));
179 } else { /* there are no arguments so fix by hand */
180 D(("_pam_init_handlers: empty argument list"));
189 D(("CONF%s: %s%s %d %s %d"
190 , must_fail?"<*will fail*>":""
191 , this_service, other ? "(backup)":""
194 for (y = 0; y < argc; y++) {
195 D(("CONF: %s", argv[y]));
197 for (y = 0; y<_PAM_RETURN_VALUES; ++y) {
198 D(("RETURN %s(%d) -> %d %s",
199 _pam_token_returns[y], y, actions[y],
200 actions[y]>0 ? "jump":
201 _pam_token_actions[-actions[y]]));
203 fprintf(stderr, "pause to look at debugging: ");
208 res = _pam_add_handler(pamh, must_fail, other
209 , module_type, actions, mod_path
210 , argc, argv, argvlen);
211 if (res != PAM_SUCCESS) {
212 pam_system_log(pamh, NULL, LOG_ERR,
213 "error loading %s", mod_path);
214 D(("failed to load module - aborting"));
220 return ( (x < 0) ? PAM_ABORT:PAM_SUCCESS );
223 /* Parse config file, allocate handler structures, dlopen() */
224 int _pam_init_handlers(pam_handle_t *pamh)
229 D(("_pam_init_handlers called"));
230 IF_NO_PAMH("_pam_init_handlers",pamh,PAM_SYSTEM_ERR);
232 /* Return immediately if everything is already loaded */
233 if (pamh->handlers.handlers_loaded) {
237 D(("_pam_init_handlers: initializing"));
239 /* First clean the service structure */
241 _pam_free_handlers(pamh);
242 if (! pamh->handlers.module) {
243 if ((pamh->handlers.module =
244 malloc(MODULE_CHUNK * sizeof(struct loaded_module))) == NULL) {
245 pam_system_log(pamh, NULL, LOG_CRIT,
246 "_pam_init_handlers: no memory loading module");
249 pamh->handlers.modules_allocated = MODULE_CHUNK;
250 pamh->handlers.modules_used = 0;
253 if (pamh->service_name == NULL) {
254 return PAM_BAD_ITEM; /* XXX - better error? */
258 /* Is the PAM subsystem locked? */
262 if ((fd_tmp = open( PAM_LOCK_FILE, O_RDONLY )) != -1) {
263 pam_system_log(pamh, NULL, LOG_ERR,
264 "_pam_init_handlers: PAM lockfile ("
265 PAM_LOCK_FILE ") exists - aborting");
266 (void) close(fd_tmp);
268 * to avoid swamping the system with requests
270 _pam_start_timer(pamh);
271 pam_fail_delay(pamh, 5000000);
272 _pam_await_timer(pamh, PAM_ABORT);
277 #endif /* PAM_LOCKING */
280 * Now parse the config file(s) and add handlers
285 /* Is there a PAM_CONFIG_D directory? */
286 if ( stat(PAM_CONFIG_D, &test_d) == 0 && S_ISDIR(test_d.st_mode) ) {
288 int read_something=0;
290 D(("searching " PAM_CONFIG_D " for config files"));
291 filename = malloc(sizeof(PAM_CONFIG_DF)
292 +strlen(pamh->service_name));
293 if (filename == NULL) {
294 pam_system_log(pamh, NULL, LOG_ERR,
295 "_pam_init_handlers: no memory; service %s",
299 sprintf(filename, PAM_CONFIG_DF, pamh->service_name);
300 D(("opening %s", filename));
301 f = fopen(filename, "r");
303 /* would test magic here? */
304 retval = _pam_parse_conf_file(pamh, f, pamh->service_name
305 #ifdef PAM_READ_BOTH_CONFS
307 #endif /* PAM_READ_BOTH_CONFS */
310 if (retval != PAM_SUCCESS) {
311 pam_system_log(pamh, NULL, LOG_ERR,
312 "_pam_init_handlers: error reading %s",
314 pam_system_log(pamh, NULL, LOG_ERR,
315 "_pam_init_handlers: [%s]",
316 pam_strerror(pamh, retval));
321 D(("unable to open %s", filename));
322 #ifdef PAM_READ_BOTH_CONFS
323 D(("checking %s", PAM_CONFIG));
325 if ((f = fopen(PAM_CONFIG,"r")) != NULL) {
326 retval = _pam_parse_conf_file(pamh, f, NULL, 1);
329 #endif /* PAM_READ_BOTH_CONFS */
330 retval = PAM_SUCCESS;
332 * XXX - should we log an error? Some people want to always
338 if (retval == PAM_SUCCESS) {
339 /* now parse the PAM_DEFAULT_SERVICE_FILE */
341 D(("opening %s", PAM_DEFAULT_SERVICE_FILE));
342 f = fopen(PAM_DEFAULT_SERVICE_FILE, "r");
344 /* would test magic here? */
345 retval = _pam_parse_conf_file(pamh, f
346 , PAM_DEFAULT_SERVICE
347 #ifdef PAM_READ_BOTH_CONFS
349 #endif /* PAM_READ_BOTH_CONFS */
352 if (retval != PAM_SUCCESS) {
353 pam_system_log(pamh, NULL, LOG_ERR,
354 "_pam_init_handlers: error reading %s",
355 PAM_DEFAULT_SERVICE_FILE);
356 pam_system_log(pamh, NULL, LOG_ERR,
357 "_pam_init_handlers: [%s]",
358 pam_strerror(pamh, retval));
363 D(("unable to open %s", PAM_DEFAULT_SERVICE_FILE));
364 pam_system_log(pamh, NULL, LOG_ERR,
365 "_pam_init_handlers: no default config %s",
366 PAM_DEFAULT_SERVICE_FILE);
368 if (!read_something) { /* nothing read successfully */
373 if ((f = fopen(PAM_CONFIG, "r")) == NULL) {
374 pam_system_log(pamh, NULL, LOG_ERR,
375 "_pam_init_handlers: could not open "
380 retval = _pam_parse_conf_file(pamh, f, NULL
381 #ifdef PAM_READ_BOTH_CONFS
383 #endif /* PAM_READ_BOTH_CONFS */
386 D(("closing configuration file"));
391 if (retval != PAM_SUCCESS) {
393 pam_system_log(pamh, NULL, LOG_ERR,
394 "error reading PAM configuration file");
398 pamh->handlers.handlers_loaded = 1;
400 D(("_pam_init_handlers exiting"));
405 * This is where we read a line of the PAM config file. The line may be
406 * preceeded by lines of comments and also extended with "\\\n"
409 int _pam_assemble_line(FILE *f, char *buffer, int buf_len)
415 /* loop broken with a 'break' when a non-'\\n' ended line is read */
419 if (used >= buf_len) {
421 D(("_pam_assemble_line: overflow"));
424 if (fgets(p, buf_len - used, f) == NULL) {
426 /* Incomplete read */
434 /* skip leading spaces --- line may be blank */
436 s = p + strspn(p, " \n\t");
437 if (*s && (*s != '#')) {
441 * we are only interested in characters before the first '#'
445 while (*s && *s != '#')
450 break; /* the line has been read */
456 * Check for backslash by scanning back from the end of
457 * the entered line, the '\n' has been included since
458 * normally a line is terminated with this
459 * character. fgets() should only return one though!
463 while (s > os && ((*--s == ' ') || (*s == '\t')
466 /* check if it ends with a backslash */
468 *s++ = ' '; /* replace backslash with ' ' */
469 *s = '\0'; /* truncate the line here */
471 p = s; /* there is more ... */
473 /* End of the line! */
475 break; /* this is the complete line */
479 /* Nothing in this line */
487 typedef int (*servicefn)(pam_handle_t *, int, int, char **);
489 int _pam_add_handler(pam_handle_t *pamh
490 , int must_fail, int other, int type
491 , int *actions, const char *mod_path
492 , int argc, char **argv, int argvlen)
494 struct loaded_module *mod;
496 struct handler **handler_p;
497 struct handler **handler_p2;
498 struct handlers *the_handlers;
499 const char *sym, *sym2;
501 const char *_sym, *_sym2;
503 char *mod_full_path=NULL;
504 servicefn func, func2;
508 IF_NO_PAMH("_pam_add_handler",pamh,PAM_SYSTEM_ERR);
510 /* if NULL set to something that can be searched for */
511 if (mod_path == NULL) {
512 mod_path = "<*unknown module path*>";
513 } else if (mod_path[0] != '/') {
514 mod_full_path = malloc(sizeof(DEFAULT_MODULE_PATH)+strlen(mod_path));
515 sprintf(mod_full_path, DEFAULT_MODULE_PATH "%s", mod_path);
516 mod_path = mod_full_path;
519 D(("_pam_add_handler: adding type %d, module `%s'",type,mod_path));
520 mod = pamh->handlers.module;
522 /* First, ensure the module is loaded */
523 while (x < pamh->handlers.modules_used) {
524 if (!strcmp(mod[x].name, mod_path)) { /* case sensitive ! */
529 if (x == pamh->handlers.modules_used) {
531 if (pamh->handlers.modules_allocated == pamh->handlers.modules_used) {
532 /* will need more memory */
533 void *tmp = realloc(pamh->handlers.module,
534 (pamh->handlers.modules_allocated+MODULE_CHUNK)
535 *sizeof(struct loaded_module));
537 D(("cannot enlarge module pointer memory"));
538 pam_system_log(pamh, NULL, LOG_ERR,
539 "realloc returned NULL in _pam_add_handler");
540 _pam_drop(mod_full_path);
543 pamh->handlers.module = tmp;
544 pamh->handlers.modules_allocated += MODULE_CHUNK;
546 mod = &(pamh->handlers.module[x]);
547 /* Be pessimistic... */
551 D(("_pam_add_handler: dlopen(%s) -> %lx", mod_path, &mod->dl_handle));
554 shl_load(mod_path, BIND_IMMEDIATE, 0L);
556 dlopen(mod_path, RTLD_NOW);
557 # endif /* PAM_SHL */
558 D(("_pam_add_handler: dlopen'ed"));
559 if (mod->dl_handle == NULL) {
560 D(("_pam_add_handler: dlopen(%s) failed", mod_path));
561 pam_system_log(pamh, NULL, LOG_ERR, "unable to dlopen(%s)",
564 pam_system_log(pamh, NULL, LOG_ERR, "[dlerror: %s]", dlerror());
565 # endif /* PAM_SHL */
566 /* Don't abort yet; static code may be able to find function.
567 * But defaults to abort if nothing found below... */
569 D(("module added successfully"));
570 success = PAM_SUCCESS;
571 mod->type = PAM_MT_DYNAMIC_MOD;
572 pamh->handlers.modules_used++;
576 /* Only load static function if function was not found dynamically.
577 * This code should work even if no dynamic loading is available. */
578 if (success != PAM_SUCCESS) {
579 D(("_pam_add_handler: open static handler %s", mod_path));
580 mod->dl_handle = _pam_open_static_handler(mod_path);
581 if (mod->dl_handle == NULL) {
582 D(("_pam_add_handler: unable to find static handler %s",
584 pam_system_log(pamh, NULL, LOG_ERR,
585 "unable to open static handler %s", mod_path);
586 /* Didn't find module in dynamic or static..will mark bad */
588 D(("static module added successfully"));
589 success = PAM_SUCCESS;
590 mod->type = PAM_MT_STATIC_MOD;
591 pamh->handlers.modules_used++;
596 if (success != PAM_SUCCESS) { /* add a malformed module */
597 mod->dl_handle = NULL;
598 mod->type = PAM_MT_FAULTY_MOD;
599 pamh->handlers.modules_used++;
600 pam_system_log(pamh, NULL, LOG_ERR,
601 "adding faulty module: %s", mod_path);
602 success = PAM_SUCCESS; /* We have successfully added a module */
605 /* indicate its name - later we will search for it by this */
606 if ((mod->name = _pam_strdup(mod_path)) == NULL) {
607 D(("_pam_handler: couldn't get memory for mod_path"));
608 pam_system_log(pamh, NULL, LOG_ERR,
609 "no memory for module path", mod_path);
613 } else { /* x != pamh->handlers.modules_used */
614 mod += x; /* the located module */
615 success = PAM_SUCCESS;
618 _pam_drop(mod_full_path);
619 mod_path = NULL; /* no longer needed or trusted */
621 /* Now return error if necessary after trying all possible ways... */
622 if (success != PAM_SUCCESS)
626 * At this point 'mod' points to the stored/loaded module. If its
627 * dl_handle is unknown, then we must be able to indicate dispatch
628 * failure with 'must_fail'
631 /* Now define the handler(s) based on mod->dlhandle and type */
633 /* decide which list of handlers to use */
634 the_handlers = (other) ? &pamh->handlers.other : &pamh->handlers.conf;
636 handler_p = handler_p2 = NULL;
643 /* point handler_p's at the root addresses of the function stacks */
646 handler_p = &the_handlers->authenticate;
647 sym = SHLIB_SYM_PREFIX "pam_sm_authenticate";
648 handler_p2 = &the_handlers->setcred;
649 sym2 = SHLIB_SYM_PREFIX "pam_sm_setcred";
651 _sym = "_pam_sm_authenticate";
652 _sym2 = "_pam_sm_setcred";
656 handler_p = &the_handlers->open_session;
657 sym = SHLIB_SYM_PREFIX "pam_sm_open_session";
658 handler_p2 = &the_handlers->close_session;
659 sym2 = SHLIB_SYM_PREFIX "pam_sm_close_session";
661 _sym = "_pam_sm_open_session";
662 _sym2 = "_pam_sm_close_session";
666 handler_p = &the_handlers->acct_mgmt;
667 sym = SHLIB_SYM_PREFIX "pam_sm_acct_mgmt";
669 _sym = "_pam_sm_acct_mgmt";
673 handler_p = &the_handlers->chauthtok;
674 sym = SHLIB_SYM_PREFIX "pam_sm_chauthtok";
676 _sym = "_pam_sm_chauthtok";
680 /* Illegal module type */
681 D(("_pam_add_handler: illegal module type %d", type));
685 /* are the modules reliable? */
688 mod->type != PAM_MT_DYNAMIC_MOD
690 #endif /* PAM_DYNAMIC */
692 mod->type != PAM_MT_STATIC_MOD
694 #endif /* PAM_STATIC */
695 mod->type != PAM_MT_FAULTY_MOD
697 D(("_pam_add_handlers: illegal module library type; %d", mod->type));
698 pam_system_log(pamh, NULL, LOG_ERR,
699 "internal error: module library type not known: %s;%d",
704 /* now identify this module's functions - for non-faulty modules */
707 if ((mod->type == PAM_MT_DYNAMIC_MOD) &&
709 (shl_findsym(&mod->dl_handle, sym, (short) TYPE_PROCEDURE, &func) &&
710 shl_findsym(&mod->dl_handle, _sym, (short) TYPE_PROCEDURE, &func))
712 (func = (servicefn) dlsym(mod->dl_handle, sym)) == NULL
713 # endif /* PAM_SHL */
715 pam_system_log(pamh, NULL, LOG_ERR, "unable to resolve symbol: %s",
720 if ((mod->type == PAM_MT_STATIC_MOD) &&
721 (func = (servicefn)_pam_get_static_sym(mod->dl_handle, sym)) == NULL) {
722 pam_system_log(pamh, NULL, LOG_ERR,
723 "unable to resolve static symbol: %s", sym);
728 if ((mod->type == PAM_MT_DYNAMIC_MOD) &&
730 (shl_findsym(&mod->dl_handle,sym2,(short)TYPE_PROCEDURE, &func2)&&
731 shl_findsym(&mod->dl_handle,_sym2,(short)TYPE_PROCEDURE, &func2))
733 (func2 = (servicefn) dlsym(mod->dl_handle, sym2)) == NULL
734 # endif /* PAM_SHL */
736 pam_system_log(pamh, NULL, LOG_ERR, "unable to resolve symbol: %s",
741 if ((mod->type == PAM_MT_STATIC_MOD) &&
742 (func2 = (servicefn)_pam_get_static_sym(mod->dl_handle, sym2))
744 pam_system_log(pamh, NULL, LOG_ERR, "unable to resolve symbol: %s",
750 /* here func (and perhaps func2) point to the appropriate functions */
752 /* add new handler to end of existing list */
753 while (*handler_p != NULL) {
754 handler_p = &((*handler_p)->next);
757 if ((*handler_p = malloc(sizeof(struct handler))) == NULL) {
758 pam_system_log(pamh, NULL, LOG_CRIT,
759 "cannot malloc struct handler #1");
763 (*handler_p)->must_fail = must_fail; /* failure forced? */
764 (*handler_p)->func = func;
765 memcpy((*handler_p)->actions,actions,sizeof((*handler_p)->actions));
766 (*handler_p)->argc = argc;
767 (*handler_p)->argv = argv; /* not a copy */
768 (*handler_p)->next = NULL;
770 /* some of the modules have a second calling function */
772 /* add new handler to end of existing list */
773 while (*handler_p2) {
774 handler_p2 = &((*handler_p2)->next);
777 if ((*handler_p2 = malloc(sizeof(struct handler))) == NULL) {
778 pam_system_log(pamh, NULL, LOG_CRIT,
779 "cannot malloc struct handler #2");
783 (*handler_p2)->must_fail = must_fail; /* failure forced? */
784 (*handler_p2)->func = func2;
785 memcpy((*handler_p2)->actions,actions,sizeof((*handler_p2)->actions));
786 (*handler_p2)->argc = argc;
788 if (((*handler_p2)->argv = malloc(argvlen)) == NULL) {
789 pam_system_log(pamh, NULL, LOG_CRIT,
790 "cannot malloc argv for handler #2");
793 memcpy((*handler_p2)->argv, argv, argvlen);
795 (*handler_p2)->argv = NULL; /* no arguments */
797 (*handler_p2)->next = NULL;
800 D(("_pam_add_handler: returning successfully"));
805 /* Free various allocated structures and dlclose() the libs */
806 int _pam_free_handlers(pam_handle_t *pamh)
808 struct loaded_module *mod;
811 IF_NO_PAMH("_pam_free_handlers",pamh,PAM_SYSTEM_ERR);
813 mod = pamh->handlers.module;
815 /* Close all loaded modules */
817 while (pamh->handlers.modules_used) {
818 D(("_pam_free_handlers: dlclose(%s)", mod->name));
822 if (mod->type == PAM_MT_DYNAMIC_MOD) shl_unload(mod->dl_handle);
824 if (mod->type == PAM_MT_DYNAMIC_MOD) dlclose(mod->dl_handle);
828 pamh->handlers.modules_used--;
831 /* Free all the handlers */
833 _pam_free_handlers_aux(&(pamh->handlers.conf.authenticate));
834 _pam_free_handlers_aux(&(pamh->handlers.conf.setcred));
835 _pam_free_handlers_aux(&(pamh->handlers.conf.acct_mgmt));
836 _pam_free_handlers_aux(&(pamh->handlers.conf.open_session));
837 _pam_free_handlers_aux(&(pamh->handlers.conf.close_session));
838 _pam_free_handlers_aux(&(pamh->handlers.conf.chauthtok));
840 _pam_free_handlers_aux(&(pamh->handlers.other.authenticate));
841 _pam_free_handlers_aux(&(pamh->handlers.other.setcred));
842 _pam_free_handlers_aux(&(pamh->handlers.other.acct_mgmt));
843 _pam_free_handlers_aux(&(pamh->handlers.other.open_session));
844 _pam_free_handlers_aux(&(pamh->handlers.other.close_session));
845 _pam_free_handlers_aux(&(pamh->handlers.other.chauthtok));
847 /* no more loaded modules */
849 _pam_drop(pamh->handlers.module);
851 /* Indicate that handlers are not initialized for this pamh */
853 pamh->handlers.handlers_loaded = 0;
858 void _pam_start_handlers(pam_handle_t *pamh)
861 /* NB. There is no check for a NULL pamh here, since no return
862 * value to communicate the fact! */
864 /* Indicate that handlers are not initialized for this pamh */
865 pamh->handlers.handlers_loaded = 0;
867 pamh->handlers.modules_allocated = 0;
868 pamh->handlers.modules_used = 0;
869 pamh->handlers.module = NULL;
871 /* initialize the .conf and .other entries */
873 pamh->handlers.conf.authenticate = NULL;
874 pamh->handlers.conf.setcred = NULL;
875 pamh->handlers.conf.acct_mgmt = NULL;
876 pamh->handlers.conf.open_session = NULL;
877 pamh->handlers.conf.close_session = NULL;
878 pamh->handlers.conf.chauthtok = NULL;
880 pamh->handlers.other.authenticate = NULL;
881 pamh->handlers.other.setcred = NULL;
882 pamh->handlers.other.acct_mgmt = NULL;
883 pamh->handlers.other.open_session = NULL;
884 pamh->handlers.other.close_session = NULL;
885 pamh->handlers.other.chauthtok = NULL;
888 void _pam_free_handlers_aux(struct handler **hp)
890 struct handler *h = *hp;
891 struct handler *last;
896 _pam_drop(h->argv); /* This is all alocated in a single chunk */
898 memset(last, 0, sizeof(*last));