785 lines
28 KiB
Diff
785 lines
28 KiB
Diff
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 @@
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
+ <varlistentry>
|
|
+ <term>substack</term>
|
|
+ <listitem>
|
|
+ <para>
|
|
+ include all lines of given type from the configuration
|
|
+ file specified as an argument to this control. This differs from
|
|
+ <emphasis>include</emphasis> in that evaluation of the
|
|
+ <emphasis>done</emphasis> and <emphasis>die</emphasis> 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 <emphasis>reset</emphasis> action will reset the state of a
|
|
+ module stack to the state it was in as of beginning of the substack
|
|
+ evaluation.
|
|
+ </para>
|
|
+ </listitem>
|
|
+ </varlistentry>
|
|
</variablelist>
|
|
|
|
<para>
|