1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045 |
- /* pam_handlers.c -- pam config file parsing and module loading */
- /*
- * created by Marc Ewing.
- * Currently maintained by Andrew G. Morgan <morgan@kernel.org>
- *
- */
- #include "pam_private.h"
- #include "pam_inline.h"
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <unistd.h>
- #define BUF_SIZE 1024
- #define MODULE_CHUNK 4
- #define UNKNOWN_MODULE "<*unknown module*>"
- #ifndef _PAM_ISA
- #define _PAM_ISA "."
- #endif
- static int _pam_assemble_line(FILE *f, char *buf, int buf_len);
- static void _pam_free_handlers_aux(struct handler **hp);
- static int _pam_add_handler(pam_handle_t *pamh
- , int must_fail, int other, int stack_level, int type
- , int *actions, const char *mod_path
- , int argc, char **argv, int argvlen);
- /* Values for module type */
- #define PAM_T_ANY 0
- #define PAM_T_AUTH 1
- #define PAM_T_SESS 2
- #define PAM_T_ACCT 4
- #define PAM_T_PASS 8
- static int _pam_load_conf_file(pam_handle_t *pamh, const char *config_name
- , const char *service /* specific file */
- , int module_type /* specific type */
- , int stack_level /* level of substack */
- #ifdef PAM_READ_BOTH_CONFS
- , int not_other
- #endif /* PAM_READ_BOTH_CONFS */
- );
- static int _pam_parse_conf_file(pam_handle_t *pamh, FILE *f
- , const char *known_service /* specific file */
- , int requested_module_type /* specific type */
- , int stack_level /* level of substack */
- #ifdef PAM_READ_BOTH_CONFS
- , int not_other
- #endif /* PAM_READ_BOTH_CONFS */
- )
- {
- char buf[BUF_SIZE];
- int x; /* read a line from the FILE *f ? */
- /*
- * read a line from the configuration (FILE *) f
- */
- while ((x = _pam_assemble_line(f, buf, BUF_SIZE)) > 0) {
- char *tok, *nexttok=NULL;
- const char *this_service;
- const char *mod_path;
- int module_type, actions[_PAM_RETURN_VALUES];
- int other; /* set if module is for PAM_DEFAULT_SERVICE */
- int res; /* module added successfully? */
- int handler_type = PAM_HT_MODULE; /* regular handler from a module */
- int argc;
- char **argv;
- int argvlen;
- D(("_pam_init_handler: LINE: %s", buf));
- if (known_service != NULL) {
- nexttok = buf;
- /* No service field: all lines are for the known service. */
- this_service = known_service;
- } else {
- this_service = tok = _pam_StrTok(buf, " \n\t", &nexttok);
- }
- #ifdef PAM_READ_BOTH_CONFS
- if (not_other)
- other = 0;
- else
- #endif /* PAM_READ_BOTH_CONFS */
- other = !strcasecmp(this_service, PAM_DEFAULT_SERVICE);
- /* accept "service name" or PAM_DEFAULT_SERVICE modules */
- if (!strcasecmp(this_service, pamh->service_name) || other) {
- int pam_include = 0;
- int substack = 0;
- /* This is a service we are looking for */
- D(("_pam_init_handlers: Found PAM config entry for: %s"
- , this_service));
- tok = _pam_StrTok(NULL, " \n\t", &nexttok);
- if (tok == NULL) {
- /* module type does not exist */
- D(("_pam_init_handlers: empty module type for %s", this_service));
- pam_syslog(pamh, LOG_ERR,
- "(%s) empty module type", this_service);
- module_type = (requested_module_type != PAM_T_ANY) ?
- requested_module_type : PAM_T_AUTH; /* most sensitive */
- handler_type = PAM_HT_MUST_FAIL; /* install as normal but fail when dispatched */
- } else {
- if (tok[0] == '-') { /* do not log module load errors */
- handler_type = PAM_HT_SILENT_MODULE;
- ++tok;
- }
- if (!strcasecmp("auth", tok)) {
- module_type = PAM_T_AUTH;
- } else if (!strcasecmp("session", tok)) {
- module_type = PAM_T_SESS;
- } else if (!strcasecmp("account", tok)) {
- module_type = PAM_T_ACCT;
- } else if (!strcasecmp("password", tok)) {
- module_type = PAM_T_PASS;
- } else {
- /* Illegal module type */
- D(("_pam_init_handlers: bad module type: %s", tok));
- pam_syslog(pamh, LOG_ERR, "(%s) illegal module type: %s",
- this_service, tok);
- module_type = (requested_module_type != PAM_T_ANY) ?
- requested_module_type : PAM_T_AUTH; /* most sensitive */
- handler_type = PAM_HT_MUST_FAIL; /* install as normal but fail when dispatched */
- }
- }
- D(("Using %s config entry: %s", handler_type?"BAD ":"", tok));
- if (requested_module_type != PAM_T_ANY &&
- module_type != requested_module_type) {
- D(("Skipping config entry: %s (requested=%d, found=%d)",
- tok, requested_module_type, module_type));
- continue;
- }
- /* reset the actions to .._UNDEF's -- this is so that
- we can work out which entries are not yet set (for default). */
- {
- int i;
- for (i=0; i<_PAM_RETURN_VALUES;
- actions[i++] = _PAM_ACTION_UNDEF);
- }
- tok = _pam_StrTok(NULL, " \n\t", &nexttok);
- if (tok == NULL) {
- /* no module name given */
- D(("_pam_init_handlers: no control flag supplied"));
- pam_syslog(pamh, LOG_ERR,
- "(%s) no control flag supplied", this_service);
- _pam_set_default_control(actions, _PAM_ACTION_BAD);
- handler_type = PAM_HT_MUST_FAIL;
- } else if (!strcasecmp("required", tok)) {
- D(("*PAM_F_REQUIRED*"));
- actions[PAM_SUCCESS] = _PAM_ACTION_OK;
- actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
- actions[PAM_IGNORE] = _PAM_ACTION_IGNORE;
- _pam_set_default_control(actions, _PAM_ACTION_BAD);
- } else if (!strcasecmp("requisite", tok)) {
- D(("*PAM_F_REQUISITE*"));
- actions[PAM_SUCCESS] = _PAM_ACTION_OK;
- actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
- actions[PAM_IGNORE] = _PAM_ACTION_IGNORE;
- _pam_set_default_control(actions, _PAM_ACTION_DIE);
- } else if (!strcasecmp("optional", tok)) {
- D(("*PAM_F_OPTIONAL*"));
- actions[PAM_SUCCESS] = _PAM_ACTION_OK;
- actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
- _pam_set_default_control(actions, _PAM_ACTION_IGNORE);
- } else if (!strcasecmp("sufficient", tok)) {
- D(("*PAM_F_SUFFICIENT*"));
- actions[PAM_SUCCESS] = _PAM_ACTION_DONE;
- actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_DONE;
- _pam_set_default_control(actions, _PAM_ACTION_IGNORE);
- } else if (!strcasecmp("include", tok)) {
- D(("*PAM_F_INCLUDE*"));
- pam_include = 1;
- substack = 0;
- } else if (!strcasecmp("substack", tok)) {
- D(("*PAM_F_SUBSTACK*"));
- pam_include = 1;
- substack = 1;
- } else {
- D(("will need to parse %s", tok));
- _pam_parse_control(actions, tok);
- /* by default the default is to treat as failure */
- _pam_set_default_control(actions, _PAM_ACTION_BAD);
- }
- tok = _pam_StrTok(NULL, " \n\t", &nexttok);
- if (pam_include) {
- if (substack) {
- res = _pam_add_handler(pamh, PAM_HT_SUBSTACK, other,
- stack_level, module_type, actions, tok,
- 0, NULL, 0);
- if (res != PAM_SUCCESS) {
- pam_syslog(pamh, LOG_ERR, "error adding substack %s", tok);
- D(("failed to load module - aborting"));
- return PAM_ABORT;
- }
- }
- if (_pam_load_conf_file(pamh, tok, this_service, module_type,
- stack_level + substack
- #ifdef PAM_READ_BOTH_CONFS
- , !other
- #endif /* PAM_READ_BOTH_CONFS */
- ) == PAM_SUCCESS)
- continue;
- _pam_set_default_control(actions, _PAM_ACTION_BAD);
- mod_path = NULL;
- handler_type = PAM_HT_MUST_FAIL;
- nexttok = NULL;
- } else if (tok != NULL) {
- mod_path = tok;
- D(("mod_path = %s",mod_path));
- } else {
- /* no module name given */
- D(("_pam_init_handlers: no module name supplied"));
- pam_syslog(pamh, LOG_ERR,
- "(%s) no module name supplied", this_service);
- mod_path = NULL;
- handler_type = PAM_HT_MUST_FAIL;
- }
- /* nexttok points to remaining arguments... */
- if (nexttok != NULL) {
- D(("list: %s",nexttok));
- argvlen = _pam_mkargv(nexttok, &argv, &argc);
- D(("argvlen = %d",argvlen));
- } else { /* there are no arguments so fix by hand */
- D(("_pam_init_handlers: empty argument list"));
- argvlen = argc = 0;
- argv = NULL;
- }
- #ifdef PAM_DEBUG
- {
- int y;
- D(("CONF%s: %s%s %d %s %d"
- , handler_type==PAM_HT_MUST_FAIL?"<*will fail*>":""
- , this_service, other ? "(backup)":""
- , module_type
- , mod_path, argc));
- for (y = 0; y < argc; y++) {
- D(("CONF: %s", argv[y]));
- }
- for (y = 0; y<_PAM_RETURN_VALUES; ++y) {
- D(("RETURN %s(%d) -> %d %s",
- _pam_token_returns[y], y, actions[y],
- actions[y]>0 ? "jump":
- _pam_token_actions[-actions[y]]));
- }
- }
- #endif
- res = _pam_add_handler(pamh, handler_type, other, stack_level
- , module_type, actions, mod_path
- , argc, argv, argvlen);
- if (res != PAM_SUCCESS) {
- pam_syslog(pamh, LOG_ERR, "error loading %s", mod_path);
- D(("failed to load module - aborting"));
- return PAM_ABORT;
- }
- }
- }
- return ( (x < 0) ? PAM_ABORT:PAM_SUCCESS );
- }
- static int
- _pam_open_config_file(pam_handle_t *pamh
- , const char *service
- , char **path
- , FILE **file)
- {
- const char *pamd_dirs[] = { PAM_CONFIG_DF, PAM_CONFIG_DIST_DF
- #ifdef VENDORDIR
- , PAM_CONFIG_DIST2_DF
- #endif
- };
- char *p = NULL;
- FILE *f;
- size_t i;
- /* Absolute path */
- if (service[0] == '/') {
- p = _pam_strdup(service);
- if (p == NULL) {
- pam_syslog(pamh, LOG_CRIT, "strdup failed");
- return PAM_BUF_ERR;
- }
- } else if (pamh->confdir != NULL) {
- if (asprintf (&p, "%s/%s", pamh->confdir, service) < 0) {
- pam_syslog(pamh, LOG_CRIT, "asprintf failed");
- return PAM_BUF_ERR;
- }
- }
- if (p != NULL) {
- D(("opening %s", p));
- f = fopen(p, "r");
- if (f != NULL) {
- *path = p;
- *file = f;
- return PAM_SUCCESS;
- }
- _pam_drop(p);
- return PAM_ABORT;
- }
- for (i = 0; i < PAM_ARRAY_SIZE(pamd_dirs); i++) {
- if (asprintf (&p, pamd_dirs[i], service) < 0) {
- pam_syslog(pamh, LOG_CRIT, "asprintf failed");
- return PAM_BUF_ERR;
- }
- D(("opening %s", p));
- f = fopen(p, "r");
- if (f != NULL) {
- *path = p;
- *file = f;
- return PAM_SUCCESS;
- }
- _pam_drop(p);
- }
- return PAM_ABORT;
- }
- static int _pam_load_conf_file(pam_handle_t *pamh, const char *config_name
- , const char *service /* specific file */
- , int module_type /* specific type */
- , int stack_level /* level of substack */
- #ifdef PAM_READ_BOTH_CONFS
- , int not_other
- #endif /* PAM_READ_BOTH_CONFS */
- )
- {
- FILE *f;
- char *path = NULL;
- int retval = PAM_ABORT;
- D(("_pam_load_conf_file called"));
- if (stack_level >= PAM_SUBSTACK_MAX_LEVEL) {
- D(("maximum level of substacks reached"));
- pam_syslog(pamh, LOG_ERR, "maximum level of substacks reached");
- return PAM_ABORT;
- }
- if (config_name == NULL) {
- D(("no config file supplied"));
- pam_syslog(pamh, LOG_ERR, "(%s) no config name supplied", service);
- return PAM_ABORT;
- }
- if (_pam_open_config_file(pamh, config_name, &path, &f) == PAM_SUCCESS) {
- retval = _pam_parse_conf_file(pamh, f, service, module_type, stack_level
- #ifdef PAM_READ_BOTH_CONFS
- , not_other
- #endif /* PAM_READ_BOTH_CONFS */
- );
- if (retval != PAM_SUCCESS)
- pam_syslog(pamh, LOG_ERR,
- "_pam_load_conf_file: error reading %s: %s",
- path, pam_strerror(pamh, retval));
- _pam_drop(path);
- fclose(f);
- } else {
- D(("unable to open %s", config_name));
- pam_syslog(pamh, LOG_ERR,
- "_pam_load_conf_file: unable to open config for %s",
- config_name);
- }
- return retval;
- }
- /* Parse config file, allocate handler structures, dlopen() */
- int _pam_init_handlers(pam_handle_t *pamh)
- {
- FILE *f;
- int retval;
- D(("_pam_init_handlers called"));
- IF_NO_PAMH("_pam_init_handlers",pamh,PAM_SYSTEM_ERR);
- /* Return immediately if everything is already loaded */
- if (pamh->handlers.handlers_loaded) {
- return PAM_SUCCESS;
- }
- D(("_pam_init_handlers: initializing"));
- /* First clean the service structure */
- _pam_free_handlers(pamh);
- if (! pamh->handlers.module) {
- if ((pamh->handlers.module =
- malloc(MODULE_CHUNK * sizeof(struct loaded_module))) == NULL) {
- pam_syslog(pamh, LOG_CRIT,
- "_pam_init_handlers: no memory loading module");
- return PAM_BUF_ERR;
- }
- pamh->handlers.modules_allocated = MODULE_CHUNK;
- pamh->handlers.modules_used = 0;
- }
- if (pamh->service_name == NULL) {
- return PAM_BAD_ITEM; /* XXX - better error? */
- }
- #ifdef PAM_LOCKING
- /* Is the PAM subsystem locked? */
- {
- int fd_tmp;
- if ((fd_tmp = open( PAM_LOCK_FILE, O_RDONLY )) != -1) {
- pam_syslog(pamh, LOG_ERR,
- "_pam_init_handlers: PAM lockfile ("
- PAM_LOCK_FILE ") exists - aborting");
- (void) close(fd_tmp);
- /*
- * to avoid swamping the system with requests
- */
- _pam_start_timer(pamh);
- pam_fail_delay(pamh, 5000000);
- _pam_await_timer(pamh, PAM_ABORT);
- return PAM_ABORT;
- }
- }
- #endif /* PAM_LOCKING */
- /*
- * Now parse the config file(s) and add handlers
- */
- {
- struct stat test_d;
- /* Is there a PAM_CONFIG_D directory? */
- if (pamh->confdir != NULL ||
- (stat(PAM_CONFIG_D, &test_d) == 0 && S_ISDIR(test_d.st_mode)) ||
- (stat(PAM_CONFIG_DIST_D, &test_d) == 0 && S_ISDIR(test_d.st_mode))
- #ifdef PAM_CONFIG_DIST2_D
- || (stat(PAM_CONFIG_DIST2_D, &test_d) == 0
- && S_ISDIR(test_d.st_mode))
- #endif
- ) {
- char *path = NULL;
- int read_something=0;
- if (_pam_open_config_file(pamh, pamh->service_name, &path, &f) == PAM_SUCCESS) {
- retval = _pam_parse_conf_file(pamh, f, pamh->service_name,
- PAM_T_ANY, 0
- #ifdef PAM_READ_BOTH_CONFS
- , 0
- #endif /* PAM_READ_BOTH_CONFS */
- );
- if (retval != PAM_SUCCESS) {
- pam_syslog(pamh, LOG_ERR,
- "_pam_init_handlers: error reading %s",
- path);
- pam_syslog(pamh, LOG_ERR, "_pam_init_handlers: [%s]",
- pam_strerror(pamh, retval));
- } else {
- read_something = 1;
- }
- _pam_drop(path);
- fclose(f);
- } else {
- D(("unable to open configuration for %s", pamh->service_name));
- #ifdef PAM_READ_BOTH_CONFS
- D(("checking %s", PAM_CONFIG));
- if (pamh->confdir == NULL
- && (f = fopen(PAM_CONFIG,"r")) != NULL) {
- retval = _pam_parse_conf_file(pamh, f, NULL, PAM_T_ANY, 0, 1);
- fclose(f);
- } else
- #endif /* PAM_READ_BOTH_CONFS */
- retval = PAM_SUCCESS;
- /*
- * XXX - should we log an error? Some people want to always
- * use "other"
- */
- }
- if (retval == PAM_SUCCESS) {
- /* now parse the PAM_DEFAULT_SERVICE */
- if (_pam_open_config_file(pamh, PAM_DEFAULT_SERVICE, &path, &f) == PAM_SUCCESS) {
- /* would test magic here? */
- retval = _pam_parse_conf_file(pamh, f, PAM_DEFAULT_SERVICE,
- PAM_T_ANY, 0
- #ifdef PAM_READ_BOTH_CONFS
- , 0
- #endif /* PAM_READ_BOTH_CONFS */
- );
- if (retval != PAM_SUCCESS) {
- pam_syslog(pamh, LOG_ERR,
- "_pam_init_handlers: error reading %s",
- path);
- pam_syslog(pamh, LOG_ERR,
- "_pam_init_handlers: [%s]",
- pam_strerror(pamh, retval));
- } else {
- read_something = 1;
- }
- _pam_drop(path);
- fclose(f);
- } else {
- D(("unable to open %s", PAM_DEFAULT_SERVICE));
- pam_syslog(pamh, LOG_ERR,
- "_pam_init_handlers: no default config %s",
- PAM_DEFAULT_SERVICE);
- }
- if (!read_something) { /* nothing read successfully */
- retval = PAM_ABORT;
- }
- }
- } else {
- if ((f = fopen(PAM_CONFIG, "r")) == NULL) {
- pam_syslog(pamh, LOG_ERR, "_pam_init_handlers: could not open "
- PAM_CONFIG );
- return PAM_ABORT;
- }
- retval = _pam_parse_conf_file(pamh, f, NULL, PAM_T_ANY, 0
- #ifdef PAM_READ_BOTH_CONFS
- , 0
- #endif /* PAM_READ_BOTH_CONFS */
- );
- D(("closing configuration file"));
- fclose(f);
- }
- }
- if (retval != PAM_SUCCESS) {
- /* Read error */
- pam_syslog(pamh, LOG_ERR, "error reading PAM configuration file");
- return PAM_ABORT;
- }
- pamh->handlers.handlers_loaded = 1;
- D(("_pam_init_handlers exiting"));
- return PAM_SUCCESS;
- }
- /*
- * This is where we read a line of the PAM config file. The line may be
- * preceded by lines of comments and also extended with "\\\n"
- */
- static int _pam_assemble_line(FILE *f, char *buffer, int buf_len)
- {
- char *p = buffer;
- char *endp = buffer + buf_len;
- char *s, *os;
- int used = 0;
- /* loop broken with a 'break' when a non-'\\n' ended line is read */
- D(("called."));
- for (;;) {
- if (p >= endp) {
- /* Overflow */
- D(("_pam_assemble_line: overflow"));
- return -1;
- }
- if (fgets(p, endp - p, f) == NULL) {
- if (used) {
- /* Incomplete read */
- return -1;
- } else {
- /* EOF */
- return 0;
- }
- }
- /* skip leading spaces --- line may be blank */
- s = p + strspn(p, " \n\t");
- if (*s && (*s != '#')) {
- os = s;
- /*
- * we are only interested in characters before the first '#'
- * character
- */
- while (*s && *s != '#')
- ++s;
- if (*s == '#') {
- *s = '\0';
- used += strlen(os);
- break; /* the line has been read */
- }
- s = os;
- /*
- * Check for backslash by scanning back from the end of
- * the entered line, the '\n' has been included since
- * normally a line is terminated with this
- * character. fgets() should only return one though!
- */
- s += strlen(s);
- while (s > os && ((*--s == ' ') || (*s == '\t')
- || (*s == '\n')));
- /* check if it ends with a backslash */
- if (*s == '\\') {
- *s++ = ' '; /* replace backslash with ' ' */
- *s = '\0'; /* truncate the line here */
- used += strlen(os);
- p = s; /* there is more ... */
- } else {
- /* End of the line! */
- used += strlen(os);
- break; /* this is the complete line */
- }
- } else {
- /* Nothing in this line */
- /* Don't move p */
- }
- }
- return used;
- }
- static char *
- extract_modulename(const char *mod_path)
- {
- const char *p = strrchr (mod_path, '/');
- char *dot, *retval;
- if (p == NULL)
- p = mod_path;
- else
- p++;
- if ((retval = _pam_strdup (p)) == NULL)
- return NULL;
- dot = strrchr (retval, '.');
- if (dot)
- *dot = '\0';
- if (*retval == '\0' || strcmp(retval, "?") == 0) {
- /* do not allow empty module name or "?" to avoid confusing audit trail */
- _pam_drop(retval);
- return NULL;
- }
- return retval;
- }
- static struct loaded_module *
- _pam_load_module(pam_handle_t *pamh, const char *mod_path, int handler_type)
- {
- int x = 0;
- int success;
- struct loaded_module *mod;
- D(("_pam_load_module: loading module `%s'", mod_path));
- mod = pamh->handlers.module;
- /* First, ensure the module is loaded */
- while (x < pamh->handlers.modules_used) {
- if (!strcmp(mod[x].name, mod_path)) { /* case sensitive ! */
- break;
- }
- x++;
- }
- if (x == pamh->handlers.modules_used) {
- /* Not found */
- if (pamh->handlers.modules_allocated == pamh->handlers.modules_used) {
- /* will need more memory */
- void *tmp = realloc(pamh->handlers.module,
- (pamh->handlers.modules_allocated+MODULE_CHUNK)
- *sizeof(struct loaded_module));
- if (tmp == NULL) {
- D(("cannot enlarge module pointer memory"));
- pam_syslog(pamh, LOG_CRIT,
- "realloc returned NULL in _pam_load_module");
- return NULL;
- }
- pamh->handlers.module = tmp;
- pamh->handlers.modules_allocated += MODULE_CHUNK;
- }
- mod = &(pamh->handlers.module[x]);
- /* Be pessimistic... */
- success = PAM_ABORT;
- D(("_pam_load_module: _pam_dlopen(%s)", mod_path));
- mod->dl_handle = _pam_dlopen(mod_path);
- D(("_pam_load_module: _pam_dlopen'ed"));
- D(("_pam_load_module: dlopen'ed"));
- if (mod->dl_handle == NULL) {
- const char *isa = strstr(mod_path, "$ISA");
- size_t isa_len = strlen("$ISA");
- if (isa != NULL) {
- size_t pam_isa_len = strlen(_PAM_ISA);
- char *mod_full_isa_path =
- malloc(strlen(mod_path) - isa_len + pam_isa_len + 1);
- if (mod_full_isa_path == NULL) {
- D(("_pam_load_module: couldn't get memory for mod_path"));
- pam_syslog(pamh, LOG_CRIT, "no memory for module path");
- success = PAM_ABORT;
- } else {
- char *p = mod_full_isa_path;
- memcpy(p, mod_path, isa - mod_path);
- p += isa - mod_path;
- memcpy(p, _PAM_ISA, pam_isa_len);
- p += pam_isa_len;
- strcpy(p, isa + isa_len);
- mod->dl_handle = _pam_dlopen(mod_full_isa_path);
- _pam_drop(mod_full_isa_path);
- }
- }
- }
- if (mod->dl_handle == NULL) {
- D(("_pam_load_module: _pam_dlopen(%s) failed", mod_path));
- if (handler_type != PAM_HT_SILENT_MODULE)
- pam_syslog(pamh, LOG_ERR, "unable to dlopen(%s): %s", mod_path,
- _pam_dlerror());
- /* Don't abort yet; static code may be able to find function.
- * But defaults to abort if nothing found below... */
- } else {
- D(("module added successfully"));
- success = PAM_SUCCESS;
- mod->type = PAM_MT_DYNAMIC_MOD;
- pamh->handlers.modules_used++;
- }
- if (success != PAM_SUCCESS) { /* add a malformed module */
- mod->dl_handle = NULL;
- mod->type = PAM_MT_FAULTY_MOD;
- pamh->handlers.modules_used++;
- if (handler_type != PAM_HT_SILENT_MODULE)
- pam_syslog(pamh, LOG_ERR, "adding faulty module: %s", mod_path);
- success = PAM_SUCCESS; /* We have successfully added a module */
- }
- /* indicate its name - later we will search for it by this */
- if ((mod->name = _pam_strdup(mod_path)) == NULL) {
- D(("_pam_load_module: couldn't get memory for mod_path"));
- pam_syslog(pamh, LOG_CRIT, "no memory for module path");
- success = PAM_ABORT;
- }
- } else { /* x != pamh->handlers.modules_used */
- mod += x; /* the located module */
- success = PAM_SUCCESS;
- }
- return success == PAM_SUCCESS ? mod : NULL;
- }
- int _pam_add_handler(pam_handle_t *pamh
- , int handler_type, int other, int stack_level, int type
- , int *actions, const char *mod_path
- , int argc, char **argv, int argvlen)
- {
- struct loaded_module *mod = NULL;
- struct handler **handler_p;
- struct handler **handler_p2;
- struct handlers *the_handlers;
- const char *sym, *sym2;
- char *mod_full_path;
- servicefn func, func2;
- int mod_type = PAM_MT_FAULTY_MOD;
- D(("called."));
- IF_NO_PAMH("_pam_add_handler",pamh,PAM_SYSTEM_ERR);
- D(("_pam_add_handler: adding type %d, handler_type %d, module `%s'",
- type, handler_type, mod_path));
- if ((handler_type == PAM_HT_MODULE || handler_type == PAM_HT_SILENT_MODULE) &&
- mod_path != NULL) {
- if (mod_path[0] == '/') {
- mod = _pam_load_module(pamh, mod_path, handler_type);
- } else if (asprintf(&mod_full_path, "%s%s",
- DEFAULT_MODULE_PATH, mod_path) >= 0) {
- mod = _pam_load_module(pamh, mod_full_path, handler_type);
- _pam_drop(mod_full_path);
- } else {
- pam_syslog(pamh, LOG_CRIT, "cannot malloc full mod path");
- return PAM_ABORT;
- }
- if (mod == NULL) {
- /* if we get here with NULL it means allocation error */
- return PAM_ABORT;
- }
- mod_type = mod->type;
- }
- if (mod_path == NULL)
- mod_path = UNKNOWN_MODULE;
- /*
- * At this point 'mod' points to the stored/loaded module.
- */
- /* Now define the handler(s) based on mod->dlhandle and type */
- /* decide which list of handlers to use */
- the_handlers = (other) ? &pamh->handlers.other : &pamh->handlers.conf;
- handler_p = handler_p2 = NULL;
- func = func2 = NULL;
- sym2 = NULL;
- /* point handler_p's at the root addresses of the function stacks */
- switch (type) {
- case PAM_T_AUTH:
- handler_p = &the_handlers->authenticate;
- sym = "pam_sm_authenticate";
- handler_p2 = &the_handlers->setcred;
- sym2 = "pam_sm_setcred";
- break;
- case PAM_T_SESS:
- handler_p = &the_handlers->open_session;
- sym = "pam_sm_open_session";
- handler_p2 = &the_handlers->close_session;
- sym2 = "pam_sm_close_session";
- break;
- case PAM_T_ACCT:
- handler_p = &the_handlers->acct_mgmt;
- sym = "pam_sm_acct_mgmt";
- break;
- case PAM_T_PASS:
- handler_p = &the_handlers->chauthtok;
- sym = "pam_sm_chauthtok";
- break;
- default:
- /* Illegal module type */
- D(("_pam_add_handler: illegal module type %d", type));
- return PAM_ABORT;
- }
- /* are the modules reliable? */
- if (mod_type != PAM_MT_DYNAMIC_MOD &&
- mod_type != PAM_MT_FAULTY_MOD) {
- D(("_pam_add_handlers: illegal module library type; %d", mod_type));
- pam_syslog(pamh, LOG_ERR,
- "internal error: module library type not known: %s;%d",
- sym, mod_type);
- return PAM_ABORT;
- }
- /* now identify this module's functions - for non-faulty modules */
- if ((mod_type == PAM_MT_DYNAMIC_MOD) &&
- !(func = _pam_dlsym(mod->dl_handle, sym)) ) {
- pam_syslog(pamh, LOG_ERR, "unable to resolve symbol: %s", sym);
- }
- if (sym2) {
- if ((mod_type == PAM_MT_DYNAMIC_MOD) &&
- !(func2 = _pam_dlsym(mod->dl_handle, sym2)) ) {
- pam_syslog(pamh, LOG_ERR, "unable to resolve symbol: %s", sym2);
- }
- }
- /* here func (and perhaps func2) point to the appropriate functions */
- /* add new handler to end of existing list */
- while (*handler_p != NULL) {
- handler_p = &((*handler_p)->next);
- }
- if ((*handler_p = malloc(sizeof(struct handler))) == NULL) {
- pam_syslog(pamh, LOG_CRIT, "cannot malloc struct handler #1");
- return (PAM_ABORT);
- }
- (*handler_p)->handler_type = handler_type;
- (*handler_p)->stack_level = stack_level;
- (*handler_p)->func = func;
- memcpy((*handler_p)->actions,actions,sizeof((*handler_p)->actions));
- (*handler_p)->cached_retval = _PAM_INVALID_RETVAL;
- (*handler_p)->cached_retval_p = &((*handler_p)->cached_retval);
- (*handler_p)->argc = argc;
- (*handler_p)->argv = argv; /* not a copy */
- if (((*handler_p)->mod_name = extract_modulename(mod_path)) == NULL)
- return PAM_ABORT;
- (*handler_p)->grantor = 0;
- (*handler_p)->next = NULL;
- /* some of the modules have a second calling function */
- if (handler_p2) {
- /* add new handler to end of existing list */
- while (*handler_p2) {
- handler_p2 = &((*handler_p2)->next);
- }
- if ((*handler_p2 = malloc(sizeof(struct handler))) == NULL) {
- pam_syslog(pamh, LOG_CRIT, "cannot malloc struct handler #2");
- return (PAM_ABORT);
- }
- (*handler_p2)->handler_type = handler_type;
- (*handler_p2)->stack_level = stack_level;
- (*handler_p2)->func = func2;
- memcpy((*handler_p2)->actions,actions,sizeof((*handler_p2)->actions));
- (*handler_p2)->cached_retval = _PAM_INVALID_RETVAL; /* ignored */
- /* Note, this next entry points to the handler_p value! */
- (*handler_p2)->cached_retval_p = &((*handler_p)->cached_retval);
- (*handler_p2)->argc = argc;
- if (argv) {
- if (((*handler_p2)->argv = malloc(argvlen)) == NULL) {
- pam_syslog(pamh, LOG_CRIT, "cannot malloc argv for handler #2");
- return (PAM_ABORT);
- }
- memcpy((*handler_p2)->argv, argv, argvlen);
- } else {
- (*handler_p2)->argv = NULL; /* no arguments */
- }
- if (((*handler_p2)->mod_name = extract_modulename(mod_path)) == NULL)
- return PAM_ABORT;
- (*handler_p2)->grantor = 0;
- (*handler_p2)->next = NULL;
- }
- D(("_pam_add_handler: returning successfully"));
- return PAM_SUCCESS;
- }
- /* Free various allocated structures and dlclose() the libs */
- int _pam_free_handlers(pam_handle_t *pamh)
- {
- struct loaded_module *mod;
- D(("called."));
- IF_NO_PAMH("_pam_free_handlers",pamh,PAM_SYSTEM_ERR);
- mod = pamh->handlers.module;
- /* Close all loaded modules */
- while (pamh->handlers.modules_used) {
- D(("_pam_free_handlers: dlclose(%s)", mod->name));
- free(mod->name);
- if (mod->type == PAM_MT_DYNAMIC_MOD) {
- _pam_dlclose(mod->dl_handle);
- }
- mod++;
- pamh->handlers.modules_used--;
- }
- /* Free all the handlers */
- _pam_free_handlers_aux(&(pamh->handlers.conf.authenticate));
- _pam_free_handlers_aux(&(pamh->handlers.conf.setcred));
- _pam_free_handlers_aux(&(pamh->handlers.conf.acct_mgmt));
- _pam_free_handlers_aux(&(pamh->handlers.conf.open_session));
- _pam_free_handlers_aux(&(pamh->handlers.conf.close_session));
- _pam_free_handlers_aux(&(pamh->handlers.conf.chauthtok));
- _pam_free_handlers_aux(&(pamh->handlers.other.authenticate));
- _pam_free_handlers_aux(&(pamh->handlers.other.setcred));
- _pam_free_handlers_aux(&(pamh->handlers.other.acct_mgmt));
- _pam_free_handlers_aux(&(pamh->handlers.other.open_session));
- _pam_free_handlers_aux(&(pamh->handlers.other.close_session));
- _pam_free_handlers_aux(&(pamh->handlers.other.chauthtok));
- /* no more loaded modules */
- _pam_drop(pamh->handlers.module);
- /* Indicate that handlers are not initialized for this pamh */
- pamh->handlers.handlers_loaded = 0;
- return PAM_SUCCESS;
- }
- void _pam_start_handlers(pam_handle_t *pamh)
- {
- D(("called."));
- /* NB. There is no check for a NULL pamh here, since no return
- * value to communicate the fact! */
- /* Indicate that handlers are not initialized for this pamh */
- pamh->handlers.handlers_loaded = 0;
- pamh->handlers.modules_allocated = 0;
- pamh->handlers.modules_used = 0;
- pamh->handlers.module = NULL;
- /* initialize the .conf and .other entries */
- pamh->handlers.conf.authenticate = NULL;
- pamh->handlers.conf.setcred = NULL;
- pamh->handlers.conf.acct_mgmt = NULL;
- pamh->handlers.conf.open_session = NULL;
- pamh->handlers.conf.close_session = NULL;
- pamh->handlers.conf.chauthtok = NULL;
- pamh->handlers.other.authenticate = NULL;
- pamh->handlers.other.setcred = NULL;
- pamh->handlers.other.acct_mgmt = NULL;
- pamh->handlers.other.open_session = NULL;
- pamh->handlers.other.close_session = NULL;
- pamh->handlers.other.chauthtok = NULL;
- }
- void _pam_free_handlers_aux(struct handler **hp)
- {
- struct handler *h = *hp;
- struct handler *last;
- D(("called."));
- while (h) {
- last = h;
- _pam_drop(h->argv); /* This is all allocated in a single chunk */
- _pam_drop(h->mod_name);
- h = h->next;
- memset(last, 0, sizeof(*last));
- free(last);
- }
- *hp = NULL;
- }
|