d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina/*
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina Authors:
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina Pavel Březina <pbrezina@redhat.com>
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina Copyright (C) 2016 Red Hat
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina This program is free software; you can redistribute it and/or modify
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina it under the terms of the GNU General Public License as published by
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina the Free Software Foundation; either version 3 of the License, or
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina (at your option) any later version.
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina This program is distributed in the hope that it will be useful,
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina but WITHOUT ANY WARRANTY; without even the implied warranty of
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina GNU General Public License for more details.
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina You should have received a copy of the GNU General Public License
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina along with this program. If not, see <http://www.gnu.org/licenses/>.
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina*/
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina#include <dlfcn.h>
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina#include "config.h"
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina#include "providers/data_provider/dp.h"
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina#include "providers/data_provider/dp_private.h"
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina#include "providers/backend.h"
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina#include "util/util.h"
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina/* There can be at most the same number of different modules loaded at
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina * one time as the maximum number of defined targets. */
#define DP_MAX_MODULES DP_TARGET_SENTINEL
#define DP_MODULE_PATH DATA_PROVIDER_PLUGINS_PATH "/libsss_%s.so"
#define DP_MODULE_INIT_FN "sssm_%s_init"
static errno_t dp_module_open_lib(struct dp_module *module)
{
char *libpath = NULL;
errno_t ret;
libpath = talloc_asprintf(module, DP_MODULE_PATH, module->name);
if (libpath == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n");
return ENOMEM;
}
DEBUG(SSSDBG_TRACE_LIBS, "Loading module [%s] with path [%s]\n",
module->name, libpath);
module->libhandle = dlopen(libpath, RTLD_NOW);
if (module->libhandle == NULL) {
DEBUG(SSSDBG_FATAL_FAILURE, "Unable to load module [%s] with path "
"[%s]: %s\n", module->name, libpath, dlerror());
ret = ELIBACC;
goto done;
}
ret = EOK;
done:
talloc_free(libpath);
return ret;
}
static errno_t dp_module_run_constructor(struct dp_module *module,
struct be_ctx *be_ctx,
struct data_provider *provider)
{
char *fn_name;
dp_module_init_fn fn;
errno_t ret;
fn_name = talloc_asprintf(module, DP_MODULE_INIT_FN, module->name);
if (fn_name == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n");
return ENOMEM;
}
fn = (dp_module_init_fn)dlsym(module->libhandle, fn_name);
if (fn != NULL) {
DEBUG(SSSDBG_TRACE_FUNC, "Executing module [%s] constructor.\n",
module->name);
ret = fn(module, be_ctx, provider, module->name, &module->module_data);
if (ret != EOK) {
DEBUG(SSSDBG_FATAL_FAILURE, "Module [%s] constructor failed "
"[%d]: %s\n", module->name, ret, sss_strerror(ret));
goto done;
}
} else {
DEBUG(SSSDBG_TRACE_FUNC, "No constructor found for module [%s].\n",
module->name);
module->module_data = NULL;
ret = EOK;
goto done;
}
ret = EOK;
done:
talloc_free(fn_name);
return ret;
}
static errno_t dp_module_find(struct dp_module **modules,
const char *name,
struct dp_module **_module,
unsigned int *_slot)
{
unsigned int slot;
for (slot = 0; modules[slot] != NULL; slot++) {
if (strcmp(modules[slot]->name, name) == 0) {
*_module = modules[slot];
*_slot = slot;
return EOK;
}
}
if (slot == DP_MAX_MODULES) {
/* This should not happen. */
DEBUG(SSSDBG_CRIT_FAILURE, "All module slots are taken.\n");
return ERR_INTERNAL;
}
*_module = NULL;
*_slot = slot;
return EOK;
}
static struct dp_module *dp_module_create(TALLOC_CTX *mem_ctx,
struct be_ctx *be_ctx,
struct data_provider *provider,
const char *name)
{
struct dp_module *module;
errno_t ret;
module = talloc_zero(mem_ctx, struct dp_module);
if (module == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero() failed\n");
ret = ENOMEM;
goto done;
}
module->name = talloc_strdup(module, name);
if (module->name == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n");
ret = ENOMEM;
goto done;
}
ret = dp_module_open_lib(module);
if (ret != EOK) {
goto done;
}
ret = dp_module_run_constructor(module, be_ctx, provider);
if (ret != EOK) {
goto done;
}
module->initialized = true;
ret = EOK;
done:
if (ret != EOK) {
talloc_free(module);
return NULL;
}
return module;
}
struct dp_module *dp_load_module(TALLOC_CTX *mem_ctx,
struct be_ctx *be_ctx,
struct data_provider *provider,
struct dp_module **modules,
const char *name)
{
struct dp_module *module;
unsigned int free_slot;
errno_t ret;
ret = dp_module_find(modules, name, &module, &free_slot);
if (ret != EOK) {
return NULL;
}
if (module != NULL) {
DEBUG(SSSDBG_TRACE_FUNC, "Module [%s] is already loaded.\n", name);
return module;
}
DEBUG(SSSDBG_TRACE_FUNC, "About to load module [%s].\n", name);
module = dp_module_create(mem_ctx, be_ctx, provider, name);
if (module == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create DP module.\n");
return NULL;
}
modules[free_slot] = module;
return module;
}
errno_t dp_init_modules(TALLOC_CTX *mem_ctx, struct dp_module ***_modules)
{
struct dp_module **modules;
modules = talloc_zero_array(mem_ctx, struct dp_module *,
DP_MAX_MODULES + 1);
if (modules == NULL) {
return ENOMEM;
}
*_modules = modules;
return EOK;
}