From ef946eebf0520607c1c7c72c80b51de63d9d941e Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 19 Nov 2008 14:20:15 -0500 Subject: Add some infrastructure code to add data providers. This currently breacks the dameon because of a problem with destroying the monitor dbus server in the children after fork() --- server/monitor.c | 19 +- server/providers/data_provider.c | 414 +++++++++++++++++++++++++++++++++++++++ server/providers/data_provider.h | 73 +++++++ server/providers/providers.h | 22 +++ server/sbus_interfaces.h | 6 + server/server.c | 2 + server/server.mk | 3 +- 7 files changed, 529 insertions(+), 10 deletions(-) create mode 100644 server/providers/data_provider.c create mode 100644 server/providers/data_provider.h create mode 100644 server/providers/providers.h diff --git a/server/monitor.c b/server/monitor.c index b85b7d60d..40f25c339 100644 --- a/server/monitor.c +++ b/server/monitor.c @@ -300,6 +300,14 @@ int start_monitor(TALLOC_CTX *mem_ctx, if (ret != EOK) return ret; + /* Initialize D-BUS Server + * The monitor will act as a D-BUS server for all + * SSSD processes */ + ret = monitor_dbus_init(ctx); + if (ret != EOK) { + return ret; + } + for (i = 0; ctx->services[i]; i++) { svc = talloc_zero(ctx, struct mt_svc); @@ -322,14 +330,6 @@ int start_monitor(TALLOC_CTX *mem_ctx, set_tasks_checker(svc); } - /* Initialize D-BUS Server - * The monitor will act as a D-BUS server for all - * SSSD processes */ - ret = monitor_dbus_init(ctx); - if (ret != EOK) { - return ret; - } - return EOK; } @@ -355,7 +355,8 @@ static int mt_conn_destructor(void *ptr) * method on the new client). The reply callback for this request * should set the connection destructor appropriately. */ -static int dbus_service_init(struct sbus_conn_ctx *conn_ctx, void *data) { +static int dbus_service_init(struct sbus_conn_ctx *conn_ctx, void *data) +{ struct mt_ctx *ctx; struct mt_svc *svc; struct mt_conn *mt_conn; diff --git a/server/providers/data_provider.c b/server/providers/data_provider.c new file mode 100644 index 000000000..43c80128d --- /dev/null +++ b/server/providers/data_provider.c @@ -0,0 +1,414 @@ +/* + SSSD + + Data Provider + + Copyright (C) Simo Sorce 2008 + + 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 . +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ldb.h" +#include "ldb_errors.h" +#include "util/util.h" +#include "service.h" +#include "confdb/confdb.h" +#include "dbus/dbus.h" +#include "sbus/sssd_dbus.h" +#include "sbus_interfaces.h" +#include "util/btreemap.h" +#include "data_provider.h" + +static int provide_identity(DBusMessage *message, void *data, DBusMessage **r); +static int reply_ping(DBusMessage *message, void *data, DBusMessage **r); + +struct sbus_method mon_sbus_methods[] = { + {SERVICE_METHOD_IDENTITY, provide_identity}, + {SERVICE_METHOD_PING, reply_ping}, + {NULL, NULL} +}; + +static int provide_identity(DBusMessage *message, void *data, DBusMessage **r) +{ + dbus_uint16_t version = DATA_PROVIDER_VERSION; + const char *name = DATA_PROVIDER_SERVICE_NAME; + DBusMessage *reply; + dbus_bool_t ret; + + reply = dbus_message_new_method_return(message); + ret = dbus_message_append_args(reply, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_UINT16, &version, + DBUS_TYPE_INVALID); + if (!ret) { + return EIO; + } + + *r = reply; + return EOK; +} + +static int reply_ping(DBusMessage *message, void *data, DBusMessage **r) +{ + DBusMessage *reply; + dbus_bool_t ret; + + reply = dbus_message_new_method_return(message); + ret = dbus_message_append_args(reply, DBUS_TYPE_INVALID); + if (!ret) { + return EIO; + } + + *r = reply; + return EOK; +} + +static int dp_monitor_init(struct dp_ctx *dpctx) +{ + struct sbus_method_ctx *cli_sm_ctx; + struct sbus_method_ctx *srv_sm_ctx; + struct dp_sbus_ctx *sbus_ctx; + DBusConnection *dbus_conn; + char *sbus_address; + int ret; + + ret = confdb_get_string(dpctx->cdb, dpctx, + "config/services/monitor", "sbusAddress", + DEFAULT_SBUS_ADDRESS, &sbus_address); + if (ret != EOK) { + return ret; + } + + sbus_ctx = talloc(dpctx, struct dp_sbus_ctx); + if (!sbus_ctx) { + return ENOMEM; + } + sbus_ctx->ev = dpctx->ev; + + ret = sbus_new_connection(sbus_ctx, sbus_ctx->ev, + sbus_address, + &sbus_ctx->scon_ctx, NULL); + if (ret != EOK) { + talloc_free(sbus_ctx); + return ret; + } + dbus_conn = sbus_get_connection(sbus_ctx->scon_ctx); + dbus_connection_set_exit_on_disconnect(dbus_conn, TRUE); + + /* set up handler for service methods */ + srv_sm_ctx = talloc_zero(sbus_ctx, struct sbus_method_ctx); + if (!srv_sm_ctx) { + talloc_free(sbus_ctx); + return ENOMEM; + } + srv_sm_ctx->interface = talloc_strdup(srv_sm_ctx, SERVICE_INTERFACE); + srv_sm_ctx->path = talloc_strdup(srv_sm_ctx, SERVICE_PATH); + if (!srv_sm_ctx->interface || !srv_sm_ctx->path) { + talloc_free(sbus_ctx); + return ENOMEM; + } + srv_sm_ctx->methods = mon_sbus_methods; + sbus_conn_add_method_ctx(sbus_ctx->scon_ctx, srv_sm_ctx); + + /* set up client stuff */ + cli_sm_ctx = talloc(sbus_ctx, struct sbus_method_ctx); + if (!cli_sm_ctx) { + talloc_free(sbus_ctx); + return ENOMEM; + } + cli_sm_ctx->interface = talloc_strdup(cli_sm_ctx, MONITOR_DBUS_INTERFACE); + cli_sm_ctx->path = talloc_strdup(cli_sm_ctx, MONITOR_DBUS_PATH); + if (!cli_sm_ctx->interface || !cli_sm_ctx->path) { + talloc_free(sbus_ctx); + return ENOMEM; + } + sbus_ctx->sm_ctx = cli_sm_ctx; + + dpctx->sbus_ctx = sbus_ctx; + + return EOK; +} + +static int dp_db_init(struct dp_ctx *dpctx) +{ + char *ldb_file; + int ret; + + ret = confdb_get_string(dpctx->cdb, dpctx, + DATA_PROVIDER_DB_CONF_SEC, "ldbFile", + DATA_PROVIDER_DEF_DB_FILE, &ldb_file); + if (ret != EOK) { + return ret; + } + + dpctx->ldb = ldb_init(dpctx, dpctx->ev); + if (!dpctx->ldb) { + return EIO; + } + + ret = ldb_connect(dpctx->ldb, ldb_file, 0, NULL); + if (ret != LDB_SUCCESS) { + talloc_free(dpctx->ldb); + return EIO; + } + + return EOK; +} + +static int check_online(DBusMessage *message, void *data, DBusMessage **r); + +struct sbus_method dp_sbus_methods[] = { + { DP_METHOD_CHECK_ONLINE, check_online }, + { NULL, NULL } +}; + +static int dbus_dp_init(struct sbus_conn_ctx *conn_ctx, void *data) +{ + struct dp_ctx *dpctx; + struct dp_client *dpcli; + DBusConnection *conn; + DBusError dbus_error; + + dpctx = talloc_get_type(data, struct dp_ctx); + conn = sbus_get_connection(conn_ctx); + dbus_error_init(&dbus_error); + + /* hang off this memory to the connection so that when the connection + * is freed we can potentially call a destructor */ + + dpcli = talloc(conn_ctx, struct dp_client); + if (!dpcli) { + DEBUG(0,("Out of memory?!\n")); + talloc_free(conn_ctx); + return ENOMEM; + } + dpcli->dpctx = dpctx; + dpcli->conn = conn; + + /* Attach the client context to the connection context, so that it is + * always available when we need to manage the connection. */ + sbus_conn_set_private_data(conn_ctx, dpcli); + + return EOK; +} + +/* monitor_dbus_init + * Set up the monitor service as a D-BUS Server */ +static int dp_srv_init(struct dp_ctx *dpctx) +{ + struct sbus_method_ctx *sd_ctx; + char *dpbus_address; + int ret; + + DEBUG(3, ("Initializing Data Provider D-BUS Server\n")); + + ret = confdb_get_string(dpctx->cdb, dpctx, + "config/services/dataprovider", "dpbusAddress", + DATA_PROVIDER_ADDRESS, &dpbus_address); + if (ret != EOK) { + return ret; + } + + sd_ctx = talloc_zero(dpctx, struct sbus_method_ctx); + if (!sd_ctx) { + talloc_free(dpbus_address); + return ENOMEM; + } + + /* Set up globally-available D-BUS methods */ + sd_ctx->interface = talloc_strdup(sd_ctx, DATA_PROVIDER_DBUS_INTERFACE); + if (!sd_ctx->interface) { + talloc_free(dpbus_address); + talloc_free(sd_ctx); + return ENOMEM; + } + sd_ctx->path = talloc_strdup(sd_ctx, DATA_PROVIDER_DBUS_PATH); + if (!sd_ctx->path) { + talloc_free(dpbus_address); + talloc_free(sd_ctx); + return ENOMEM; + } + sd_ctx->methods = dp_sbus_methods; + sd_ctx->message_handler = sbus_message_handler; + + ret = sbus_new_server(dpctx->ev, sd_ctx, dpbus_address, + dbus_dp_init, dpctx); + + return ret; +} + +static int check_online(DBusMessage *message, void *data, DBusMessage **r) +{ + return EOK; +} + +/* find list of backends */ +/* find library implementing them */ +/* dload() said library and set up a structure to hold pointers */ + +static int init_data_providers(struct dp_ctx *dpctx) +{ + TALLOC_CTX *tmp_ctx; + struct dp_module *module; + char **doms; + char *sec; + char *mod_name; + char *path; + void *handle; + char *mod_init_fn_name; + sssm_init_fn_t mod_init_fn; + int num_mods; + int i, ret; + + tmp_ctx = talloc_new(dpctx); + if (!tmp_ctx) { + return ENOMEM; + } + + ret = confdb_get_domains(dpctx->cdb, tmp_ctx, &doms); + if (ret != EOK) { + DEBUG(2, ("No domains configured!\n")); + return ret; + } + + num_mods = 0; + for (i = 0; doms[i]; i++) { + sec = talloc_asprintf(tmp_ctx, "config/domains/%s", doms[i]); + if (!sec) { + ret = ENOMEM; + goto done; + } + ret = confdb_get_string(dpctx->cdb, tmp_ctx, sec, + "provider", NULL, &mod_name); + if (ret != EOK) { + goto done; + } + + /* the LOCAL domain does not have a backend at the moment */ + if (strcasecmp(mod_name, "LOCAL") == 0) { + continue; + } + + path = talloc_asprintf(tmp_ctx, "%s/libsss_%s.so", + DATA_PROVIDER_PLUGINS_PATH, mod_name); + + handle = dlopen(path, RTLD_NOW); + if (!handle) { + DEBUG(0, ("Unable to load %s module with path (%s), error: %s\n", + mod_name, path, dlerror())); + ret = ELIBACC; + goto done; + } + + mod_init_fn_name = talloc_asprintf(tmp_ctx, "sssm_%s_init", mod_name); + if (!mod_init_fn_name) { + ret = ENOMEM; + goto done; + } + + mod_init_fn = (sssm_init_fn_t)dlsym(handle, mod_init_fn_name); + if (!mod_init_fn) { + DEBUG(0, ("Unable to load init fn from module %s, error: %s\n", + mod_name, dlerror())); + ret = ELIBBAD; + goto done; + } + + dpctx->modules = talloc_array(tmp_ctx, struct dp_module *, num_mods +1); + if (!dpctx->modules) { + ret = ENOMEM; + goto done; + } + module = talloc(dpctx->modules, struct dp_module); + if (!module) { + ret = ENOMEM; + goto done; + } + dpctx->modules[num_mods] = module; + + module->domain = talloc_strdup(dpctx->modules, doms[i]); + module->name = talloc_steal(dpctx->modules, mod_name); + + ret = mod_init_fn(module, &module->ops, &module->pvt_data); + if (ret != EOK) { + DEBUG(0, ("Error (%d) in module (%s) initialization!\n", + ret, mod_name)); + continue; + } + + num_mods++; + } + + ret = EOK; + +done: + talloc_free(doms); + return ret; +} + +void dp_task_init(struct task_server *task) +{ + struct dp_ctx *dpctx; + int ret; + + task_server_set_title(task, "sssd[datap]"); + + dpctx = talloc_zero(task, struct dp_ctx); + if (!dpctx) { + task_server_terminate(task, "fatal error initializing dp_ctx\n"); + return; + } + dpctx->ev = task->event_ctx; + dpctx->task = task; + + ret = confdb_init(task, task->event_ctx, &dpctx->cdb); + if (ret != EOK) { + task_server_terminate(task, "fatal error initializing confdb\n"); + return; + } + + ret = dp_db_init(dpctx); + if (ret != EOK) { + task_server_terminate(task, "fatal error opening database\n"); + return; + } + + ret = dp_monitor_init(dpctx); + if (ret != EOK) { + task_server_terminate(task, "fatal error setting up monitor bus\n"); + return; + } + + ret = dp_srv_init(dpctx); + if (ret != EOK) { + task_server_terminate(task, "fatal error setting up server bus\n"); + return; + } + + ret = init_data_providers(dpctx); + if (ret != EOK) { + task_server_terminate(task, "fatal error initializing data providers\n"); + return; + } +} diff --git a/server/providers/data_provider.h b/server/providers/data_provider.h new file mode 100644 index 000000000..a5c0a4177 --- /dev/null +++ b/server/providers/data_provider.h @@ -0,0 +1,73 @@ +/* + SSSD + + Data Provider, private header file + + Copyright (C) Simo Sorce 2008 + + 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 . +*/ + +#ifndef __DATA_PROVIDER_H__ +#define __DATA_PROVIDER_H__ + +#include +#include +#include "talloc.h" +#include "events.h" +#include "ldb.h" + +#define DATA_PROVIDER_VERSION 0x0001 +#define DATA_PROVIDER_SERVICE_NAME "data-provider" +#define DATA_PROVIDER_ADDRESS "unix:path=/var/lib/sss/pipes/private/dbus-dp" + +#define DATA_PROVIDER_DEF_DB_FILE "/var/lib/sss/db/sssd.ldb" +#define DATA_PROVIDER_DB_CONF_SEC "config/services/nss" + +#define DATA_PROVIDER_PLUGINS_PATH "/usr/lib/sssd" + +struct dp_mod_ops { + int (*check_online)(void *pvt_data, int *reply); +}; + +typedef int (*sssm_init_fn_t)(TALLOC_CTX *, struct dp_mod_ops **, void **); + +struct dp_module { + const char *name; + const char *domain; + struct dp_mod_ops *ops; + void *pvt_data; +}; + +struct dp_sbus_ctx { + struct event_context *ev; + struct sbus_method_ctx *sm_ctx; + struct sbus_conn_ctx *scon_ctx; +}; + +struct dp_ctx { + struct event_context *ev; + struct task_server *task; + struct confdb_ctx *cdb; + struct ldb_context *ldb; + struct dp_sbus_ctx *sbus_ctx; + struct dp_module **modules; +}; + +struct dp_client { + struct dp_ctx *dpctx; + DBusConnection *conn; +}; + +#endif /* __DATA_PROVIDER_ */ diff --git a/server/providers/providers.h b/server/providers/providers.h new file mode 100644 index 000000000..a1cc1fc42 --- /dev/null +++ b/server/providers/providers.h @@ -0,0 +1,22 @@ +/* + SSSD + + Data Provider, public header file + + Copyright (C) Simo Sorce 2008 + + 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 . +*/ + +void dp_task_init(struct task_server *task); diff --git a/server/sbus_interfaces.h b/server/sbus_interfaces.h index 2e6372de4..b07023093 100644 --- a/server/sbus_interfaces.h +++ b/server/sbus_interfaces.h @@ -40,3 +40,9 @@ #define DEFAULT_SBUS_ADDRESS "unix:path=/var/lib/sss/pipes/private/dbus" +/* Data Provider */ + +#define DATA_PROVIDER_DBUS_INTERFACE "org.freeipa.sssd.dataprovider" +#define DATA_PROVIDER_DBUS_PATH "/org/freeipa/sssd/dataprovider" + +#define DP_METHOD_CHECK_ONLINE "isOnline" diff --git a/server/server.c b/server/server.c index d95919970..01bcf29c3 100644 --- a/server/server.c +++ b/server/server.c @@ -33,6 +33,7 @@ #include "../ldb/include/ldb.h" #include "service.h" #include "confdb/confdb.h" +#include "providers/providers.h" #include "monitor.h" extern void monitor_task_init(struct task_server *task); @@ -214,6 +215,7 @@ int main(int argc, const char *argv[]) /* Services */ register_server_service("nss", nss_task_init); + register_server_service("dp", dp_task_init); /* the monitor starts the services */ status = start_monitor(mem_ctx, event_ctx, confdb_ctx); diff --git a/server/server.mk b/server/server.mk index 6277a5597..ee5f036a3 100644 --- a/server/server.mk +++ b/server/server.mk @@ -16,7 +16,8 @@ SERVER_OBJ = \ nss/nsssrv_ldb.o \ sbus/sssd_dbus_common.o \ sbus/sssd_dbus_connection.o \ - sbus/sssd_dbus_server.o + sbus/sssd_dbus_server.o \ + providers/data_provider.o CLIENT_OBJ = \ sbus/sssd_dbus_common.o \ -- cgit