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>
7
* $Id: pam_handlers.c,v 1.2 2002/10/06 21:50:48 hartmans Exp $
14
#include <sys/types.h>
25
#endif /* PAM_DYNAMIC */
27
#include "pam_private.h"
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 */
54
static int _pam_parse_conf_file(pam_handle_t *pamh, FILE *f
55
, const char *known_service /* specific file */
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 must_fail=0; /* a badly formatted line must fail when used */
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 = !_pam_strCMP(this_service, PAM_DEFAULT_SERVICE);
94
/* accept "service name" or PAM_DEFAULT_SERVICE modules */
95
if (!_pam_strCMP(this_service, pamh->service_name) || other) {
96
/* This is a service we are looking for */
97
D(("_pam_init_handlers: Found PAM config entry for: %s"
100
tok = _pam_StrTok(NULL, " \n\t", &nexttok);
101
if (!_pam_strCMP("auth", tok)) {
102
module_type = PAM_T_AUTH;
103
} else if (!_pam_strCMP("session", tok)) {
104
module_type = PAM_T_SESS;
105
} else if (!_pam_strCMP("account", tok)) {
106
module_type = PAM_T_ACCT;
107
} else if (!_pam_strCMP("password", tok)) {
108
module_type = PAM_T_PASS;
109
} else if (!_pam_strCMP("@include", tok)) {
110
/* include a file here
111
* most of the code adapted from _pam_init_handlers */
116
tok = _pam_StrTok(NULL, " \n\t", &nexttok);
118
D(("_pam_parse_conf_file: included file name not given"));
119
_pam_system_log(LOG_ERR,
120
"(%s) included file name not given",
126
if (!_pam_strCMP("/", tok)) {
129
} else if ( stat(PAM_CONFIG_D, &test_d) == 0 && S_ISDIR(test_d.st_mode) ) {
130
D(("searching " PAM_CONFIG_D " for included file"));
131
filename = malloc(sizeof(PAM_CONFIG_DF)
133
if (filename == NULL) {
134
_pam_system_log(LOG_ERR,
135
"_pam_parse_conf_file: no memory; service %s",
139
sprintf(filename, PAM_CONFIG_DF, tok);
141
D(("opening %s", filename));
142
inc_f = fopen(filename, "r");
144
retval = _pam_parse_conf_file(pamh, inc_f, known_service
145
#ifdef PAM_READ_BOTH_CONFS
147
#endif /* PAM_READ_BOTH_CONFS */
150
if (retval != PAM_SUCCESS) {
151
_pam_system_log(LOG_ERR,
152
"_pam_parse_conf_file: error reading %s",
154
_pam_system_log(LOG_ERR, "_pam_parse_conf_file: [%s]",
155
pam_strerror(pamh, retval));
162
/* skip dealing with the module; and go to the next line */
165
/* Illegal module type */
166
D(("_pam_init_handlers: bad module type: %s", tok));
167
_pam_system_log(LOG_ERR, "(%s) illegal module type: %s",
169
module_type = PAM_T_AUTH; /* most sensitive */
170
must_fail = 1; /* install as normal but fail when dispatched */
172
D(("Using %s config entry: %s", must_fail?"BAD ":"", tok));
174
/* reset the actions to .._UNDEF's -- this is so that
175
we can work out which entries are not yet set (for default). */
178
for (i=0; i<_PAM_RETURN_VALUES;
179
actions[i++] = _PAM_ACTION_UNDEF);
181
tok = _pam_StrTok(NULL, " \n\t", &nexttok);
182
if (!_pam_strCMP("required", tok)) {
183
D(("*PAM_F_REQUIRED*"));
184
actions[PAM_SUCCESS] = _PAM_ACTION_OK;
185
actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
186
actions[PAM_IGNORE] = _PAM_ACTION_IGNORE;
187
_pam_set_default_control(actions, _PAM_ACTION_BAD);
188
} else if (!_pam_strCMP("requisite", tok)) {
189
D(("*PAM_F_REQUISITE*"));
190
actions[PAM_SUCCESS] = _PAM_ACTION_OK;
191
actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
192
actions[PAM_IGNORE] = _PAM_ACTION_IGNORE;
193
_pam_set_default_control(actions, _PAM_ACTION_DIE);
194
} else if (!_pam_strCMP("optional", tok)) {
195
D(("*PAM_F_OPTIONAL*"));
196
actions[PAM_SUCCESS] = _PAM_ACTION_OK;
197
actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
198
_pam_set_default_control(actions, _PAM_ACTION_IGNORE);
199
} else if (!_pam_strCMP("sufficient", tok)) {
200
D(("*PAM_F_SUFFICIENT*"));
201
actions[PAM_SUCCESS] = _PAM_ACTION_DONE;
202
actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_DONE;
203
_pam_set_default_control(actions, _PAM_ACTION_IGNORE);
205
D(("will need to parse %s", tok));
206
_pam_parse_control(actions, tok);
207
/* by default the default is to treat as failure */
208
_pam_set_default_control(actions, _PAM_ACTION_BAD);
211
tok = _pam_StrTok(NULL, " \n\t", &nexttok);
214
D(("mod_path = %s",mod_path));
216
/* no module name given */
217
D(("_pam_init_handlers: no module name supplied"));
218
_pam_system_log(LOG_ERR,
219
"(%s) no module name supplied", this_service);
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
, 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, must_fail, other
258
, module_type, actions, mod_path
259
, argc, argv, argvlen);
260
if (res != PAM_SUCCESS) {
261
_pam_system_log(LOG_ERR, "error loading %s", mod_path);
262
D(("failed to load module - aborting"));
269
return ( (x < 0) ? PAM_ABORT:PAM_SUCCESS );
272
/* Parse config file, allocate handler structures, dlopen() */
273
int _pam_init_handlers(pam_handle_t *pamh)
278
D(("_pam_init_handlers called"));
279
IF_NO_PAMH("_pam_init_handlers",pamh,PAM_SYSTEM_ERR);
281
/* Return immediately if everything is already loaded */
282
if (pamh->handlers.handlers_loaded) {
286
D(("_pam_init_handlers: initializing"));
288
/* First clean the service structure */
290
_pam_free_handlers(pamh);
291
if (! pamh->handlers.module) {
292
if ((pamh->handlers.module =
293
malloc(MODULE_CHUNK * sizeof(struct loaded_module))) == NULL) {
294
_pam_system_log(LOG_CRIT,
295
"_pam_init_handlers: no memory loading module");
298
pamh->handlers.modules_allocated = MODULE_CHUNK;
299
pamh->handlers.modules_used = 0;
302
if (pamh->service_name == NULL) {
303
return PAM_BAD_ITEM; /* XXX - better error? */
307
/* Is the PAM subsystem locked? */
311
if ((fd_tmp = open( PAM_LOCK_FILE, O_RDONLY )) != -1) {
312
_pam_system_log(LOG_ERR, "_pam_init_handlers: PAM lockfile ("
313
PAM_LOCK_FILE ") exists - aborting");
314
(void) close(fd_tmp);
316
* to avoid swamping the system with requests
318
_pam_start_timer(pamh);
319
pam_fail_delay(pamh, 5000000);
320
_pam_await_timer(pamh, PAM_ABORT);
325
#endif /* PAM_LOCKING */
328
* Now parse the config file(s) and add handlers
333
/* Is there a PAM_CONFIG_D directory? */
334
if ( stat(PAM_CONFIG_D, &test_d) == 0 && S_ISDIR(test_d.st_mode) ) {
336
int read_something=0;
338
D(("searching " PAM_CONFIG_D " for config files"));
339
filename = malloc(sizeof(PAM_CONFIG_DF)
340
+strlen(pamh->service_name));
341
if (filename == NULL) {
342
_pam_system_log(LOG_ERR,
343
"_pam_init_handlers: no memory; service %s",
347
sprintf(filename, PAM_CONFIG_DF, pamh->service_name);
348
D(("opening %s", filename));
349
f = fopen(filename, "r");
351
/* would test magic here? */
352
retval = _pam_parse_conf_file(pamh, f, pamh->service_name
353
#ifdef PAM_READ_BOTH_CONFS
355
#endif /* PAM_READ_BOTH_CONFS */
358
if (retval != PAM_SUCCESS) {
359
_pam_system_log(LOG_ERR,
360
"_pam_init_handlers: error reading %s",
362
_pam_system_log(LOG_ERR, "_pam_init_handlers: [%s]",
363
pam_strerror(pamh, retval));
368
D(("unable to open %s", filename));
369
#ifdef PAM_READ_BOTH_CONFS
370
D(("checking %s", PAM_CONFIG));
372
if ((f = fopen(PAM_CONFIG,"r")) != NULL) {
373
retval = _pam_parse_conf_file(pamh, f, NULL, 1);
376
#endif /* PAM_READ_BOTH_CONFS */
377
retval = PAM_SUCCESS;
379
* XXX - should we log an error? Some people want to always
385
if (retval == PAM_SUCCESS) {
386
/* now parse the PAM_DEFAULT_SERVICE_FILE */
388
D(("opening %s", PAM_DEFAULT_SERVICE_FILE));
389
f = fopen(PAM_DEFAULT_SERVICE_FILE, "r");
391
/* would test magic here? */
392
retval = _pam_parse_conf_file(pamh, f
393
, PAM_DEFAULT_SERVICE
394
#ifdef PAM_READ_BOTH_CONFS
396
#endif /* PAM_READ_BOTH_CONFS */
399
if (retval != PAM_SUCCESS) {
400
_pam_system_log(LOG_ERR,
401
"_pam_init_handlers: error reading %s",
402
PAM_DEFAULT_SERVICE_FILE);
403
_pam_system_log(LOG_ERR,
404
"_pam_init_handlers: [%s]",
405
pam_strerror(pamh, retval));
410
D(("unable to open %s", PAM_DEFAULT_SERVICE_FILE));
411
_pam_system_log(LOG_ERR,
412
"_pam_init_handlers: no default config %s",
413
PAM_DEFAULT_SERVICE_FILE);
415
if (!read_something) { /* nothing read successfully */
420
if ((f = fopen(PAM_CONFIG, "r")) == NULL) {
421
_pam_system_log(LOG_ERR, "_pam_init_handlers: could not open "
426
retval = _pam_parse_conf_file(pamh, f, NULL
427
#ifdef PAM_READ_BOTH_CONFS
429
#endif /* PAM_READ_BOTH_CONFS */
432
D(("closing configuration file"));
437
if (retval != PAM_SUCCESS) {
439
_pam_system_log(LOG_ERR, "error reading PAM configuration file");
443
pamh->handlers.handlers_loaded = 1;
445
D(("_pam_init_handlers exiting"));
450
* This is where we read a line of the PAM config file. The line may be
451
* preceeded by lines of comments and also extended with "\\\n"
454
static int _pam_assemble_line(FILE *f, char *buffer, int buf_len)
460
/* loop broken with a 'break' when a non-'\\n' ended line is read */
464
if (used >= buf_len) {
466
D(("_pam_assemble_line: overflow"));
469
if (fgets(p, buf_len - used, f) == NULL) {
471
/* Incomplete read */
479
/* skip leading spaces --- line may be blank */
481
s = p + strspn(p, " \n\t");
482
if (*s && (*s != '#')) {
486
* we are only interested in characters before the first '#'
490
while (*s && *s != '#')
495
break; /* the line has been read */
501
* Check for backslash by scanning back from the end of
502
* the entered line, the '\n' has been included since
503
* normally a line is terminated with this
504
* character. fgets() should only return one though!
508
while (s > os && ((*--s == ' ') || (*s == '\t')
511
/* check if it ends with a backslash */
513
*s++ = ' '; /* replace backslash with ' ' */
514
*s = '\0'; /* truncate the line here */
516
p = s; /* there is more ... */
518
/* End of the line! */
520
break; /* this is the complete line */
524
/* Nothing in this line */
532
typedef int (*servicefn)(pam_handle_t *, int, int, char **);
534
int _pam_add_handler(pam_handle_t *pamh
535
, int must_fail, int other, int type
536
, int *actions, const char *mod_path
537
, int argc, char **argv, int argvlen)
539
struct loaded_module *mod;
541
struct handler **handler_p;
542
struct handler **handler_p2;
543
struct handlers *the_handlers;
544
const char *sym, *sym2;
546
const char *_sym, *_sym2;
548
char *mod_full_path=NULL;
549
servicefn func, func2;
553
IF_NO_PAMH("_pam_add_handler",pamh,PAM_SYSTEM_ERR);
555
/* if NULL set to something that can be searched for */
556
switch (mod_path != NULL) {
558
if (mod_path[0] == '/') {
561
mod_full_path = malloc(sizeof(DEFAULT_MODULE_PATH)+strlen(mod_path));
563
sprintf(mod_full_path, DEFAULT_MODULE_PATH "%s", mod_path);
564
mod_path = mod_full_path;
567
_pam_system_log(LOG_CRIT, "cannot malloc full mod path");
569
mod_path = UNKNOWN_MODULE_PATH;
572
D(("_pam_add_handler: adding type %d, module `%s'",type,mod_path));
573
mod = pamh->handlers.module;
575
/* First, ensure the module is loaded */
576
while (x < pamh->handlers.modules_used) {
577
if (!strcmp(mod[x].name, mod_path)) { /* case sensitive ! */
582
if (x == pamh->handlers.modules_used) {
584
if (pamh->handlers.modules_allocated == pamh->handlers.modules_used) {
585
/* will need more memory */
586
void *tmp = realloc(pamh->handlers.module,
587
(pamh->handlers.modules_allocated+MODULE_CHUNK)
588
*sizeof(struct loaded_module));
590
D(("cannot enlarge module pointer memory"));
591
_pam_system_log(LOG_ERR,
592
"realloc returned NULL in _pam_add_handler");
593
_pam_drop(mod_full_path);
596
pamh->handlers.module = tmp;
597
pamh->handlers.modules_allocated += MODULE_CHUNK;
599
mod = &(pamh->handlers.module[x]);
600
/* Be pessimistic... */
604
D(("_pam_add_handler: dlopen(%s) -> %lx", mod_path, &mod->dl_handle));
607
shl_load(mod_path, BIND_IMMEDIATE, 0L);
609
dlopen(mod_path, RTLD_NOW);
610
# endif /* PAM_SHL */
611
D(("_pam_add_handler: dlopen'ed"));
612
if (mod->dl_handle == NULL) {
613
D(("_pam_add_handler: dlopen(%s) failed", mod_path));
614
_pam_system_log(LOG_ERR, "unable to dlopen(%s)", mod_path);
616
_pam_system_log(LOG_ERR, "[dlerror: %s]", dlerror());
617
# endif /* PAM_SHL */
618
/* Don't abort yet; static code may be able to find function.
619
* But defaults to abort if nothing found below... */
621
D(("module added successfully"));
622
success = PAM_SUCCESS;
623
mod->type = PAM_MT_DYNAMIC_MOD;
624
pamh->handlers.modules_used++;
628
/* Only load static function if function was not found dynamically.
629
* This code should work even if no dynamic loading is available. */
630
if (success != PAM_SUCCESS) {
631
D(("_pam_add_handler: open static handler %s", mod_path));
632
mod->dl_handle = _pam_open_static_handler(mod_path);
633
if (mod->dl_handle == NULL) {
634
D(("_pam_add_handler: unable to find static handler %s",
636
_pam_system_log(LOG_ERR,
637
"unable to open static handler %s", mod_path);
638
/* Didn't find module in dynamic or static..will mark bad */
640
D(("static module added successfully"));
641
success = PAM_SUCCESS;
642
mod->type = PAM_MT_STATIC_MOD;
643
pamh->handlers.modules_used++;
648
if (success != PAM_SUCCESS) { /* add a malformed module */
649
mod->dl_handle = NULL;
650
mod->type = PAM_MT_FAULTY_MOD;
651
pamh->handlers.modules_used++;
652
_pam_system_log(LOG_ERR, "adding faulty module: %s", mod_path);
653
success = PAM_SUCCESS; /* We have successfully added a module */
656
/* indicate its name - later we will search for it by this */
657
if ((mod->name = _pam_strdup(mod_path)) == NULL) {
658
D(("_pam_handler: couldn't get memory for mod_path"));
659
_pam_system_log(LOG_ERR, "no memory for module path", mod_path);
663
} else { /* x != pamh->handlers.modules_used */
664
mod += x; /* the located module */
665
success = PAM_SUCCESS;
668
_pam_drop(mod_full_path);
669
mod_path = NULL; /* no longer needed or trusted */
671
/* Now return error if necessary after trying all possible ways... */
672
if (success != PAM_SUCCESS)
676
* At this point 'mod' points to the stored/loaded module. If its
677
* dl_handle is unknown, then we must be able to indicate dispatch
678
* failure with 'must_fail'
681
/* Now define the handler(s) based on mod->dlhandle and type */
683
/* decide which list of handlers to use */
684
the_handlers = (other) ? &pamh->handlers.other : &pamh->handlers.conf;
686
handler_p = handler_p2 = NULL;
693
/* point handler_p's at the root addresses of the function stacks */
696
handler_p = &the_handlers->authenticate;
697
sym = SHLIB_SYM_PREFIX "pam_sm_authenticate";
698
handler_p2 = &the_handlers->setcred;
699
sym2 = SHLIB_SYM_PREFIX "pam_sm_setcred";
701
_sym = "_pam_sm_authenticate";
702
_sym2 = "_pam_sm_setcred";
706
handler_p = &the_handlers->open_session;
707
sym = SHLIB_SYM_PREFIX "pam_sm_open_session";
708
handler_p2 = &the_handlers->close_session;
709
sym2 = SHLIB_SYM_PREFIX "pam_sm_close_session";
711
_sym = "_pam_sm_open_session";
712
_sym2 = "_pam_sm_close_session";
716
handler_p = &the_handlers->acct_mgmt;
717
sym = SHLIB_SYM_PREFIX "pam_sm_acct_mgmt";
719
_sym = "_pam_sm_acct_mgmt";
723
handler_p = &the_handlers->chauthtok;
724
sym = SHLIB_SYM_PREFIX "pam_sm_chauthtok";
726
_sym = "_pam_sm_chauthtok";
730
/* Illegal module type */
731
D(("_pam_add_handler: illegal module type %d", type));
735
/* are the modules reliable? */
738
mod->type != PAM_MT_DYNAMIC_MOD
740
#endif /* PAM_DYNAMIC */
742
mod->type != PAM_MT_STATIC_MOD
744
#endif /* PAM_STATIC */
745
mod->type != PAM_MT_FAULTY_MOD
747
D(("_pam_add_handlers: illegal module library type; %d", mod->type));
748
_pam_system_log(LOG_ERR,
749
"internal error: module library type not known: %s;%d",
754
/* now identify this module's functions - for non-faulty modules */
757
if ((mod->type == PAM_MT_DYNAMIC_MOD) &&
759
(shl_findsym(&mod->dl_handle, sym, (short) TYPE_PROCEDURE, &func) &&
760
shl_findsym(&mod->dl_handle, _sym, (short) TYPE_PROCEDURE, &func))
762
(func = (servicefn) dlsym(mod->dl_handle, sym)) == NULL
763
# endif /* PAM_SHL */
765
_pam_system_log(LOG_ERR, "unable to resolve symbol: %s", sym);
769
if ((mod->type == PAM_MT_STATIC_MOD) &&
770
(func = (servicefn)_pam_get_static_sym(mod->dl_handle, sym)) == NULL) {
771
_pam_system_log(LOG_ERR, "unable to resolve static symbol: %s", sym);
776
if ((mod->type == PAM_MT_DYNAMIC_MOD) &&
778
(shl_findsym(&mod->dl_handle,sym2,(short)TYPE_PROCEDURE, &func2)&&
779
shl_findsym(&mod->dl_handle,_sym2,(short)TYPE_PROCEDURE, &func2))
781
(func2 = (servicefn) dlsym(mod->dl_handle, sym2)) == NULL
782
# endif /* PAM_SHL */
784
_pam_system_log(LOG_ERR, "unable to resolve symbol: %s", sym2);
788
if ((mod->type == PAM_MT_STATIC_MOD) &&
789
(func2 = (servicefn)_pam_get_static_sym(mod->dl_handle, sym2))
791
_pam_system_log(LOG_ERR, "unable to resolve symbol: %s", sym2);
796
/* here func (and perhaps func2) point to the appropriate functions */
798
/* add new handler to end of existing list */
799
while (*handler_p != NULL) {
800
handler_p = &((*handler_p)->next);
803
if ((*handler_p = malloc(sizeof(struct handler))) == NULL) {
804
_pam_system_log(LOG_CRIT, "cannot malloc struct handler #1");
808
(*handler_p)->must_fail = must_fail; /* failure forced? */
809
(*handler_p)->func = func;
810
memcpy((*handler_p)->actions,actions,sizeof((*handler_p)->actions));
811
(*handler_p)->cached_retval = _PAM_INVALID_RETVAL;
812
(*handler_p)->cached_retval_p = &((*handler_p)->cached_retval);
813
(*handler_p)->argc = argc;
814
(*handler_p)->argv = argv; /* not a copy */
815
(*handler_p)->next = NULL;
817
/* some of the modules have a second calling function */
819
/* add new handler to end of existing list */
820
while (*handler_p2) {
821
handler_p2 = &((*handler_p2)->next);
824
if ((*handler_p2 = malloc(sizeof(struct handler))) == NULL) {
825
_pam_system_log(LOG_CRIT, "cannot malloc struct handler #2");
829
(*handler_p2)->must_fail = must_fail; /* failure forced? */
830
(*handler_p2)->func = func2;
831
memcpy((*handler_p2)->actions,actions,sizeof((*handler_p2)->actions));
832
(*handler_p2)->cached_retval = _PAM_INVALID_RETVAL; /* ignored */
833
/* Note, this next entry points to the handler_p value! */
834
(*handler_p2)->cached_retval_p = &((*handler_p)->cached_retval);
835
(*handler_p2)->argc = argc;
837
if (((*handler_p2)->argv = malloc(argvlen)) == NULL) {
838
_pam_system_log(LOG_CRIT, "cannot malloc argv for handler #2");
841
memcpy((*handler_p2)->argv, argv, argvlen);
843
(*handler_p2)->argv = NULL; /* no arguments */
845
(*handler_p2)->next = NULL;
848
D(("_pam_add_handler: returning successfully"));
853
/* Free various allocated structures and dlclose() the libs */
854
int _pam_free_handlers(pam_handle_t *pamh)
856
struct loaded_module *mod;
859
IF_NO_PAMH("_pam_free_handlers",pamh,PAM_SYSTEM_ERR);
861
mod = pamh->handlers.module;
863
/* Close all loaded modules */
865
while (pamh->handlers.modules_used) {
866
D(("_pam_free_handlers: dlclose(%s)", mod->name));
869
if (mod->type == PAM_MT_DYNAMIC_MOD) {
871
shl_unload(mod->dl_handle);
873
dlclose(mod->dl_handle);
878
pamh->handlers.modules_used--;
881
/* Free all the handlers */
883
_pam_free_handlers_aux(&(pamh->handlers.conf.authenticate));
884
_pam_free_handlers_aux(&(pamh->handlers.conf.setcred));
885
_pam_free_handlers_aux(&(pamh->handlers.conf.acct_mgmt));
886
_pam_free_handlers_aux(&(pamh->handlers.conf.open_session));
887
_pam_free_handlers_aux(&(pamh->handlers.conf.close_session));
888
_pam_free_handlers_aux(&(pamh->handlers.conf.chauthtok));
890
_pam_free_handlers_aux(&(pamh->handlers.other.authenticate));
891
_pam_free_handlers_aux(&(pamh->handlers.other.setcred));
892
_pam_free_handlers_aux(&(pamh->handlers.other.acct_mgmt));
893
_pam_free_handlers_aux(&(pamh->handlers.other.open_session));
894
_pam_free_handlers_aux(&(pamh->handlers.other.close_session));
895
_pam_free_handlers_aux(&(pamh->handlers.other.chauthtok));
897
/* no more loaded modules */
899
_pam_drop(pamh->handlers.module);
901
/* Indicate that handlers are not initialized for this pamh */
903
pamh->handlers.handlers_loaded = 0;
908
void _pam_start_handlers(pam_handle_t *pamh)
911
/* NB. There is no check for a NULL pamh here, since no return
912
* value to communicate the fact! */
914
/* Indicate that handlers are not initialized for this pamh */
915
pamh->handlers.handlers_loaded = 0;
917
pamh->handlers.modules_allocated = 0;
918
pamh->handlers.modules_used = 0;
919
pamh->handlers.module = NULL;
921
/* initialize the .conf and .other entries */
923
pamh->handlers.conf.authenticate = NULL;
924
pamh->handlers.conf.setcred = NULL;
925
pamh->handlers.conf.acct_mgmt = NULL;
926
pamh->handlers.conf.open_session = NULL;
927
pamh->handlers.conf.close_session = NULL;
928
pamh->handlers.conf.chauthtok = NULL;
930
pamh->handlers.other.authenticate = NULL;
931
pamh->handlers.other.setcred = NULL;
932
pamh->handlers.other.acct_mgmt = NULL;
933
pamh->handlers.other.open_session = NULL;
934
pamh->handlers.other.close_session = NULL;
935
pamh->handlers.other.chauthtok = NULL;
938
void _pam_free_handlers_aux(struct handler **hp)
940
struct handler *h = *hp;
941
struct handler *last;
946
_pam_drop(h->argv); /* This is all alocated in a single chunk */
948
memset(last, 0, sizeof(*last));