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>
11 #include "pam_private.h"
16 #include <sys/types.h>
27 #endif /* PAM_DYNAMIC */
29 /* If not required, define as nothing */
30 #ifndef SHLIB_SYM_PREFIX
31 # define SHLIB_SYM_PREFIX ""
35 #define MODULE_CHUNK 4
36 #define UNKNOWN_MODULE_PATH "<*unknown module path*>"
38 static int _pam_assemble_line(FILE *f, char *buf, int buf_len);
40 static void _pam_free_handlers_aux(struct handler **hp);
42 static int _pam_add_handler(pam_handle_t *pamh
43 , int must_fail, int other, int type
44 , int *actions, const char *mod_path
45 , int argc, char **argv, int argvlen);
47 /* Values for module type */
55 static int _pam_load_conf_file(pam_handle_t *pamh, const char *config_name
56 , const char *service /* specific file */
57 , int module_type /* specific type */
58 #ifdef PAM_READ_BOTH_CONFS
60 #endif /* PAM_READ_BOTH_CONFS */
63 static int _pam_parse_conf_file(pam_handle_t *pamh, FILE *f
64 , const char *known_service /* specific file */
65 , int requested_module_type /* specific type */
66 #ifdef PAM_READ_BOTH_CONFS
68 #endif /* PAM_READ_BOTH_CONFS */
72 int x; /* read a line from the FILE *f ? */
74 * read a line from the configuration (FILE *) f
76 while ((x = _pam_assemble_line(f, buf, BUF_SIZE)) > 0) {
77 char *tok, *nexttok=NULL;
78 const char *this_service;
80 int module_type, actions[_PAM_RETURN_VALUES];
81 int other; /* set if module is for PAM_DEFAULT_SERVICE */
82 int res; /* module added successfully? */
83 int must_fail=0; /* a badly formatted line must fail when used */
88 D(("_pam_init_handler: LINE: %s", buf));
89 if (known_service != NULL) {
91 /* No service field: all lines are for the known service. */
92 this_service = known_service;
94 this_service = tok = _pam_StrTok(buf, " \n\t", &nexttok);
97 #ifdef PAM_READ_BOTH_CONFS
101 #endif /* PAM_READ_BOTH_CONFS */
102 other = !_pam_strCMP(this_service, PAM_DEFAULT_SERVICE);
104 /* accept "service name" or PAM_DEFAULT_SERVICE modules */
105 if (!_pam_strCMP(this_service, pamh->service_name) || other) {
108 /* This is a service we are looking for */
109 D(("_pam_init_handlers: Found PAM config entry for: %s"
112 tok = _pam_StrTok(NULL, " \n\t", &nexttok);
113 if (!_pam_strCMP("auth", tok)) {
114 module_type = PAM_T_AUTH;
115 } else if (!_pam_strCMP("session", tok)) {
116 module_type = PAM_T_SESS;
117 } else if (!_pam_strCMP("account", tok)) {
118 module_type = PAM_T_ACCT;
119 } else if (!_pam_strCMP("password", tok)) {
120 module_type = PAM_T_PASS;
122 /* Illegal module type */
123 D(("_pam_init_handlers: bad module type: %s", tok));
124 _pam_system_log(LOG_ERR, "(%s) illegal module type: %s",
126 module_type = (requested_module_type != PAM_T_ANY) ?
127 requested_module_type : PAM_T_AUTH; /* most sensitive */
128 must_fail = 1; /* install as normal but fail when dispatched */
130 D(("Using %s config entry: %s", must_fail?"BAD ":"", tok));
131 if (requested_module_type != PAM_T_ANY &&
132 module_type != requested_module_type) {
133 D(("Skipping config entry: %s (requested=%d, found=%d)",
134 tok, requested_module_type, module_type));
138 /* reset the actions to .._UNDEF's -- this is so that
139 we can work out which entries are not yet set (for default). */
142 for (i=0; i<_PAM_RETURN_VALUES;
143 actions[i++] = _PAM_ACTION_UNDEF);
145 tok = _pam_StrTok(NULL, " \n\t", &nexttok);
146 if (!_pam_strCMP("required", tok)) {
147 D(("*PAM_F_REQUIRED*"));
148 actions[PAM_SUCCESS] = _PAM_ACTION_OK;
149 actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
150 actions[PAM_IGNORE] = _PAM_ACTION_IGNORE;
151 _pam_set_default_control(actions, _PAM_ACTION_BAD);
152 } else if (!_pam_strCMP("requisite", tok)) {
153 D(("*PAM_F_REQUISITE*"));
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_DIE);
158 } else if (!_pam_strCMP("optional", tok)) {
159 D(("*PAM_F_OPTIONAL*"));
160 actions[PAM_SUCCESS] = _PAM_ACTION_OK;
161 actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
162 _pam_set_default_control(actions, _PAM_ACTION_IGNORE);
163 } else if (!_pam_strCMP("sufficient", tok)) {
164 D(("*PAM_F_SUFFICIENT*"));
165 actions[PAM_SUCCESS] = _PAM_ACTION_DONE;
166 actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_DONE;
167 _pam_set_default_control(actions, _PAM_ACTION_IGNORE);
168 } else if (!_pam_strCMP("include", tok)) {
169 D(("*PAM_F_INCLUDE*"));
172 D(("will need to parse %s", tok));
173 _pam_parse_control(actions, tok);
174 /* by default the default is to treat as failure */
175 _pam_set_default_control(actions, _PAM_ACTION_BAD);
178 tok = _pam_StrTok(NULL, " \n\t", &nexttok);
180 if (_pam_load_conf_file(pamh, tok, this_service, module_type
181 #ifdef PAM_READ_BOTH_CONFS
183 #endif /* PAM_READ_BOTH_CONFS */
186 _pam_set_default_control(actions, _PAM_ACTION_BAD);
190 } else if (tok != NULL) {
192 D(("mod_path = %s",mod_path));
194 /* no module name given */
195 D(("_pam_init_handlers: no module name supplied"));
196 _pam_system_log(LOG_ERR,
197 "(%s) no module name supplied", this_service);
202 /* nexttok points to remaining arguments... */
204 if (nexttok != NULL) {
205 D(("list: %s",nexttok));
206 argvlen = _pam_mkargv(nexttok, &argv, &argc);
207 D(("argvlen = %d",argvlen));
208 } else { /* there are no arguments so fix by hand */
209 D(("_pam_init_handlers: empty argument list"));
218 D(("CONF%s: %s%s %d %s %d"
219 , must_fail?"<*will fail*>":""
220 , this_service, other ? "(backup)":""
223 for (y = 0; y < argc; y++) {
224 D(("CONF: %s", argv[y]));
226 for (y = 0; y<_PAM_RETURN_VALUES; ++y) {
227 D(("RETURN %s(%d) -> %d %s",
228 _pam_token_returns[y], y, actions[y],
229 actions[y]>0 ? "jump":
230 _pam_token_actions[-actions[y]]));
235 res = _pam_add_handler(pamh, must_fail, other
236 , module_type, actions, mod_path
237 , argc, argv, argvlen);
238 if (res != PAM_SUCCESS) {
239 _pam_system_log(LOG_ERR, "error loading %s", mod_path);
240 D(("failed to load module - aborting"));
246 return ( (x < 0) ? PAM_ABORT:PAM_SUCCESS );
249 static int _pam_load_conf_file(pam_handle_t *pamh, const char *config_name
250 , const char *service /* specific file */
251 , int module_type /* specific type */
252 #ifdef PAM_READ_BOTH_CONFS
254 #endif /* PAM_READ_BOTH_CONFS */
258 char *config_path = NULL;
259 int retval = PAM_ABORT;
261 D(("_pam_load_conf_file called"));
263 if (config_name == NULL) {
264 D(("no config file supplied"));
265 _pam_system_log(LOG_ERR, "(%s) no config file supplied", service);
269 if (config_name[0] != '/') {
270 if (asprintf (&config_path, PAM_CONFIG_DF, config_name) < 0) {
271 _pam_system_log(LOG_CRIT, "asprintf failed");
274 config_name = config_path;
277 D(("opening %s", config_name));
278 f = fopen(config_name, "r");
280 retval = _pam_parse_conf_file(pamh, f, service, module_type
281 #ifdef PAM_READ_BOTH_CONFS
283 #endif /* PAM_READ_BOTH_CONFS */
286 if (retval != PAM_SUCCESS)
287 _pam_system_log(LOG_ERR,
288 "_pam_load_conf_file: error reading %s: %s",
289 config_name, pam_strerror(pamh, retval));
291 D(("unable to open %s", filename));
292 _pam_system_log(LOG_ERR,
293 "_pam_load_conf_file: unable to open %s",
297 _pam_drop(config_path);
301 /* Parse config file, allocate handler structures, dlopen() */
302 int _pam_init_handlers(pam_handle_t *pamh)
307 D(("_pam_init_handlers called"));
308 IF_NO_PAMH("_pam_init_handlers",pamh,PAM_SYSTEM_ERR);
310 /* Return immediately if everything is already loaded */
311 if (pamh->handlers.handlers_loaded) {
315 D(("_pam_init_handlers: initializing"));
317 /* First clean the service structure */
319 _pam_free_handlers(pamh);
320 if (! pamh->handlers.module) {
321 if ((pamh->handlers.module =
322 malloc(MODULE_CHUNK * sizeof(struct loaded_module))) == NULL) {
323 _pam_system_log(LOG_CRIT,
324 "_pam_init_handlers: no memory loading module");
327 pamh->handlers.modules_allocated = MODULE_CHUNK;
328 pamh->handlers.modules_used = 0;
331 if (pamh->service_name == NULL) {
332 return PAM_BAD_ITEM; /* XXX - better error? */
336 /* Is the PAM subsystem locked? */
340 if ((fd_tmp = open( PAM_LOCK_FILE, O_RDONLY )) != -1) {
341 _pam_system_log(LOG_ERR, "_pam_init_handlers: PAM lockfile ("
342 PAM_LOCK_FILE ") exists - aborting");
343 (void) close(fd_tmp);
345 * to avoid swamping the system with requests
347 _pam_start_timer(pamh);
348 pam_fail_delay(pamh, 5000000);
349 _pam_await_timer(pamh, PAM_ABORT);
354 #endif /* PAM_LOCKING */
357 * Now parse the config file(s) and add handlers
362 /* Is there a PAM_CONFIG_D directory? */
363 if ( stat(PAM_CONFIG_D, &test_d) == 0 && S_ISDIR(test_d.st_mode) ) {
365 int read_something=0;
367 D(("searching " PAM_CONFIG_D " for config files"));
368 filename = malloc(sizeof(PAM_CONFIG_DF)
369 +strlen(pamh->service_name));
370 if (filename == NULL) {
371 _pam_system_log(LOG_ERR,
372 "_pam_init_handlers: no memory; service %s",
376 sprintf(filename, PAM_CONFIG_DF, pamh->service_name);
377 D(("opening %s", filename));
378 f = fopen(filename, "r");
380 /* would test magic here? */
381 retval = _pam_parse_conf_file(pamh, f, pamh->service_name, PAM_T_ANY
382 #ifdef PAM_READ_BOTH_CONFS
384 #endif /* PAM_READ_BOTH_CONFS */
387 if (retval != PAM_SUCCESS) {
388 _pam_system_log(LOG_ERR,
389 "_pam_init_handlers: error reading %s",
391 _pam_system_log(LOG_ERR, "_pam_init_handlers: [%s]",
392 pam_strerror(pamh, retval));
397 D(("unable to open %s", filename));
398 #ifdef PAM_READ_BOTH_CONFS
399 D(("checking %s", PAM_CONFIG));
401 if ((f = fopen(PAM_CONFIG,"r")) != NULL) {
402 retval = _pam_parse_conf_file(pamh, f, NULL, PAM_T_ANY, 1);
405 #endif /* PAM_READ_BOTH_CONFS */
406 retval = PAM_SUCCESS;
408 * XXX - should we log an error? Some people want to always
414 if (retval == PAM_SUCCESS) {
415 /* now parse the PAM_DEFAULT_SERVICE_FILE */
417 D(("opening %s", PAM_DEFAULT_SERVICE_FILE));
418 f = fopen(PAM_DEFAULT_SERVICE_FILE, "r");
420 /* would test magic here? */
421 retval = _pam_parse_conf_file(pamh, f
422 , PAM_DEFAULT_SERVICE
424 #ifdef PAM_READ_BOTH_CONFS
426 #endif /* PAM_READ_BOTH_CONFS */
429 if (retval != PAM_SUCCESS) {
430 _pam_system_log(LOG_ERR,
431 "_pam_init_handlers: error reading %s",
432 PAM_DEFAULT_SERVICE_FILE);
433 _pam_system_log(LOG_ERR,
434 "_pam_init_handlers: [%s]",
435 pam_strerror(pamh, retval));
440 D(("unable to open %s", PAM_DEFAULT_SERVICE_FILE));
441 _pam_system_log(LOG_ERR,
442 "_pam_init_handlers: no default config %s",
443 PAM_DEFAULT_SERVICE_FILE);
445 if (!read_something) { /* nothing read successfully */
450 if ((f = fopen(PAM_CONFIG, "r")) == NULL) {
451 _pam_system_log(LOG_ERR, "_pam_init_handlers: could not open "
456 retval = _pam_parse_conf_file(pamh, f, NULL, PAM_T_ANY
457 #ifdef PAM_READ_BOTH_CONFS
459 #endif /* PAM_READ_BOTH_CONFS */
462 D(("closing configuration file"));
467 if (retval != PAM_SUCCESS) {
469 _pam_system_log(LOG_ERR, "error reading PAM configuration file");
473 pamh->handlers.handlers_loaded = 1;
475 D(("_pam_init_handlers exiting"));
480 * This is where we read a line of the PAM config file. The line may be
481 * preceeded by lines of comments and also extended with "\\\n"
484 static int _pam_assemble_line(FILE *f, char *buffer, int buf_len)
490 /* loop broken with a 'break' when a non-'\\n' ended line is read */
494 if (used >= buf_len) {
496 D(("_pam_assemble_line: overflow"));
499 if (fgets(p, buf_len - used, f) == NULL) {
501 /* Incomplete read */
509 /* skip leading spaces --- line may be blank */
511 s = p + strspn(p, " \n\t");
512 if (*s && (*s != '#')) {
516 * we are only interested in characters before the first '#'
520 while (*s && *s != '#')
525 break; /* the line has been read */
531 * Check for backslash by scanning back from the end of
532 * the entered line, the '\n' has been included since
533 * normally a line is terminated with this
534 * character. fgets() should only return one though!
538 while (s > os && ((*--s == ' ') || (*s == '\t')
541 /* check if it ends with a backslash */
543 *s++ = ' '; /* replace backslash with ' ' */
544 *s = '\0'; /* truncate the line here */
546 p = s; /* there is more ... */
548 /* End of the line! */
550 break; /* this is the complete line */
554 /* Nothing in this line */
562 typedef int (*servicefn)(pam_handle_t *, int, int, char **);
564 int _pam_add_handler(pam_handle_t *pamh
565 , int must_fail, int other, int type
566 , int *actions, const char *mod_path
567 , int argc, char **argv, int argvlen)
569 struct loaded_module *mod;
571 struct handler **handler_p;
572 struct handler **handler_p2;
573 struct handlers *the_handlers;
574 const char *sym, *sym2;
576 const char *_sym, *_sym2;
578 char *mod_full_path=NULL;
579 servicefn func, func2;
583 IF_NO_PAMH("_pam_add_handler",pamh,PAM_SYSTEM_ERR);
585 /* if NULL set to something that can be searched for */
586 switch (mod_path != NULL) {
588 if (mod_path[0] == '/') {
591 mod_full_path = malloc(sizeof(DEFAULT_MODULE_PATH)+strlen(mod_path));
593 sprintf(mod_full_path, DEFAULT_MODULE_PATH "%s", mod_path);
594 mod_path = mod_full_path;
597 _pam_system_log(LOG_CRIT, "cannot malloc full mod path");
599 mod_path = UNKNOWN_MODULE_PATH;
602 D(("_pam_add_handler: adding type %d, module `%s'",type,mod_path));
603 mod = pamh->handlers.module;
605 /* First, ensure the module is loaded */
606 while (x < pamh->handlers.modules_used) {
607 if (!strcmp(mod[x].name, mod_path)) { /* case sensitive ! */
612 if (x == pamh->handlers.modules_used) {
614 if (pamh->handlers.modules_allocated == pamh->handlers.modules_used) {
615 /* will need more memory */
616 void *tmp = realloc(pamh->handlers.module,
617 (pamh->handlers.modules_allocated+MODULE_CHUNK)
618 *sizeof(struct loaded_module));
620 D(("cannot enlarge module pointer memory"));
621 _pam_system_log(LOG_ERR,
622 "realloc returned NULL in _pam_add_handler");
623 _pam_drop(mod_full_path);
626 pamh->handlers.module = tmp;
627 pamh->handlers.modules_allocated += MODULE_CHUNK;
629 mod = &(pamh->handlers.module[x]);
630 /* Be pessimistic... */
634 D(("_pam_add_handler: dlopen(%s) -> %lx", mod_path, &mod->dl_handle));
637 shl_load(mod_path, BIND_IMMEDIATE, 0L);
639 dlopen(mod_path, RTLD_NOW);
640 # endif /* PAM_SHL */
641 D(("_pam_add_handler: dlopen'ed"));
642 if (mod->dl_handle == NULL) {
643 D(("_pam_add_handler: dlopen(%s) failed", mod_path));
644 _pam_system_log(LOG_ERR, "unable to dlopen(%s)", mod_path);
646 _pam_system_log(LOG_ERR, "[dlerror: %s]", dlerror());
647 # endif /* PAM_SHL */
648 /* Don't abort yet; static code may be able to find function.
649 * But defaults to abort if nothing found below... */
651 D(("module added successfully"));
652 success = PAM_SUCCESS;
653 mod->type = PAM_MT_DYNAMIC_MOD;
654 pamh->handlers.modules_used++;
658 /* Only load static function if function was not found dynamically.
659 * This code should work even if no dynamic loading is available. */
660 if (success != PAM_SUCCESS) {
661 D(("_pam_add_handler: open static handler %s", mod_path));
662 mod->dl_handle = _pam_open_static_handler(mod_path);
663 if (mod->dl_handle == NULL) {
664 D(("_pam_add_handler: unable to find static handler %s",
666 _pam_system_log(LOG_ERR,
667 "unable to open static handler %s", mod_path);
668 /* Didn't find module in dynamic or static..will mark bad */
670 D(("static module added successfully"));
671 success = PAM_SUCCESS;
672 mod->type = PAM_MT_STATIC_MOD;
673 pamh->handlers.modules_used++;
678 if (success != PAM_SUCCESS) { /* add a malformed module */
679 mod->dl_handle = NULL;
680 mod->type = PAM_MT_FAULTY_MOD;
681 pamh->handlers.modules_used++;
682 _pam_system_log(LOG_ERR, "adding faulty module: %s", mod_path);
683 success = PAM_SUCCESS; /* We have successfully added a module */
686 /* indicate its name - later we will search for it by this */
687 if ((mod->name = _pam_strdup(mod_path)) == NULL) {
688 D(("_pam_handler: couldn't get memory for mod_path"));
689 _pam_system_log(LOG_ERR, "no memory for module path", mod_path);
693 } else { /* x != pamh->handlers.modules_used */
694 mod += x; /* the located module */
695 success = PAM_SUCCESS;
698 _pam_drop(mod_full_path);
699 mod_path = NULL; /* no longer needed or trusted */
701 /* Now return error if necessary after trying all possible ways... */
702 if (success != PAM_SUCCESS)
706 * At this point 'mod' points to the stored/loaded module. If its
707 * dl_handle is unknown, then we must be able to indicate dispatch
708 * failure with 'must_fail'
711 /* Now define the handler(s) based on mod->dlhandle and type */
713 /* decide which list of handlers to use */
714 the_handlers = (other) ? &pamh->handlers.other : &pamh->handlers.conf;
716 handler_p = handler_p2 = NULL;
723 /* point handler_p's at the root addresses of the function stacks */
726 handler_p = &the_handlers->authenticate;
727 sym = SHLIB_SYM_PREFIX "pam_sm_authenticate";
728 handler_p2 = &the_handlers->setcred;
729 sym2 = SHLIB_SYM_PREFIX "pam_sm_setcred";
731 _sym = "_pam_sm_authenticate";
732 _sym2 = "_pam_sm_setcred";
736 handler_p = &the_handlers->open_session;
737 sym = SHLIB_SYM_PREFIX "pam_sm_open_session";
738 handler_p2 = &the_handlers->close_session;
739 sym2 = SHLIB_SYM_PREFIX "pam_sm_close_session";
741 _sym = "_pam_sm_open_session";
742 _sym2 = "_pam_sm_close_session";
746 handler_p = &the_handlers->acct_mgmt;
747 sym = SHLIB_SYM_PREFIX "pam_sm_acct_mgmt";
749 _sym = "_pam_sm_acct_mgmt";
753 handler_p = &the_handlers->chauthtok;
754 sym = SHLIB_SYM_PREFIX "pam_sm_chauthtok";
756 _sym = "_pam_sm_chauthtok";
760 /* Illegal module type */
761 D(("_pam_add_handler: illegal module type %d", type));
765 /* are the modules reliable? */
768 mod->type != PAM_MT_DYNAMIC_MOD
770 #endif /* PAM_DYNAMIC */
772 mod->type != PAM_MT_STATIC_MOD
774 #endif /* PAM_STATIC */
775 mod->type != PAM_MT_FAULTY_MOD
777 D(("_pam_add_handlers: illegal module library type; %d", mod->type));
778 _pam_system_log(LOG_ERR,
779 "internal error: module library type not known: %s;%d",
784 /* now identify this module's functions - for non-faulty modules */
787 if ((mod->type == PAM_MT_DYNAMIC_MOD) &&
789 (shl_findsym(&mod->dl_handle, sym, (short) TYPE_PROCEDURE, &func) &&
790 shl_findsym(&mod->dl_handle, _sym, (short) TYPE_PROCEDURE, &func))
792 (func = (servicefn) dlsym(mod->dl_handle, sym)) == NULL
793 # endif /* PAM_SHL */
795 _pam_system_log(LOG_ERR, "unable to resolve symbol: %s", sym);
799 if ((mod->type == PAM_MT_STATIC_MOD) &&
800 (func = (servicefn)_pam_get_static_sym(mod->dl_handle, sym)) == NULL) {
801 _pam_system_log(LOG_ERR, "unable to resolve static symbol: %s", sym);
806 if ((mod->type == PAM_MT_DYNAMIC_MOD) &&
808 (shl_findsym(&mod->dl_handle,sym2,(short)TYPE_PROCEDURE, &func2)&&
809 shl_findsym(&mod->dl_handle,_sym2,(short)TYPE_PROCEDURE, &func2))
811 (func2 = (servicefn) dlsym(mod->dl_handle, sym2)) == NULL
812 # endif /* PAM_SHL */
814 _pam_system_log(LOG_ERR, "unable to resolve symbol: %s", sym2);
818 if ((mod->type == PAM_MT_STATIC_MOD) &&
819 (func2 = (servicefn)_pam_get_static_sym(mod->dl_handle, sym2))
821 _pam_system_log(LOG_ERR, "unable to resolve symbol: %s", sym2);
826 /* here func (and perhaps func2) point to the appropriate functions */
828 /* add new handler to end of existing list */
829 while (*handler_p != NULL) {
830 handler_p = &((*handler_p)->next);
833 if ((*handler_p = malloc(sizeof(struct handler))) == NULL) {
834 _pam_system_log(LOG_CRIT, "cannot malloc struct handler #1");
838 (*handler_p)->must_fail = must_fail; /* failure forced? */
839 (*handler_p)->func = func;
840 memcpy((*handler_p)->actions,actions,sizeof((*handler_p)->actions));
841 (*handler_p)->cached_retval = _PAM_INVALID_RETVAL;
842 (*handler_p)->cached_retval_p = &((*handler_p)->cached_retval);
843 (*handler_p)->argc = argc;
844 (*handler_p)->argv = argv; /* not a copy */
845 (*handler_p)->next = NULL;
847 /* some of the modules have a second calling function */
849 /* add new handler to end of existing list */
850 while (*handler_p2) {
851 handler_p2 = &((*handler_p2)->next);
854 if ((*handler_p2 = malloc(sizeof(struct handler))) == NULL) {
855 _pam_system_log(LOG_CRIT, "cannot malloc struct handler #2");
859 (*handler_p2)->must_fail = must_fail; /* failure forced? */
860 (*handler_p2)->func = func2;
861 memcpy((*handler_p2)->actions,actions,sizeof((*handler_p2)->actions));
862 (*handler_p2)->cached_retval = _PAM_INVALID_RETVAL; /* ignored */
863 /* Note, this next entry points to the handler_p value! */
864 (*handler_p2)->cached_retval_p = &((*handler_p)->cached_retval);
865 (*handler_p2)->argc = argc;
867 if (((*handler_p2)->argv = malloc(argvlen)) == NULL) {
868 _pam_system_log(LOG_CRIT, "cannot malloc argv for handler #2");
871 memcpy((*handler_p2)->argv, argv, argvlen);
873 (*handler_p2)->argv = NULL; /* no arguments */
875 (*handler_p2)->next = NULL;
878 D(("_pam_add_handler: returning successfully"));
883 /* Free various allocated structures and dlclose() the libs */
884 int _pam_free_handlers(pam_handle_t *pamh)
886 struct loaded_module *mod;
889 IF_NO_PAMH("_pam_free_handlers",pamh,PAM_SYSTEM_ERR);
891 mod = pamh->handlers.module;
893 /* Close all loaded modules */
895 while (pamh->handlers.modules_used) {
896 D(("_pam_free_handlers: dlclose(%s)", mod->name));
899 if (mod->type == PAM_MT_DYNAMIC_MOD) {
901 shl_unload(mod->dl_handle);
903 dlclose(mod->dl_handle);
908 pamh->handlers.modules_used--;
911 /* Free all the handlers */
913 _pam_free_handlers_aux(&(pamh->handlers.conf.authenticate));
914 _pam_free_handlers_aux(&(pamh->handlers.conf.setcred));
915 _pam_free_handlers_aux(&(pamh->handlers.conf.acct_mgmt));
916 _pam_free_handlers_aux(&(pamh->handlers.conf.open_session));
917 _pam_free_handlers_aux(&(pamh->handlers.conf.close_session));
918 _pam_free_handlers_aux(&(pamh->handlers.conf.chauthtok));
920 _pam_free_handlers_aux(&(pamh->handlers.other.authenticate));
921 _pam_free_handlers_aux(&(pamh->handlers.other.setcred));
922 _pam_free_handlers_aux(&(pamh->handlers.other.acct_mgmt));
923 _pam_free_handlers_aux(&(pamh->handlers.other.open_session));
924 _pam_free_handlers_aux(&(pamh->handlers.other.close_session));
925 _pam_free_handlers_aux(&(pamh->handlers.other.chauthtok));
927 /* no more loaded modules */
929 _pam_drop(pamh->handlers.module);
931 /* Indicate that handlers are not initialized for this pamh */
933 pamh->handlers.handlers_loaded = 0;
938 void _pam_start_handlers(pam_handle_t *pamh)
941 /* NB. There is no check for a NULL pamh here, since no return
942 * value to communicate the fact! */
944 /* Indicate that handlers are not initialized for this pamh */
945 pamh->handlers.handlers_loaded = 0;
947 pamh->handlers.modules_allocated = 0;
948 pamh->handlers.modules_used = 0;
949 pamh->handlers.module = NULL;
951 /* initialize the .conf and .other entries */
953 pamh->handlers.conf.authenticate = NULL;
954 pamh->handlers.conf.setcred = NULL;
955 pamh->handlers.conf.acct_mgmt = NULL;
956 pamh->handlers.conf.open_session = NULL;
957 pamh->handlers.conf.close_session = NULL;
958 pamh->handlers.conf.chauthtok = NULL;
960 pamh->handlers.other.authenticate = NULL;
961 pamh->handlers.other.setcred = NULL;
962 pamh->handlers.other.acct_mgmt = NULL;
963 pamh->handlers.other.open_session = NULL;
964 pamh->handlers.other.close_session = NULL;
965 pamh->handlers.other.chauthtok = NULL;
968 void _pam_free_handlers_aux(struct handler **hp)
970 struct handler *h = *hp;
971 struct handler *last;
976 _pam_drop(h->argv); /* This is all alocated in a single chunk */
978 memset(last, 0, sizeof(*last));