From 695f6e358dd1e8c05e77bd13f93d85e5963c9c3e Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Fri, 19 Oct 2007 17:06:29 +0000 Subject: [PATCH] Relevant BUGIDs: Purpose of commit: new feature Commit summary: --------------- 2007-10-19 Tomas Mraz * xtests/tst-pam_access1.c: Use different name for user and group. * xtests/tst-pam_access1.sh: Likewise. * xtests/tst-pam_access2.c: Likewise. * xtests/tst-pam_access2.sh: Likewise. * xtests/tst-pam_access4.c: Likewise. * xtests/tst-pam_access4.sh: Likewise. * xtests/group.conf: Likewise. * xtests/tst-pam_group1.c: Likewise. * xtests/tst-pam_group1.sh: Likewise. * libpam/pam_dispatch.c (_pam_dispatch_aux): Save states for substacks, record substack level, skip over virtual substack modules, implement evaluation of done, die, reset and jumps in substacks. Also fixes too far jumps in substacks. * libpam/pam_end.c (pam_end): Drop substack evaluation states. * libpam/pam_handlers.c (_pam_parse_conf_file): Add substack level parameter, instead of must_fail use handler_type needed for virtual substack modules. (_pam_load_conf_file): Add substack level parameter. (_pam_init_handlers): Substack level parameter added to _pam_parse_conf_file() calls. (_pam_load_module): New function. (_pam_add_handler): Refactor code into the _pam_load_module(). Add support for virtual substack modules. * libpam/pam_private.h: Rename must_fail to handler_type, add stack_level to struct handler. Define handler type constants. Add struct for substack evaluation states. Define constant for maximum substack level. Add substack states pointer to former state struct. * libpam/pam_start.c (pam_start): Initialize pointer to substack states. * doc/man/pam.conf-syntax.xml: Document substack control. * xtests/Makefile.am: Add new tests for substack evaluation. * xtests/run_xtests.sh: Support multiple .pamd files in a test. * xtests/tst-pam_authfail.pamd: New tests for substack evaluation. * xtests/tst-pam_authsucceed.pamd: Likewise. * xtests/tst-pam_substack1.pamd: Likewise. * xtests/tst-pam_substack1a.pamd: Likewise. * xtests/tst-pam_substack1.sh: Likewise. * xtests/tst-pam_substack2.pamd: Likewise. * xtests/tst-pam_substack2a.pamd: Likewise. * xtests/tst-pam_substack2.sh: Likewise. * xtests/tst-pam_substack3.pamd: Likewise. * xtests/tst-pam_substack3a.pamd: Likewise. * xtests/tst-pam_substack3.sh: Likewise. * xtests/tst-pam_substack4.pamd: Likewise. * xtests/tst-pam_substack4a.pamd: Likewise. * xtests/tst-pam_substack4.sh: Likewise. * xtests/tst-pam_substack5.pamd: Likewise. * xtests/tst-pam_substack5a.pamd: Likewise. * xtests/tst-pam_substack5.sh: Likewise. --- ChangeLog | 52 ++++++++ NEWS | 1 + doc/man/pam.conf-syntax.xml | 18 +++ libpam/pam_dispatch.c | 66 +++++++--- libpam/pam_end.c | 2 + libpam/pam_handlers.c | 210 +++++++++++++++++++------------- libpam/pam_private.h | 18 ++- libpam/pam_start.c | 1 + xtests/.cvsignore | 2 + xtests/Makefile.am | 16 ++- xtests/group.conf | 2 +- xtests/run-xtests.sh | 6 +- xtests/tst-pam_access1.c | 2 +- xtests/tst-pam_access1.sh | 6 +- xtests/tst-pam_access2.c | 2 +- xtests/tst-pam_access2.sh | 6 +- xtests/tst-pam_access4.c | 2 +- xtests/tst-pam_access4.sh | 4 +- xtests/tst-pam_authfail.c | 96 +++++++++++++++ xtests/tst-pam_authfail.pamd | 5 + xtests/tst-pam_authsucceed.c | 96 +++++++++++++++ xtests/tst-pam_authsucceed.pamd | 5 + xtests/tst-pam_group1.c | 6 +- xtests/tst-pam_group1.sh | 4 +- xtests/tst-pam_substack1.pamd | 5 + xtests/tst-pam_substack1.sh | 3 + xtests/tst-pam_substack1a.pamd | 2 + xtests/tst-pam_substack2.pamd | 6 + xtests/tst-pam_substack2.sh | 3 + xtests/tst-pam_substack2a.pamd | 2 + xtests/tst-pam_substack3.pamd | 5 + xtests/tst-pam_substack3.sh | 3 + xtests/tst-pam_substack3a.pamd | 3 + xtests/tst-pam_substack4.pamd | 5 + xtests/tst-pam_substack4.sh | 3 + xtests/tst-pam_substack4a.pamd | 4 + xtests/tst-pam_substack5.pamd | 4 + xtests/tst-pam_substack5.sh | 3 + xtests/tst-pam_substack5a.pamd | 3 + 39 files changed, 554 insertions(+), 128 deletions(-) create mode 100644 xtests/tst-pam_authfail.c create mode 100644 xtests/tst-pam_authfail.pamd create mode 100644 xtests/tst-pam_authsucceed.c create mode 100644 xtests/tst-pam_authsucceed.pamd create mode 100644 xtests/tst-pam_substack1.pamd create mode 100755 xtests/tst-pam_substack1.sh create mode 100644 xtests/tst-pam_substack1a.pamd create mode 100644 xtests/tst-pam_substack2.pamd create mode 100755 xtests/tst-pam_substack2.sh create mode 100644 xtests/tst-pam_substack2a.pamd create mode 100644 xtests/tst-pam_substack3.pamd create mode 100755 xtests/tst-pam_substack3.sh create mode 100644 xtests/tst-pam_substack3a.pamd create mode 100644 xtests/tst-pam_substack4.pamd create mode 100755 xtests/tst-pam_substack4.sh create mode 100644 xtests/tst-pam_substack4a.pamd create mode 100644 xtests/tst-pam_substack5.pamd create mode 100755 xtests/tst-pam_substack5.sh create mode 100644 xtests/tst-pam_substack5a.pamd diff --git a/ChangeLog b/ChangeLog index 49379e6e..93ccb080 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,55 @@ +2007-10-19 Tomas Mraz + + * xtests/tst-pam_access1.c: Use different name for user and group. + * xtests/tst-pam_access1.sh: Likewise. + * xtests/tst-pam_access2.c: Likewise. + * xtests/tst-pam_access2.sh: Likewise. + * xtests/tst-pam_access4.c: Likewise. + * xtests/tst-pam_access4.sh: Likewise. + * xtests/group.conf: Likewise. + * xtests/tst-pam_group1.c: Likewise. + * xtests/tst-pam_group1.sh: Likewise. + + * libpam/pam_dispatch.c (_pam_dispatch_aux): Save states for substacks, + record substack level, skip over virtual substack modules, implement + evaluation of done, die, reset and jumps in substacks. Also fixes + too far jumps in substacks. + * libpam/pam_end.c (pam_end): Drop substack evaluation states. + * libpam/pam_handlers.c (_pam_parse_conf_file): Add substack level + parameter, instead of must_fail use handler_type needed for virtual + substack modules. + (_pam_load_conf_file): Add substack level parameter. + (_pam_init_handlers): Substack level parameter added to + _pam_parse_conf_file() calls. + (_pam_load_module): New function. + (_pam_add_handler): Refactor code into the _pam_load_module(). Add + support for virtual substack modules. + * libpam/pam_private.h: Rename must_fail to handler_type, add stack_level + to struct handler. Define handler type constants. Add struct + for substack evaluation states. Define constant for maximum + substack level. Add substack states pointer to former state struct. + * libpam/pam_start.c (pam_start): Initialize pointer to substack states. + * doc/man/pam.conf-syntax.xml: Document substack control. + * xtests/Makefile.am: Add new tests for substack evaluation. + * xtests/run_xtests.sh: Support multiple .pamd files in a test. + * xtests/tst-pam_authfail.pamd: New tests for substack evaluation. + * xtests/tst-pam_authsucceed.pamd: Likewise. + * xtests/tst-pam_substack1.pamd: Likewise. + * xtests/tst-pam_substack1a.pamd: Likewise. + * xtests/tst-pam_substack1.sh: Likewise. + * xtests/tst-pam_substack2.pamd: Likewise. + * xtests/tst-pam_substack2a.pamd: Likewise. + * xtests/tst-pam_substack2.sh: Likewise. + * xtests/tst-pam_substack3.pamd: Likewise. + * xtests/tst-pam_substack3a.pamd: Likewise. + * xtests/tst-pam_substack3.sh: Likewise. + * xtests/tst-pam_substack4.pamd: Likewise. + * xtests/tst-pam_substack4a.pamd: Likewise. + * xtests/tst-pam_substack4.sh: Likewise. + * xtests/tst-pam_substack5.pamd: Likewise. + * xtests/tst-pam_substack5a.pamd: Likewise. + * xtests/tst-pam_substack5.sh: Likewise. + 2007-10-18 Tomas Mraz * xtests/tst-pam_dispatch4.c: Fix comment about the test. * xtests/tst-pam_dispatch4.pamd: Improve the testcase. diff --git a/NEWS b/NEWS index 2b14fec9..acc6d0f2 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,6 @@ Linux-PAM NEWS -- history of user-visible changes. +* New substack directive in config file syntax. Release 0.99.9.0 * misc_conv no longer blocks SIGINT; applications that don't want diff --git a/doc/man/pam.conf-syntax.xml b/doc/man/pam.conf-syntax.xml index f098a26a..1460c6f6 100644 --- a/doc/man/pam.conf-syntax.xml +++ b/doc/man/pam.conf-syntax.xml @@ -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/libpam/pam_dispatch.c b/libpam/pam_dispatch.c index ab032d74..fa4e5ed4 100644 --- a/libpam/pam_dispatch.c +++ b/libpam/pam_dispatch.c @@ -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_t *pamh, int flags, struct handler *h, 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_t *pamh, int flags, struct handler *h, 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_t *pamh, int flags, struct handler *h, 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_t *pamh, int flags, struct handler *h, 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_t *pamh, int flags, struct handler *h, } /* 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_t *pamh, int flags, struct handler *h, /* 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 we have made a decision */ status = PAM_MUST_FAIL_CODE; } + free(substates); /* We have made a decision about the modules executed */ return status; } diff --git a/libpam/pam_end.c b/libpam/pam_end.c index e46dd0c4..de1c26ed 100644 --- a/libpam/pam_end.c +++ b/libpam/pam_end.c @@ -71,6 +71,8 @@ int pam_end(pam_handle_t *pamh, int pam_status) _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); diff --git a/libpam/pam_handlers.c b/libpam/pam_handlers.c index 87d781d2..11508145 100644 --- a/libpam/pam_handlers.c +++ b/libpam/pam_handlers.c @@ -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, 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 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 *pamh 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_handle_t *pamh, const char *config_name 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_handle_t *pamh, FILE *f 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_handle_t *pamh, FILE *f /* 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_handle_t *pamh, FILE *f "(%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_handle_t *pamh, FILE *f 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_handle_t *pamh, FILE *f 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_handle_t *pamh, FILE *f } 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_handle_t *pamh, FILE *f 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_handle_t *pamh, FILE *f 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_handle_t *pamh, FILE *f 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_handle_t *pamh, FILE *f 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_handle_t *pamh, FILE *f } #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_handle_t *pamh, FILE *f 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_handle_t *pamh, const char *config_name 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_handle_t *pamh, const char *config_name 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 *pamh) 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 *pamh) 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 *pamh) 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 *pamh) 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; + struct loaded_module *mod; - 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; - } - - 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; +} - _pam_drop(mod_full_path); - mod_path = NULL; /* no longer needed or trusted */ +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; - /* Now return error if necessary after trying all possible ways... */ - if (success != PAM_SUCCESS) - return(success); + 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 && 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; } diff --git a/libpam/pam_private.h b/libpam/pam_private.h index 8b7d9146..bf32ad44 100644 --- a/libpam/pam_private.h +++ b/libpam/pam_private.h @@ -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]; diff --git a/libpam/pam_start.c b/libpam/pam_start.c index 6f6df6b1..7b0d3aa4 100644 --- a/libpam/pam_start.c +++ b/libpam/pam_start.c @@ -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 diff --git a/xtests/.cvsignore b/xtests/.cvsignore index 00c9ad07..530ce890 100644 --- a/xtests/.cvsignore +++ b/xtests/.cvsignore @@ -19,3 +19,5 @@ tst-pam_unix2 tst-pam_unix3 tst-pam_succeed_if1 tst-pam_group1 +tst-pam_authfail +tst-pam_authsucceed diff --git a/xtests/Makefile.am b/xtests/Makefile.am index 8b6dbd25..62e32643 100644 --- a/xtests/Makefile.am +++ b/xtests/Makefile.am @@ -21,7 +21,13 @@ EXTRA_DIST = run-xtests.sh tst-pam_dispatch1.pamd tst-pam_dispatch2.pamd \ tst-pam_access4.pamd tst-pam_access4.sh \ limits.conf tst-pam_limits1.pamd tst-pam_limits1.sh \ tst-pam_succeed_if1.pamd tst-pam_succeed_if1.sh \ - group.conf tst-pam_group1.pamd tst-pam_group1.sh + group.conf tst-pam_group1.pamd tst-pam_group1.sh \ + tst-pam_authfail.pamd tst-pam_authsucceed.pamd \ + tst-pam_substack1.pamd tst-pam_substack1a.pamd tst-pam_substack1.sh \ + tst-pam_substack2.pamd tst-pam_substack2a.pamd tst-pam_substack2.sh \ + tst-pam_substack3.pamd tst-pam_substack3a.pamd tst-pam_substack3.sh \ + tst-pam_substack4.pamd tst-pam_substack4a.pamd tst-pam_substack4.sh \ + tst-pam_substack5.pamd tst-pam_substack5a.pamd tst-pam_substack5.sh XTESTS = tst-pam_dispatch1 tst-pam_dispatch2 tst-pam_dispatch3 \ tst-pam_dispatch4 tst-pam_dispatch5 \ @@ -29,9 +35,13 @@ XTESTS = tst-pam_dispatch1 tst-pam_dispatch2 tst-pam_dispatch3 \ tst-pam_unix1 tst-pam_unix2 tst-pam_unix3 \ tst-pam_access1 tst-pam_access2 tst-pam_access3 \ tst-pam_access4 tst-pam_limits1 tst-pam_succeed_if1 \ - tst-pam_group1 + tst-pam_group1 tst-pam_authfail tst-pam_authsucceed + +NOSRCTESTS = tst-pam_substack1 tst-pam_substack2 tst-pam_substack3 \ + tst-pam_substack4 tst-pam_substack5 + noinst_PROGRAMS = $(XTESTS) xtests: $(XTESTS) run-xtests.sh - "$(srcdir)"/run-xtests.sh "$(srcdir)" ${XTESTS} + "$(srcdir)"/run-xtests.sh "$(srcdir)" ${XTESTS} ${NOSRCTESTS} diff --git a/xtests/group.conf b/xtests/group.conf index bcfe3755..04fe3ef7 100644 --- a/xtests/group.conf +++ b/xtests/group.conf @@ -1,3 +1,3 @@ -tst-pam_group1;tty1;tstpamgrp;Al0000-2400;tstpamgrp +tst-pam_group1;tty1;tstpamgrp;Al0000-2400;tstpamgrpg diff --git a/xtests/run-xtests.sh b/xtests/run-xtests.sh index 53dbdf06..4e981858 100755 --- a/xtests/run-xtests.sh +++ b/xtests/run-xtests.sh @@ -24,7 +24,9 @@ install -m 644 "${SRCDIR}"/group.conf /etc/security/group.conf cp /etc/security/limits.conf /etc/security/limits.conf-pam-xtests install -m 644 "${SRCDIR}"/limits.conf /etc/security/limits.conf for testname in $XTESTS ; do - install -m 644 "${SRCDIR}"/$testname.pamd /etc/pam.d/$testname + for cfg in "${SRCDIR}"/$testname*.pamd ; do + install -m 644 $cfg /etc/pam.d/$(basename $cfg .pamd) + done if test -x "${SRCDIR}"/$testname.sh ; then "${SRCDIR}"/$testname.sh > /dev/null else @@ -42,7 +44,7 @@ for testname in $XTESTS ; do pass=`expr $pass + 1` fi all=`expr $all + 1` - rm -f /etc/pam.d/$testname + rm -f /etc/pam.d/$testname* done mv /etc/security/access.conf-pam-xtests /etc/security/access.conf mv /etc/security/group.conf-pam-xtests /etc/security/group.conf diff --git a/xtests/tst-pam_access1.c b/xtests/tst-pam_access1.c index 06b65f0c..457b95d4 100644 --- a/xtests/tst-pam_access1.c +++ b/xtests/tst-pam_access1.c @@ -87,7 +87,7 @@ int main(int argc, char *argv[]) { pam_handle_t *pamh = NULL; - const char *user="tstpamaccess"; + const char *user="tstpamaccess1"; int retval; int debug = 0; diff --git a/xtests/tst-pam_access1.sh b/xtests/tst-pam_access1.sh index 48d8cb3e..180d2563 100755 --- a/xtests/tst-pam_access1.sh +++ b/xtests/tst-pam_access1.sh @@ -1,9 +1,9 @@ #!/bin/bash -/usr/sbin/groupadd -p '!!' tstpamaccess -/usr/sbin/useradd -G tstpamaccess -p '!!' tstpamaccess +/usr/sbin/groupadd tstpamaccess +/usr/sbin/useradd -G tstpamaccess -p '!!' tstpamaccess1 ./tst-pam_access1 RET=$? -/usr/sbin/userdel -r tstpamaccess 2> /dev/null +/usr/sbin/userdel -r tstpamaccess1 2> /dev/null /usr/sbin/groupdel tstpamaccess 2> /dev/null exit $RET diff --git a/xtests/tst-pam_access2.c b/xtests/tst-pam_access2.c index 194d07d7..b6e18812 100644 --- a/xtests/tst-pam_access2.c +++ b/xtests/tst-pam_access2.c @@ -87,7 +87,7 @@ int main(int argc, char *argv[]) { pam_handle_t *pamh = NULL; - const char *user="tstpamaccess"; + const char *user="tstpamaccess2"; int retval; int debug = 0; diff --git a/xtests/tst-pam_access2.sh b/xtests/tst-pam_access2.sh index c1b3c992..0a302759 100755 --- a/xtests/tst-pam_access2.sh +++ b/xtests/tst-pam_access2.sh @@ -1,9 +1,9 @@ #!/bin/bash -/usr/sbin/groupadd -p '!!' tstpamaccess -/usr/sbin/useradd -p '!!' tstpamaccess +/usr/sbin/groupadd tstpamaccess +/usr/sbin/useradd -p '!!' tstpamaccess2 ./tst-pam_access2 RET=$? -/usr/sbin/userdel -r tstpamaccess 2> /dev/null +/usr/sbin/userdel -r tstpamaccess2 2> /dev/null /usr/sbin/groupdel tstpamaccess 2> /dev/null exit $RET diff --git a/xtests/tst-pam_access4.c b/xtests/tst-pam_access4.c index 1e53a364..acdb46f1 100644 --- a/xtests/tst-pam_access4.c +++ b/xtests/tst-pam_access4.c @@ -87,7 +87,7 @@ int main(int argc, char *argv[]) { pam_handle_t *pamh = NULL; - const char *user="tstpamaccess"; + const char *user="tstpamaccess4"; int retval; int debug = 0; diff --git a/xtests/tst-pam_access4.sh b/xtests/tst-pam_access4.sh index 58bf260d..61e7b448 100755 --- a/xtests/tst-pam_access4.sh +++ b/xtests/tst-pam_access4.sh @@ -1,7 +1,7 @@ #!/bin/bash -/usr/sbin/useradd -p '!!' tstpamaccess +/usr/sbin/useradd -p '!!' tstpamaccess4 ./tst-pam_access4 RET=$? -/usr/sbin/userdel -r tstpamaccess 2> /dev/null +/usr/sbin/userdel -r tstpamaccess4 2> /dev/null exit $RET diff --git a/xtests/tst-pam_authfail.c b/xtests/tst-pam_authfail.c new file mode 100644 index 00000000..afdbd6a4 --- /dev/null +++ b/xtests/tst-pam_authfail.c @@ -0,0 +1,96 @@ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +static struct pam_conv conv = { + misc_conv, + NULL +}; + + +/* Check that auth stack fails. */ + +int +main(int argc, char *argv[]) +{ + pam_handle_t *pamh=NULL; + const char *user="nobody"; + const char *stack="tst-pam_authfail"; + int retval; + int debug = 0; + + if (argc > 2) { + stack = argv[2]; + } + + if (argc > 1) { + if (strcmp (argv[1], "-d") == 0) + debug = 1; + else + stack = argv[1]; + } + + + retval = pam_start(stack, user, &conv, &pamh); + if (retval != PAM_SUCCESS) + { + if (debug) + fprintf (stderr, "test3: pam_start returned %d\n", retval); + return 1; + } + + retval = pam_authenticate(pamh, 0); + if (retval == PAM_SUCCESS) + { + if (debug) + fprintf (stderr, "test3: pam_authenticate returned %d\n", retval); + return 1; + } + + retval = pam_end(pamh,retval); + if (retval != PAM_SUCCESS) + { + if (debug) + fprintf (stderr, "test3: pam_end returned %d\n", retval); + return 1; + } + return 0; +} diff --git a/xtests/tst-pam_authfail.pamd b/xtests/tst-pam_authfail.pamd new file mode 100644 index 00000000..8ff1a40f --- /dev/null +++ b/xtests/tst-pam_authfail.pamd @@ -0,0 +1,5 @@ +#%PAM-1.0 +# test that successful sufficient module cannot affect stack +# after failed required module +auth required pam_debug.so auth=perm_denied +auth sufficient pam_debug.so auth=success diff --git a/xtests/tst-pam_authsucceed.c b/xtests/tst-pam_authsucceed.c new file mode 100644 index 00000000..8666f3f7 --- /dev/null +++ b/xtests/tst-pam_authsucceed.c @@ -0,0 +1,96 @@ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +static struct pam_conv conv = { + misc_conv, + NULL +}; + + +/* Check that auth stack succeeds. */ + +int +main(int argc, char *argv[]) +{ + pam_handle_t *pamh=NULL; + const char *user="nobody"; + const char *stack="tst-pam_authsucceed"; + int retval; + int debug = 0; + + if (argc > 2) { + stack = argv[2]; + } + + if (argc > 1) { + if (strcmp (argv[1], "-d") == 0) + debug = 1; + else + stack = argv[1]; + } + + + retval = pam_start(stack, user, &conv, &pamh); + if (retval != PAM_SUCCESS) + { + if (debug) + fprintf (stderr, "test3: pam_start returned %d\n", retval); + return 1; + } + + retval = pam_authenticate(pamh, 0); + if (retval != PAM_SUCCESS) + { + if (debug) + fprintf (stderr, "test3: pam_authenticate returned %d\n", retval); + return 1; + } + + retval = pam_end(pamh,retval); + if (retval != PAM_SUCCESS) + { + if (debug) + fprintf (stderr, "test3: pam_end returned %d\n", retval); + return 1; + } + return 0; +} diff --git a/xtests/tst-pam_authsucceed.pamd b/xtests/tst-pam_authsucceed.pamd new file mode 100644 index 00000000..abaa1eff --- /dev/null +++ b/xtests/tst-pam_authsucceed.pamd @@ -0,0 +1,5 @@ +#%PAM-1.0 +# test that failed sufficient module cannot affect stack +# with following successful required module +auth sufficient pam_debug.so auth=auth_err +auth required pam_debug.so auth=success diff --git a/xtests/tst-pam_group1.c b/xtests/tst-pam_group1.c index e4e3ca48..f5a04bc0 100644 --- a/xtests/tst-pam_group1.c +++ b/xtests/tst-pam_group1.c @@ -36,10 +36,10 @@ Check the following line in group.conf: - tst-pam_group1;*;tstpamgrp;Al0000-2400;tstpamgrp + tst-pam_group1;*;tstpamgrp;Al0000-2400;tstpamgrpg - pam_group should add group tstpamgrp to user tstpamgrp, but not + pam_group should add group tstpamgrpg to user tstpamgrp, but not to tstpamgrp2. */ @@ -193,7 +193,7 @@ main(int argc, char *argv[]) if (argc > 1 && strcmp (argv[1], "-d") == 0) debug = 1; - grp = getgrnam ("tstpamgrp"); + grp = getgrnam ("tstpamgrpg"); if (grp == NULL) return 1; grpid = grp->gr_gid; diff --git a/xtests/tst-pam_group1.sh b/xtests/tst-pam_group1.sh index 2d38a6ad..b76377f5 100755 --- a/xtests/tst-pam_group1.sh +++ b/xtests/tst-pam_group1.sh @@ -1,11 +1,11 @@ #!/bin/bash -/usr/sbin/groupadd -p '!!' tstpamgrp +/usr/sbin/groupadd tstpamgrpg /usr/sbin/useradd -p '!!' tstpamgrp /usr/sbin/useradd -p '!!' tstpamgrp2 ./tst-pam_group1 RET=$? /usr/sbin/userdel -r tstpamgrp 2> /dev/null /usr/sbin/userdel -r tstpamgrp2 2> /dev/null -/usr/sbin/groupdel tstpamgrp 2> /dev/null +/usr/sbin/groupdel tstpamgrpg 2> /dev/null exit $RET diff --git a/xtests/tst-pam_substack1.pamd b/xtests/tst-pam_substack1.pamd new file mode 100644 index 00000000..6eab233e --- /dev/null +++ b/xtests/tst-pam_substack1.pamd @@ -0,0 +1,5 @@ +#%PAM-1.0 +# Even if the substack succeeds with sufficient +# the whole stack should fail. +auth substack tst-pam_substack1a +auth required pam_debug.so auth=auth_err diff --git a/xtests/tst-pam_substack1.sh b/xtests/tst-pam_substack1.sh new file mode 100755 index 00000000..52601755 --- /dev/null +++ b/xtests/tst-pam_substack1.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +exec ./tst-pam_authfail tst-pam_substack1 diff --git a/xtests/tst-pam_substack1a.pamd b/xtests/tst-pam_substack1a.pamd new file mode 100644 index 00000000..51c8c8fd --- /dev/null +++ b/xtests/tst-pam_substack1a.pamd @@ -0,0 +1,2 @@ +#%PAM-1.0 +auth sufficient pam_debug.so auth=success diff --git a/xtests/tst-pam_substack2.pamd b/xtests/tst-pam_substack2.pamd new file mode 100644 index 00000000..618e2986 --- /dev/null +++ b/xtests/tst-pam_substack2.pamd @@ -0,0 +1,6 @@ +#%PAM-1.0 +# Even if the substack fails with requisite +# the whole stack should succeed. +auth substack tst-pam_substack2a +auth [success=reset] pam_permit.so +auth required pam_debug.so auth=success diff --git a/xtests/tst-pam_substack2.sh b/xtests/tst-pam_substack2.sh new file mode 100755 index 00000000..c02f597e --- /dev/null +++ b/xtests/tst-pam_substack2.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +exec ./tst-pam_authsucceed tst-pam_substack2 diff --git a/xtests/tst-pam_substack2a.pamd b/xtests/tst-pam_substack2a.pamd new file mode 100644 index 00000000..db853542 --- /dev/null +++ b/xtests/tst-pam_substack2a.pamd @@ -0,0 +1,2 @@ +#%PAM-1.0 +auth requisite pam_debug.so auth=auth_err diff --git a/xtests/tst-pam_substack3.pamd b/xtests/tst-pam_substack3.pamd new file mode 100644 index 00000000..4fc6016c --- /dev/null +++ b/xtests/tst-pam_substack3.pamd @@ -0,0 +1,5 @@ +#%PAM-1.0 +# Reset in the substack resets to state as of it was +# in the beginning of substack evaluation +auth required pam_permit.so +auth substack tst-pam_substack3a diff --git a/xtests/tst-pam_substack3.sh b/xtests/tst-pam_substack3.sh new file mode 100755 index 00000000..0e572aae --- /dev/null +++ b/xtests/tst-pam_substack3.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +exec ./tst-pam_authsucceed tst-pam_substack3 diff --git a/xtests/tst-pam_substack3a.pamd b/xtests/tst-pam_substack3a.pamd new file mode 100644 index 00000000..a2ae915c --- /dev/null +++ b/xtests/tst-pam_substack3a.pamd @@ -0,0 +1,3 @@ +#%PAM-1.0 +auth required pam_debug.so auth=auth_err +auth [success=reset] pam_permit.so diff --git a/xtests/tst-pam_substack4.pamd b/xtests/tst-pam_substack4.pamd new file mode 100644 index 00000000..f0017c75 --- /dev/null +++ b/xtests/tst-pam_substack4.pamd @@ -0,0 +1,5 @@ +#%PAM-1.0 +# Substack is counted as one module in jumps +auth [success=1] pam_permit.so +auth substack tst-pam_substack4a +auth required pam_permit.so diff --git a/xtests/tst-pam_substack4.sh b/xtests/tst-pam_substack4.sh new file mode 100755 index 00000000..a3ef08a7 --- /dev/null +++ b/xtests/tst-pam_substack4.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +exec ./tst-pam_authsucceed tst-pam_substack4 diff --git a/xtests/tst-pam_substack4a.pamd b/xtests/tst-pam_substack4a.pamd new file mode 100644 index 00000000..3b91c1ba --- /dev/null +++ b/xtests/tst-pam_substack4a.pamd @@ -0,0 +1,4 @@ +#%PAM-1.0 +auth required pam_debug.so auth=auth_err +auth required pam_debug.so auth=auth_err +auth required pam_debug.so auth=auth_err diff --git a/xtests/tst-pam_substack5.pamd b/xtests/tst-pam_substack5.pamd new file mode 100644 index 00000000..04f07aeb --- /dev/null +++ b/xtests/tst-pam_substack5.pamd @@ -0,0 +1,4 @@ +#%PAM-1.0 +# Requisite terminates substack +auth required pam_permit.so +auth substack tst-pam_substack5a diff --git a/xtests/tst-pam_substack5.sh b/xtests/tst-pam_substack5.sh new file mode 100755 index 00000000..e2714fda --- /dev/null +++ b/xtests/tst-pam_substack5.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +exec ./tst-pam_authfail tst-pam_substack5 diff --git a/xtests/tst-pam_substack5a.pamd b/xtests/tst-pam_substack5a.pamd new file mode 100644 index 00000000..a6850f40 --- /dev/null +++ b/xtests/tst-pam_substack5a.pamd @@ -0,0 +1,3 @@ +#%PAM-1.0 +auth requisite pam_debug.so auth=auth_err +auth [success=reset] pam_permit.so