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
This commit is contained in:
Dag-Erling Smørgrav 2013-03-11 16:33:27 +00:00
parent 2b8f7a6154
commit 567ecaa2af
1 changed files with 85 additions and 45 deletions

View File

@ -39,9 +39,11 @@
# include "config.h"
#endif
#include <sys/param.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -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);
}