]> granicus.if.org Git - linux-pam/blobdiff - libpam/pam_handlers.c
pam_unix: fix build in --enable-selinux mode
[linux-pam] / libpam / pam_handlers.c
index 9035fb2fae724ef46f2f425bbbda552ba13a2906..02714f781bb9c437dc6432aaaf20ce2b87201c2d 100644 (file)
@@ -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;
@@ -87,11 +89,12 @@ static int _pam_parse_conf_file(pam_handle_t *pamh, FILE *f
            other = 0;
        else
 #endif /* PAM_READ_BOTH_CONFS */
-       other = !_pam_strCMP(this_service, PAM_DEFAULT_SERVICE);
+       other = !strcasecmp(this_service, PAM_DEFAULT_SERVICE);
 
        /* accept "service name" or PAM_DEFAULT_SERVICE modules */
-       if (!_pam_strCMP(this_service, pamh->service_name) || other) {
+       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,25 +108,31 @@ 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 */
-           } else if (!_pam_strCMP("auth", tok)) {
-               module_type = PAM_T_AUTH;
-           } else if (!_pam_strCMP("session", tok)) {
-               module_type = PAM_T_SESS;
-           } else if (!_pam_strCMP("account", tok)) {
-               module_type = PAM_T_ACCT;
-           } else if (!_pam_strCMP("password", tok)) {
-               module_type = PAM_T_PASS;
+               handler_type = PAM_HT_MUST_FAIL; /* install as normal but fail when dispatched */
            } else {
-               /* Illegal module type */
-               D(("_pam_init_handlers: bad module type: %s", tok));
-               pam_syslog(pamh, LOG_ERR, "(%s) illegal module type: %s",
-                          this_service, tok);
-               module_type = (requested_module_type != PAM_T_ANY) ?
-                             requested_module_type : PAM_T_AUTH;       /* most sensitive */
-               must_fail = 1; /* install as normal but fail when dispatched */
+               if (tok[0] == '-') { /* do not log module load errors */
+                   handler_type = PAM_HT_SILENT_MODULE;
+                   ++tok;
+               }
+               if (!strcasecmp("auth", tok)) {
+                   module_type = PAM_T_AUTH;
+               } else if (!strcasecmp("session", tok)) {
+                   module_type = PAM_T_SESS;
+               } else if (!strcasecmp("account", tok)) {
+                   module_type = PAM_T_ACCT;
+               } else if (!strcasecmp("password", tok)) {
+                   module_type = PAM_T_PASS;
+               } else {
+                   /* Illegal module type */
+                   D(("_pam_init_handlers: bad module type: %s", tok));
+                   pam_syslog(pamh, LOG_ERR, "(%s) illegal module type: %s",
+                           this_service, tok);
+                   module_type = (requested_module_type != PAM_T_ANY) ?
+                           requested_module_type : PAM_T_AUTH; /* most sensitive */
+                   handler_type = PAM_HT_MUST_FAIL; /* install as normal but fail when dispatched */
+               }
            }
-           D(("Using %s config entry: %s", 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,32 +154,37 @@ 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;
-           } else if (!_pam_strCMP("required", tok)) {
+               handler_type = PAM_HT_MUST_FAIL;
+           } else if (!strcasecmp("required", tok)) {
                D(("*PAM_F_REQUIRED*"));
                actions[PAM_SUCCESS] = _PAM_ACTION_OK;
                actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
                 actions[PAM_IGNORE] = _PAM_ACTION_IGNORE;
                _pam_set_default_control(actions, _PAM_ACTION_BAD);
-           } else if (!_pam_strCMP("requisite", tok)) {
+           } else if (!strcasecmp("requisite", tok)) {
                D(("*PAM_F_REQUISITE*"));
                actions[PAM_SUCCESS] = _PAM_ACTION_OK;
                actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
                 actions[PAM_IGNORE] = _PAM_ACTION_IGNORE;
                _pam_set_default_control(actions, _PAM_ACTION_DIE);
-           } else if (!_pam_strCMP("optional", tok)) {
+           } else if (!strcasecmp("optional", tok)) {
                D(("*PAM_F_OPTIONAL*"));
                actions[PAM_SUCCESS] = _PAM_ACTION_OK;
                actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
                _pam_set_default_control(actions, _PAM_ACTION_IGNORE);
-           } else if (!_pam_strCMP("sufficient", tok)) {
+           } else if (!strcasecmp("sufficient", tok)) {
                D(("*PAM_F_SUFFICIENT*"));
                actions[PAM_SUCCESS] = _PAM_ACTION_DONE;
                actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_DONE;
                _pam_set_default_control(actions, _PAM_ACTION_IGNORE);
-           } else if (!_pam_strCMP("include", tok)) {
+           } 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 +194,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 +213,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 +224,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... */
@@ -214,12 +239,12 @@ static int _pam_parse_conf_file(pam_handle_t *pamh, FILE *f
                argv = NULL;
            }
 
-#ifdef DEBUG
+#ifdef PAM_DEBUG
            {
                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 +260,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 +277,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 +289,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 +312,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 +411,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 +433,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 +452,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 +486,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 */
@@ -485,6 +517,7 @@ int _pam_init_handlers(pam_handle_t *pamh)
 static int _pam_assemble_line(FILE *f, char *buffer, int buf_len)
 {
     char *p = buffer;
+    char *endp = buffer + buf_len;
     char *s, *os;
     int used = 0;
 
@@ -492,12 +525,12 @@ static int _pam_assemble_line(FILE *f, char *buffer, int buf_len)
 
     D(("called."));
     for (;;) {
-       if (used >= buf_len) {
+       if (p >= endp) {
            /* Overflow */
            D(("_pam_assemble_line: overflow"));
            return -1;
        }
-       if (fgets(p, buf_len - used, f) == NULL) {
+       if (fgets(p, endp - p, f) == NULL) {
            if (used) {
                /* Incomplete read */
                return -1;
@@ -571,7 +604,7 @@ extract_modulename(const char *mod_path)
   else
     p++;
 
-  if ((retval = strdup (p)) == NULL)
+  if ((retval = _pam_strdup (p)) == NULL)
     return NULL;
 
   dot = strrchr (retval, '.');
@@ -581,46 +614,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, int handler_type)
 {
-    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);
+    D(("_pam_load_module: loading module `%s'", mod_path));
 
-    /* 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;
+    mod = pamh->handlers.module;
 
     /* First, ensure the module is loaded */
     while (x < pamh->handlers.modules_used) {
@@ -639,9 +645,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,12 +659,13 @@ 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));
-           mod->dl_handle = _pam_open_static_handler(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,
+               if (handler_type != PAM_HT_SILENT_MODULE)
+                   pam_syslog(pamh, LOG_ERR,
                                "unable to open static handler %s", mod_path);
                /* Didn't find module in dynamic or static..will mark bad */
            } else {
@@ -670,15 +676,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 +700,10 @@ 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));
+           if (handler_type != PAM_HT_SILENT_MODULE)
+               pam_syslog(pamh, LOG_ERR, "unable to dlopen(%s): %s", mod_path,
+                   _pam_dlerror());
            /* Don't abort yet; static code may be able to find function.
             * But defaults to abort if nothing found below... */
        } else {
@@ -711,13 +718,14 @@ int _pam_add_handler(pam_handle_t *pamh
            mod->dl_handle = NULL;
            mod->type = PAM_MT_FAULTY_MOD;
            pamh->handlers.modules_used++;
-           pam_syslog(pamh, LOG_ERR, "adding faulty module: %s", mod_path);
+           if (handler_type != PAM_HT_SILENT_MODULE)
+               pam_syslog(pamh, LOG_ERR, "adding faulty module: %s", mod_path);
            success = PAM_SUCCESS;  /* We have successfully added a module */
        }
 
        /* indicate its name - later we will search for it by this */
        if ((mod->name = _pam_strdup(mod_path)) == NULL) {
-           D(("_pam_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 +734,55 @@ 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);
+
+    D(("_pam_add_handler: adding type %d, handler_type %d, module `%s'",
+       type, handler_type, mod_path));
 
-    _pam_drop(mod_full_path);
-    mod_path = NULL;                        /* no longer needed or trusted */
+    if ((handler_type == PAM_HT_MODULE || handler_type == PAM_HT_SILENT_MODULE) &&
+       mod_path != NULL) {
+       if (mod_path[0] == '/') {
+           mod = _pam_load_module(pamh, mod_path, handler_type);
+       } else if (asprintf(&mod_full_path, "%s%s",
+                            DEFAULT_MODULE_PATH, mod_path) >= 0) {
+           mod = _pam_load_module(pamh, mod_full_path, handler_type);
+           _pam_drop(mod_full_path);
+       } else {
+           pam_syslog(pamh, LOG_CRIT, "cannot malloc full mod path");
+           return PAM_ABORT;
+       }
+
+       if (mod == NULL) {
+           /* if we get here with NULL it means allocation error */
+           return PAM_ABORT;
+       }
+
+       mod_type = mod->type;
+    }
 
-    /* Now return error if necessary after trying all possible ways... */
-    if (success != PAM_SUCCESS)
-       return(success);
+    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 +825,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 +880,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 +903,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 +920,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;
     }