From 567ecaa2af28fa003932517fb59ce4295bcfdba8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dag-Erling=20Sm=C3=B8rgrav?= Date: Mon, 11 Mar 2013 16:33:27 +0000 Subject: [PATCH] Clean up the dynamic module loading code, and add support for the module path which was added in r695. git-svn-id: svn+ssh://svn.openpam.org/svn/openpam/trunk@662 185d5e19-27fe-0310-9dcf-9bff6b9f3609 --- lib/libpam/openpam_dynamic.c | 130 +++++++++++++++++++++++------------ 1 file changed, 85 insertions(+), 45 deletions(-) diff --git a/lib/libpam/openpam_dynamic.c b/lib/libpam/openpam_dynamic.c index a323270..09f0a77 100644 --- a/lib/libpam/openpam_dynamic.c +++ b/lib/libpam/openpam_dynamic.c @@ -39,9 +39,11 @@ # include "config.h" #endif +#include + #include -#include #include +#include #include #include #include @@ -70,6 +72,7 @@ try_dlopen(const char *modfn) void *dlh; int fd; + openpam_log(PAM_LOG_LIBDEBUG, "dlopen(%s)", modfn); if ((fd = open(modfn, O_RDONLY)) < 0) return (NULL); if (OPENPAM_FEATURE(VERIFY_MODULE_FILE) && @@ -93,6 +96,7 @@ try_dlopen(const char *modfn) int check_module_file; void *dlh; + openpam_log(PAM_LOG_LIBDEBUG, "dlopen(%s)", modfn); openpam_get_feature(OPENPAM_VERIFY_MODULE_FILE, &check_module_file); if (check_module_file && @@ -108,50 +112,26 @@ try_dlopen(const char *modfn) #endif /* - * OpenPAM internal - * - * Locate a dynamically linked module + * Try to load a module from the suggested location. */ - -pam_module_t * -openpam_dynamic(const char *path) +static pam_module_t * +try_module(const char *modpath) { const pam_module_t *dlmodule; pam_module_t *module; - const char *prefix; - char *vpath; - void *dlh; int i, serrno; - dlh = NULL; - - /* Prepend the standard prefix if not an absolute pathname. */ - if (path[0] != '/') - prefix = OPENPAM_MODULES_DIR; - else - prefix = ""; - - /* try versioned module first, then unversioned module */ - if (asprintf(&vpath, "%s%s.%d", prefix, path, LIB_MAJ) < 0) + if ((module = calloc(1, sizeof *module)) == NULL || + (module->path = strdup(modpath)) == NULL || + (module->dlh = try_dlopen(modpath)) == NULL) goto err; - if ((dlh = try_dlopen(vpath)) == NULL && errno == ENOENT) { - *strrchr(vpath, '.') = '\0'; - dlh = try_dlopen(vpath); - } - if (dlh == NULL) - goto err; - if ((module = calloc(1, sizeof *module)) == NULL) - goto buf_err; - if ((module->path = strdup(path)) == NULL) - goto buf_err; - module->dlh = dlh; - dlmodule = dlsym(dlh, "_pam_module"); + dlmodule = dlsym(module->dlh, "_pam_module"); for (i = 0; i < PAM_NUM_PRIMITIVES; ++i) { if (dlmodule) { module->func[i] = dlmodule->func[i]; } else { - module->func[i] = - (pam_func_t)dlfunc(dlh, pam_sm_func_name[i]); + module->func[i] = (pam_func_t)dlfunc(module->dlh, + pam_sm_func_name[i]); /* * This openpam_log() call is a major source of * log spam, and the cases that matter are caught @@ -164,24 +144,84 @@ openpam_dynamic(const char *path) #if 0 if (module->func[i] == NULL) openpam_log(PAM_LOG_LIBDEBUG, "%s: %s(): %s", - path, pam_sm_func_name[i], dlerror()); + modpath, pam_sm_func_name[i], dlerror()); #endif } } - FREE(vpath); return (module); -buf_err: - serrno = errno; - if (dlh != NULL) - dlclose(dlh); - FREE(module); - errno = serrno; err: serrno = errno; - if (errno != 0) - openpam_log(PAM_LOG_ERROR, "%s: %m", vpath); - FREE(vpath); + if (module != NULL) { + if (module->dlh != NULL) + dlclose(module->dlh); + if (module->path != NULL) + FREE(module->path); + FREE(module); + } errno = serrno; + if (serrno != 0 && serrno != ENOENT) + openpam_log(PAM_LOG_ERROR, "%s: %m", modpath); + errno = serrno; + return (NULL); +} + +/* + * OpenPAM internal + * + * Locate a dynamically linked module + */ + +pam_module_t * +openpam_dynamic(const char *modname) +{ + pam_module_t *module; + char modpath[PATH_MAX]; + const char **path; + int dot, len; + + /* + * Simple case: module name contains path separator(s) + */ + if (strchr(modname, '/') != NULL) { + /* + * Absolute paths are not allowed if RESTRICT_MODULE_NAME + * is in effect. Relative paths are never allowed. + */ + if (OPENPAM_FEATURE(RESTRICT_MODULE_NAME) || + modname[0] != '/') { + openpam_log(PAM_LOG_ERROR, + "invalid module name: %s", modname); + return (NULL); + } + return (try_module(modname)); + } + + /* + * Complicated case: search for the module in the usual places. + */ + for (path = openpam_module_path; *path != NULL; ++path) { + /* + * Assemble the full path, including the version suffix. Take + * note of where the suffix begins so we can cut it off later. + */ + len = snprintf(modpath, sizeof modpath, "%s/%s%n.%d", + *path, modname, &dot, LIB_MAJ); + if (len < 0 || (unsigned int)len >= sizeof modpath) { + errno = ENOENT; + continue; + } + /* try the versioned path */ + if ((module = try_module(modpath)) != NULL) + return (module); + if (errno == ENOENT) { + /* no luck, try the unversioned path */ + modpath[dot] = '\0'; + if ((module = try_module(modpath)) != NULL) + return (module); + } + } + + /* :( */ return (NULL); }