summaryrefslogtreecommitdiffstats
path: root/src/providers/data_provider/dp_modules.c
diff options
context:
space:
mode:
authorPavel Březina <pbrezina@redhat.com>2016-01-15 13:00:45 +0100
committerJakub Hrozek <jhrozek@redhat.com>2016-06-20 14:48:47 +0200
commitd3dee2a07f1a8ee9ae6f94e149ced754ef76c248 (patch)
treedcb92cf97dd70a4183d05258b9db0414b91d60a8 /src/providers/data_provider/dp_modules.c
parent565b9955cc439ade58cc24a98168060a60f33e7a (diff)
downloadsssd-d3dee2a07f1a8ee9ae6f94e149ced754ef76c248.tar.gz
sssd-d3dee2a07f1a8ee9ae6f94e149ced754ef76c248.tar.xz
sssd-d3dee2a07f1a8ee9ae6f94e149ced754ef76c248.zip
DP: Introduce new interface for backend
Terminology: * Backend: Implemenation of domain * Data Provider: interface between backend and responders * Module: ldap/ipa/ad/... dlopened library that implements dp interface * Target: id/autofs/sudo/... functionality of module Benefits over current code: * data provider is a black box completely separated from backend * method handlers are just simple tevent requests on backend side * no need of spy on be_client * simplified and error proof adding of new responders * simplified adding of new methods * reply to D-Bus message is completely handled by DP code * each target can have several methods defined * properties can be added on objects * each method can have output parameters * modules now support constructor * improved debugging * clear memory hierarchy * ability to chain requests * type safe private data Reviewed-by: Sumit Bose <sbose@redhat.com> Reviewed-by: Jakub Hrozek <jhrozek@redhat.com> Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
Diffstat (limited to 'src/providers/data_provider/dp_modules.c')
-rw-r--r--src/providers/data_provider/dp_modules.c224
1 files changed, 224 insertions, 0 deletions
diff --git a/src/providers/data_provider/dp_modules.c b/src/providers/data_provider/dp_modules.c
new file mode 100644
index 000000000..2e6e33ddb
--- /dev/null
+++ b/src/providers/data_provider/dp_modules.c
@@ -0,0 +1,224 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <dlfcn.h>
+#include "config.h"
+#include "providers/data_provider/dp.h"
+#include "providers/data_provider/dp_private.h"
+#include "providers/backend.h"
+#include "util/util.h"
+
+/* There can be at most the same number of different modules loaded at
+ * 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;
+}