diff --git a/pam-0.99.8.1-substack.patch b/pam-0.99.8.1-substack.patch new file mode 100644 index 0000000..912df83 --- /dev/null +++ b/pam-0.99.8.1-substack.patch @@ -0,0 +1,784 @@ +Index: libpam/pam_dispatch.c +=================================================================== +RCS file: /cvsroot/pam/Linux-PAM/libpam/pam_dispatch.c,v +retrieving revision 1.11 +diff -u -p -r1.11 pam_dispatch.c +--- libpam/pam_dispatch.c 1 Aug 2006 08:54:57 -0000 1.11 ++++ libpam/pam_dispatch.c 12 Oct 2007 16:23:37 -0000 +@@ -34,7 +34,8 @@ + static int _pam_dispatch_aux(pam_handle_t *pamh, int flags, struct handler *h, + _pam_boolean resumed, int use_cached_chain) + { +- int depth, impression, status, skip_depth; ++ int depth, impression, status, skip_depth, prev_level, stack_level; ++ struct _pam_substack_state *substates = NULL; + + IF_NO_PAMH("_pam_dispatch_aux", pamh, PAM_SYSTEM_ERR); + +@@ -54,27 +55,51 @@ static int _pam_dispatch_aux(pam_handle_ + skip_depth = pamh->former.depth; + status = pamh->former.status; + impression = pamh->former.impression; ++ substates = pamh->former.substates; + /* forget all that */ + pamh->former.impression = _PAM_UNDEF; + pamh->former.status = PAM_MUST_FAIL_CODE; + pamh->former.depth = 0; ++ pamh->former.substates = NULL; + } else { + skip_depth = 0; +- impression = _PAM_UNDEF; +- status = PAM_MUST_FAIL_CODE; ++ substates = malloc(PAM_SUBSTACK_MAX_LEVEL * sizeof(*substates)); ++ if (substates == NULL) { ++ pam_syslog(pamh, LOG_CRIT, ++ "_pam_dispatch_aux: no memory for substack states"); ++ return PAM_BUF_ERR; ++ } ++ substates[0].impression = impression = _PAM_UNDEF; ++ substates[0].status = status = PAM_MUST_FAIL_CODE; + } + ++ prev_level = 0; ++ + /* Loop through module logic stack */ +- for (depth=0 ; h != NULL ; h = h->next, ++depth) { ++ for (depth=0 ; h != NULL ; prev_level = stack_level, h = h->next, ++depth) { + int retval, cached_retval, action; + ++ stack_level = h->stack_level; ++ + /* skip leading modules if they have already returned */ + if (depth < skip_depth) { + continue; + } + ++ /* remember state if we are entering a substack */ ++ if (prev_level < stack_level) { ++ substates[stack_level].impression = impression; ++ substates[stack_level].status = status; ++ } ++ + /* attempt to call the module */ +- if (h->func == NULL) { ++ if (h->handler_type == PAM_HT_MUST_FAIL) { ++ D(("module poorly listed in PAM config; forcing failure")); ++ retval = PAM_MUST_FAIL_CODE; ++ } else if (h->handler_type == PAM_HT_SUBSTACK) { ++ D(("skipping substack handler")); ++ continue; ++ } else if (h->func == NULL) { + D(("module function is not defined, indicating failure")); + retval = PAM_MODULE_UNKNOWN; + } else { +@@ -83,10 +108,6 @@ static int _pam_dispatch_aux(pam_handle_ + retval = h->func(pamh, flags, h->argc, h->argv); + pamh->mod_name=NULL; + D(("module returned: %s", pam_strerror(pamh, retval))); +- if (h->must_fail) { +- D(("module poorly listed in PAM config; forcing failure")); +- retval = PAM_MUST_FAIL_CODE; +- } + } + + /* +@@ -100,6 +121,7 @@ static int _pam_dispatch_aux(pam_handle_ + pamh->former.impression = impression; + pamh->former.status = status; + pamh->former.depth = depth; ++ pamh->former.substates = substates; + + D(("module %d returned PAM_INCOMPLETE", depth)); + return retval; +@@ -176,8 +198,8 @@ static int _pam_dispatch_aux(pam_handle_ + switch (action) { + case _PAM_ACTION_RESET: + +- impression = _PAM_UNDEF; +- status = PAM_MUST_FAIL_CODE; ++ impression = substates[stack_level].impression; ++ status = substates[stack_level].status; + break; + + case _PAM_ACTION_OK: +@@ -244,9 +266,13 @@ static int _pam_dispatch_aux(pam_handle_ + } + + /* this means that we need to skip #action stacked modules */ +- do { +- h = h->next; +- } while ( --action > 0 && h != NULL ); ++ while (h->next != NULL && h->next->stack_level >= stack_level && action > 0) { ++ do { ++ h = h->next; ++ ++depth; ++ } while (h->next != NULL && h->next->stack_level > stack_level); ++ --action; ++ } + + /* note if we try to skip too many modules action is + still non-zero and we snag the next if. */ +@@ -254,14 +280,19 @@ static int _pam_dispatch_aux(pam_handle_ + + /* this case is a syntax error: we can't succeed */ + if (action) { +- D(("action syntax error")); ++ pam_syslog(pamh, LOG_ERR, "bad jump in stack"); + impression = _PAM_NEGATIVE; + status = PAM_MUST_FAIL_CODE; + } + } +- } +- ++ continue; ++ + decision_made: /* by getting here we have made a decision */ ++ while (h->next != NULL && h->next->stack_level >= stack_level) { ++ h = h->next; ++ ++depth; ++ } ++ } + + /* Sanity check */ + if ( status == PAM_SUCCESS && impression != _PAM_POSITIVE ) { +@@ -269,6 +300,7 @@ decision_made: /* by getting here w + status = PAM_MUST_FAIL_CODE; + } + ++ free(substates); + /* We have made a decision about the modules executed */ + return status; + } +Index: libpam/pam_end.c +=================================================================== +RCS file: /cvsroot/pam/Linux-PAM/libpam/pam_end.c,v +retrieving revision 1.4 +diff -u -p -r1.4 pam_end.c +--- libpam/pam_end.c 12 Jan 2006 10:06:49 -0000 1.4 ++++ libpam/pam_end.c 12 Oct 2007 16:23:37 -0000 +@@ -71,6 +71,8 @@ int pam_end(pam_handle_t *pamh, int pam_ + _pam_drop(pamh->pam_conversation); + pamh->fail_delay.delay_fn_ptr = NULL; + ++ _pam_drop(pamh->former.substates); ++ + /* and finally liberate the memory for the pam_handle structure */ + + _pam_drop(pamh); +Index: libpam/pam_handlers.c +=================================================================== +RCS file: /cvsroot/pam/Linux-PAM/libpam/pam_handlers.c,v +retrieving revision 1.24 +diff -u -p -r1.24 pam_handlers.c +--- libpam/pam_handlers.c 14 Jun 2006 11:41:47 -0000 1.24 ++++ libpam/pam_handlers.c 12 Oct 2007 16:23:37 -0000 +@@ -18,7 +18,7 @@ + + #define BUF_SIZE 1024 + #define MODULE_CHUNK 4 +-#define UNKNOWN_MODULE_PATH "<*unknown module path*>" ++#define UNKNOWN_MODULE "<*unknown module*>" + #ifndef _PAM_ISA + #define _PAM_ISA "." + #endif +@@ -28,7 +28,7 @@ static int _pam_assemble_line(FILE *f, c + static void _pam_free_handlers_aux(struct handler **hp); + + static int _pam_add_handler(pam_handle_t *pamh +- , int must_fail, int other, int type ++ , int must_fail, int other, int stack_level, int type + , int *actions, const char *mod_path + , int argc, char **argv, int argvlen); + +@@ -43,6 +43,7 @@ static int _pam_add_handler(pam_handle_t + 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 */ +@@ -51,6 +52,7 @@ static int _pam_load_conf_file(pam_handl + 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 */ +@@ -68,7 +70,7 @@ static int _pam_parse_conf_file(pam_hand + int module_type, actions[_PAM_RETURN_VALUES]; + int other; /* set if module is for PAM_DEFAULT_SERVICE */ + int res; /* module added successfully? */ +- int must_fail=0; /* a badly formatted line must fail when used */ ++ int handler_type = PAM_HT_MODULE; /* regular handler from a module */ + int argc; + char **argv; + int argvlen; +@@ -92,6 +94,7 @@ static int _pam_parse_conf_file(pam_hand + /* 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" +@@ -105,7 +108,7 @@ static int _pam_parse_conf_file(pam_hand + "(%s) empty module type", this_service); + module_type = (requested_module_type != PAM_T_ANY) ? + requested_module_type : PAM_T_AUTH; /* most sensitive */ +- must_fail = 1; /* install as normal but fail when dispatched */ ++ handler_type = PAM_HT_MUST_FAIL; /* install as normal but fail when dispatched */ + } else if (!strcasecmp("auth", tok)) { + module_type = PAM_T_AUTH; + } else if (!strcasecmp("session", tok)) { +@@ -121,9 +124,9 @@ static int _pam_parse_conf_file(pam_hand + this_service, tok); + module_type = (requested_module_type != PAM_T_ANY) ? + requested_module_type : PAM_T_AUTH; /* most sensitive */ +- must_fail = 1; /* install as normal but fail when dispatched */ ++ handler_type = PAM_HT_MUST_FAIL; /* install as normal but fail when dispatched */ + } +- D(("Using %s config entry: %s", must_fail?"BAD ":"", tok)); ++ 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)", +@@ -145,7 +148,7 @@ static int _pam_parse_conf_file(pam_hand + pam_syslog(pamh, LOG_ERR, + "(%s) no control flag supplied", this_service); + _pam_set_default_control(actions, _PAM_ACTION_BAD); +- must_fail = 1; ++ handler_type = PAM_HT_MUST_FAIL; + } else if (!strcasecmp("required", tok)) { + D(("*PAM_F_REQUIRED*")); + actions[PAM_SUCCESS] = _PAM_ACTION_OK; +@@ -171,6 +174,11 @@ static int _pam_parse_conf_file(pam_hand + } 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); +@@ -180,7 +188,18 @@ static int _pam_parse_conf_file(pam_hand + + tok = _pam_StrTok(NULL, " \n\t", &nexttok); + if (pam_include) { +- if (_pam_load_conf_file(pamh, tok, this_service, module_type ++ 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 */ +@@ -188,7 +207,7 @@ static int _pam_parse_conf_file(pam_hand + continue; + _pam_set_default_control(actions, _PAM_ACTION_BAD); + mod_path = NULL; +- must_fail = 1; ++ handler_type = PAM_HT_MUST_FAIL; + nexttok = NULL; + } else if (tok != NULL) { + mod_path = tok; +@@ -199,7 +218,7 @@ static int _pam_parse_conf_file(pam_hand + pam_syslog(pamh, LOG_ERR, + "(%s) no module name supplied", this_service); + mod_path = NULL; +- must_fail = 1; ++ handler_type = PAM_HT_MUST_FAIL; + } + + /* nexttok points to remaining arguments... */ +@@ -219,7 +238,7 @@ static int _pam_parse_conf_file(pam_hand + int y; + + D(("CONF%s: %s%s %d %s %d" +- , must_fail?"<*will fail*>":"" ++ , handler_type==PAM_HT_MUST_FAIL?"<*will fail*>":"" + , this_service, other ? "(backup)":"" + , module_type + , mod_path, argc)); +@@ -235,7 +254,7 @@ static int _pam_parse_conf_file(pam_hand + } + #endif + +- res = _pam_add_handler(pamh, must_fail, other ++ res = _pam_add_handler(pamh, handler_type, other, stack_level + , module_type, actions, mod_path + , argc, argv, argvlen); + if (res != PAM_SUCCESS) { +@@ -252,6 +271,7 @@ static int _pam_parse_conf_file(pam_hand + 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 */ +@@ -263,6 +283,12 @@ static int _pam_load_conf_file(pam_handl + + 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 file supplied", service); +@@ -280,7 +306,7 @@ static int _pam_load_conf_file(pam_handl + D(("opening %s", config_name)); + f = fopen(config_name, "r"); + if (f != NULL) { +- retval = _pam_parse_conf_file(pamh, f, service, module_type ++ retval = _pam_parse_conf_file(pamh, f, service, module_type, stack_level + #ifdef PAM_READ_BOTH_CONFS + , not_other + #endif /* PAM_READ_BOTH_CONFS */ +@@ -379,7 +405,8 @@ int _pam_init_handlers(pam_handle_t *pam + f = fopen(filename, "r"); + if (f != NULL) { + /* would test magic here? */ +- retval = _pam_parse_conf_file(pamh, f, pamh->service_name, PAM_T_ANY ++ 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 */ +@@ -400,7 +427,7 @@ int _pam_init_handlers(pam_handle_t *pam + D(("checking %s", PAM_CONFIG)); + + if ((f = fopen(PAM_CONFIG,"r")) != NULL) { +- retval = _pam_parse_conf_file(pamh, f, NULL, PAM_T_ANY, 1); ++ retval = _pam_parse_conf_file(pamh, f, NULL, PAM_T_ANY, 0, 1); + fclose(f); + } else + #endif /* PAM_READ_BOTH_CONFS */ +@@ -419,9 +446,8 @@ int _pam_init_handlers(pam_handle_t *pam + f = fopen(PAM_DEFAULT_SERVICE_FILE, "r"); + if (f != NULL) { + /* would test magic here? */ +- retval = _pam_parse_conf_file(pamh, f +- , PAM_DEFAULT_SERVICE +- , PAM_T_ANY ++ 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 */ +@@ -454,7 +480,7 @@ int _pam_init_handlers(pam_handle_t *pam + return PAM_ABORT; + } + +- retval = _pam_parse_conf_file(pamh, f, NULL, PAM_T_ANY ++ retval = _pam_parse_conf_file(pamh, f, NULL, PAM_T_ANY, 0 + #ifdef PAM_READ_BOTH_CONFS + , 0 + #endif /* PAM_READ_BOTH_CONFS */ +@@ -581,46 +607,19 @@ extract_modulename(const char *mod_path) + return retval; + } + +-int _pam_add_handler(pam_handle_t *pamh +- , int must_fail, int other, int type +- , int *actions, const char *mod_path +- , int argc, char **argv, int argvlen) ++static struct loaded_module * ++_pam_load_module(pam_handle_t *pamh, const char *mod_path) + { +- struct loaded_module *mod; + int x = 0; +- struct handler **handler_p; +- struct handler **handler_p2; +- struct handlers *the_handlers; +- const char *sym, *sym2; +- char *mod_full_path=NULL; ++ int success; + #ifndef PAM_STATIC + char *mod_full_isa_path=NULL, *isa=NULL; + #endif +- servicefn func, func2; +- int success; +- +- D(("called.")); +- IF_NO_PAMH("_pam_add_handler",pamh,PAM_SYSTEM_ERR); +- +- /* if NULL set to something that can be searched for */ +- switch (mod_path != NULL) { +- default: +- if (mod_path[0] == '/') { +- break; +- } +- if (asprintf(&mod_full_path, "%s%s", +- DEFAULT_MODULE_PATH, mod_path) >= 0) { +- mod_path = mod_full_path; +- break; +- } +- mod_full_path = NULL; +- pam_syslog(pamh, LOG_CRIT, "cannot malloc full mod path"); +- case 0: +- mod_path = UNKNOWN_MODULE_PATH; +- } ++ struct loaded_module *mod; + +- D(("_pam_add_handler: adding type %d, module `%s'",type,mod_path)); +- mod = pamh->handlers.module; ++ 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) { +@@ -639,9 +638,8 @@ int _pam_add_handler(pam_handle_t *pamh + if (tmp == NULL) { + D(("cannot enlarge module pointer memory")); + pam_syslog(pamh, LOG_ERR, +- "realloc returned NULL in _pam_add_handler"); +- _pam_drop(mod_full_path); +- return PAM_ABORT; ++ "realloc returned NULL in _pam_load_module"); ++ return NULL; + } + pamh->handlers.module = tmp; + pamh->handlers.modules_allocated += MODULE_CHUNK; +@@ -654,10 +652,10 @@ int _pam_add_handler(pam_handle_t *pamh + /* Only load static function if function was not found dynamically. + * This code should work even if no dynamic loading is available. */ + if (success != PAM_SUCCESS) { +- D(("_pam_add_handler: open static handler %s", mod_path)); ++ D(("_pam_load_module: open static handler %s", mod_path)); + mod->dl_handle = _pam_open_static_handler(pamh, mod_path); + if (mod->dl_handle == NULL) { +- D(("_pam_add_handler: unable to find static handler %s", ++ D(("_pam_load_module: unable to find static handler %s", + mod_path)); + pam_syslog(pamh, LOG_ERR, + "unable to open static handler %s", mod_path); +@@ -670,15 +668,15 @@ int _pam_add_handler(pam_handle_t *pamh + } + } + #else +- D(("_pam_add_handler: _pam_dlopen(%s)", mod_path)); ++ D(("_pam_load_module: _pam_dlopen(%s)", mod_path)); + mod->dl_handle = _pam_dlopen(mod_path); +- D(("_pam_add_handler: _pam_dlopen'ed")); +- D(("_pam_add_handler: dlopen'ed")); ++ D(("_pam_load_module: _pam_dlopen'ed")); ++ D(("_pam_load_module: dlopen'ed")); + if (mod->dl_handle == NULL) { + if (strstr(mod_path, "$ISA")) { + mod_full_isa_path = malloc(strlen(mod_path) + strlen(_PAM_ISA) + 1); + if (mod_full_isa_path == NULL) { +- D(("_pam_handler: couldn't get memory for mod_path")); ++ D(("_pam_load_module: couldn't get memory for mod_path")); + pam_syslog(pamh, LOG_ERR, "no memory for module path"); + success = PAM_ABORT; + } else { +@@ -694,9 +692,9 @@ int _pam_add_handler(pam_handle_t *pamh + } + } + if (mod->dl_handle == NULL) { +- D(("_pam_add_handler: _pam_dlopen(%s) failed", mod_path)); +- pam_syslog(pamh, LOG_ERR, "unable to dlopen(%s)", mod_path); +- pam_syslog(pamh, LOG_ERR, "[error: %s]", _pam_dlerror()); ++ D(("_pam_load_module: _pam_dlopen(%s) failed", mod_path)); ++ 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 { +@@ -717,7 +715,7 @@ int _pam_add_handler(pam_handle_t *pamh + + /* indicate its name - later we will search for it by this */ + if ((mod->name = _pam_strdup(mod_path)) == NULL) { +- D(("_pam_handler: couldn't get memory for mod_path")); ++ D(("_pam_load_module: couldn't get memory for mod_path")); + pam_syslog(pamh, LOG_ERR, "no memory for module path"); + success = PAM_ABORT; + } +@@ -726,18 +724,54 @@ int _pam_add_handler(pam_handle_t *pamh + 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); + +- _pam_drop(mod_full_path); +- mod_path = NULL; /* no longer needed or trusted */ ++ D(("_pam_add_handler: adding type %d, handler_type %d, module `%s'", ++ type, handler_type, mod_path)); + +- /* Now return error if necessary after trying all possible ways... */ +- if (success != PAM_SUCCESS) +- return(success); ++ if (handler_type == PAM_HT_MODULE && mod_path != NULL) { ++ if (mod_path[0] == '/') { ++ mod = _pam_load_module(pamh, mod_path); ++ } else if (asprintf(&mod_full_path, "%s%s", ++ DEFAULT_MODULE_PATH, mod_path) >= 0) { ++ mod = _pam_load_module(pamh, mod_full_path); ++ _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. If its +- * dl_handle is unknown, then we must be able to indicate dispatch +- * failure with 'must_fail' ++ * At this point 'mod' points to the stored/loaded module. + */ + + /* Now define the handler(s) based on mod->dlhandle and type */ +@@ -780,43 +814,43 @@ int _pam_add_handler(pam_handle_t *pamh + /* are the modules reliable? */ + if ( + #ifdef PAM_STATIC +- mod->type != PAM_MT_STATIC_MOD ++ mod_type != PAM_MT_STATIC_MOD + && + #else +- mod->type != PAM_MT_DYNAMIC_MOD ++ mod_type != PAM_MT_DYNAMIC_MOD + && + #endif +- mod->type != PAM_MT_FAULTY_MOD ++ mod_type != PAM_MT_FAULTY_MOD + ) { +- D(("_pam_add_handlers: illegal module library type; %d", mod->type)); ++ 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); ++ sym, mod_type); + return PAM_ABORT; + } + + /* now identify this module's functions - for non-faulty modules */ + + #ifdef PAM_STATIC +- if ((mod->type == PAM_MT_STATIC_MOD) && ++ if ((mod_type == PAM_MT_STATIC_MOD) && + (func = (servicefn)_pam_get_static_sym(mod->dl_handle, sym)) == NULL) { + pam_syslog(pamh, LOG_ERR, "unable to resolve static symbol: %s", sym); + } + #else +- if ((mod->type == PAM_MT_DYNAMIC_MOD) && ++ 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); + } + #endif + if (sym2) { + #ifdef PAM_STATIC +- if ((mod->type == PAM_MT_STATIC_MOD) && ++ if ((mod_type == PAM_MT_STATIC_MOD) && + (func2 = (servicefn)_pam_get_static_sym(mod->dl_handle, sym2)) + == NULL) { + pam_syslog(pamh, LOG_ERR, "unable to resolve symbol: %s", sym2); + } + #else +- if ((mod->type == PAM_MT_DYNAMIC_MOD) && ++ 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); + } +@@ -835,14 +869,15 @@ int _pam_add_handler(pam_handle_t *pamh + return (PAM_ABORT); + } + +- (*handler_p)->must_fail = must_fail; /* failure forced? */ ++ (*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 */ +- (*handler_p)->mod_name = extract_modulename(mod->name); ++ (*handler_p)->mod_name = extract_modulename(mod_path); + (*handler_p)->next = NULL; + + /* some of the modules have a second calling function */ +@@ -857,7 +892,8 @@ int _pam_add_handler(pam_handle_t *pamh + return (PAM_ABORT); + } + +- (*handler_p2)->must_fail = must_fail; /* failure forced? */ ++ (*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 */ +@@ -873,7 +909,7 @@ int _pam_add_handler(pam_handle_t *pamh + } else { + (*handler_p2)->argv = NULL; /* no arguments */ + } +- (*handler_p2)->mod_name = extract_modulename(mod->name); ++ (*handler_p2)->mod_name = extract_modulename(mod_path); + (*handler_p2)->next = NULL; + } + +Index: libpam/pam_private.h +=================================================================== +RCS file: /cvsroot/pam/Linux-PAM/libpam/pam_private.h,v +retrieving revision 1.19 +diff -u -p -r1.19 pam_private.h +--- libpam/pam_private.h 24 Jul 2006 15:47:40 -0000 1.19 ++++ libpam/pam_private.h 12 Oct 2007 16:23:37 -0000 +@@ -44,7 +44,7 @@ + #define _PAM_INVALID_RETVAL -1 /* default value for cached_retval */ + + struct handler { +- int must_fail; ++ int handler_type; + int (*func)(pam_handle_t *pamh, int flags, int argc, char **argv); + int actions[_PAM_RETURN_VALUES]; + /* set by authenticate, open_session, chauthtok(1st) +@@ -54,8 +54,13 @@ struct handler { + char **argv; + struct handler *next; + char *mod_name; ++ int stack_level; + }; + ++#define PAM_HT_MODULE 0 ++#define PAM_HT_MUST_FAIL 1 ++#define PAM_HT_SUBSTACK 2 ++ + struct loaded_module { + char *name; + int type; /* PAM_STATIC_MOD or PAM_DYNAMIC_MOD */ +@@ -76,7 +81,7 @@ struct handlers { + }; + + struct service { +- struct loaded_module *module; /* Only used for dynamic loading */ ++ struct loaded_module *module; /* Array of modules */ + int modules_allocated; + int modules_used; + int handlers_loaded; +@@ -111,6 +116,12 @@ struct _pam_fail_delay { + const void *delay_fn_ptr; + }; + ++/* initial state in substack */ ++struct _pam_substack_state { ++ int impression; ++ int status; ++}; ++ + struct _pam_former_state { + /* this is known and set by _pam_dispatch() */ + int choice; /* which flavor of module function did we call? */ +@@ -119,6 +130,7 @@ struct _pam_former_state { + int depth; /* how deep in the stack were we? */ + int impression; /* the impression at that time */ + int status; /* the status before returning incomplete */ ++ struct _pam_substack_state *substates; /* array of initial substack states */ + + /* state info used by pam_get_user() function */ + int fail_user; +@@ -175,6 +187,8 @@ struct pam_handle { + #define _PAM_ACTION_UNDEF -6 /* this is treated as an error + ( = _PAM_ACTION_BAD) */ + ++#define PAM_SUBSTACK_MAX_LEVEL 16 /* maximum level of substacks */ ++ + /* character tables for parsing config files */ + extern const char * const _pam_token_actions[-_PAM_ACTION_UNDEF]; + extern const char * const _pam_token_returns[_PAM_RETURN_VALUES+1]; +Index: libpam/pam_start.c +=================================================================== +RCS file: /cvsroot/pam/Linux-PAM/libpam/pam_start.c,v +retrieving revision 1.9 +diff -u -p -r1.9 pam_start.c +--- libpam/pam_start.c 24 Jul 2006 15:47:40 -0000 1.9 ++++ libpam/pam_start.c 12 Oct 2007 16:23:37 -0000 +@@ -88,6 +88,7 @@ int pam_start ( + (*pamh)->oldauthtok = NULL; + (*pamh)->fail_delay.delay_fn_ptr = NULL; + (*pamh)->former.choice = PAM_NOT_STACKED; ++ (*pamh)->former.substates = NULL; + #ifdef HAVE_LIBAUDIT + (*pamh)->audit_state = 0; + #endif +Index: doc/man/pam.conf-syntax.xml +=================================================================== +RCS file: /cvsroot/pam/Linux-PAM/doc/man/pam.conf-syntax.xml,v +retrieving revision 1.4 +retrieving revision 1.5 +diff -u -r1.4 -r1.5 +--- doc/man/pam.conf-syntax.xml 26 Aug 2007 22:44:51 -0000 1.4 ++++ doc/man/pam.conf-syntax.xml 19 Oct 2007 17:06:30 -0000 1.5 +@@ -180,6 +180,24 @@ + + + ++ ++ substack ++ ++ ++ include all lines of given type from the configuration ++ file specified as an argument to this control. This differs from ++ include in that evaluation of the ++ done and die actions ++ in a substack does not cause skipping the rest of the complete ++ module stack, but only of the substack. Jumps in a substack ++ also can not make evaluation jump out of it, and the whole substack ++ is counted as one module when the jump is done in a parent stack. ++ The reset action will reset the state of a ++ module stack to the state it was in as of beginning of the substack ++ evaluation. ++ ++ ++ + + + diff --git a/pam.spec b/pam.spec index ae2d4cf..cd2d790 100644 --- a/pam.spec +++ b/pam.spec @@ -11,7 +11,7 @@ Summary: A security tool which provides authentication for applications Name: pam Version: 0.99.8.1 -Release: 10%{?dist} +Release: 11%{?dist} # The library is BSD licensed with option to relicense as GPLv2+ - this option is redundant # as the BSD license allows that anyway. pam_timestamp and pam_console modules are GPLv2+, # pam_rhosts_auth module is BSD with advertising @@ -44,6 +44,7 @@ Patch44: pam-0.99.7.1-namespace-homedir.patch Patch45: pam-0.99.8.1-selinux-permit.patch Patch46: pam-0.99.8.1-succif-in-operator.patch Patch47: pam-0.99.8.1-xauth-no-free.patch +Patch48: pam-0.99.8.1-substack.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) Requires: cracklib, cracklib-dicts >= 2.8 @@ -115,6 +116,7 @@ popd %patch45 -p1 -b .permit %patch46 -p1 -b .in-operator %patch47 -p1 -b .no-free +%patch48 -p0 -b .substack autoreconf @@ -407,6 +409,9 @@ fi %doc doc/adg/*.txt doc/adg/html %changelog +* Wed Nov 7 2007 Tomas Mraz 0.99.8.1-11 +- add substack support + * Tue Sep 25 2007 Tomas Mraz 0.99.8.1-10 - update db4 to 4.6.19 (#274661)