From 8f86577722f9e880c82e7a98fcb14ee06acb7170 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mon, 8 Dec 2008 19:07:56 -0500 Subject: Change data provider into a hub, where backends (ldap, nis, ipa providers) and frontends (pam, nss, ... modules) can connect to. --- server/Makefile.in | 2 +- server/monitor.c | 54 ++++ server/nss/nsssrv.c | 15 +- server/providers/data_provider.c | 356 ++++++++++++++++--------- server/providers/data_provider.h | 33 +-- server/providers/data_provider_be.c | 515 ++++++++++++++++++++++++++++++++++++ server/server.mk | 6 + server/util/server.c | 5 +- server/util/service_helpers.c | 21 +- server/util/service_helpers.h | 3 +- 10 files changed, 824 insertions(+), 186 deletions(-) create mode 100644 server/providers/data_provider_be.c (limited to 'server') diff --git a/server/Makefile.in b/server/Makefile.in index 4c989eefa..fa57d8030 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -59,7 +59,7 @@ OBJS = $(SERVER_OBJ) @LIBREPLACEOBJ@ $(EXTRA_OBJ) headers = .h -BINS = sbin/sssd sbin/sssd_nss sbin/sssd_dp +BINS = sbin/sssd sbin/sssd_nss sbin/sssd_dp sbin/sssd_be DIRS = sbin diff --git a/server/monitor.c b/server/monitor.c index fab88ff90..0075aac74 100644 --- a/server/monitor.c +++ b/server/monitor.c @@ -304,6 +304,7 @@ int monitor_process_init(TALLOC_CTX *mem_ctx, { struct mt_ctx *ctx; struct mt_svc *svc; + char **doms; char *path; int ret, i; @@ -327,6 +328,7 @@ int monitor_process_init(TALLOC_CTX *mem_ctx, return ret; } + /* start all services */ for (i = 0; ctx->services[i]; i++) { svc = talloc_zero(ctx, struct mt_svc); @@ -363,6 +365,58 @@ int monitor_process_init(TALLOC_CTX *mem_ctx, set_tasks_checker(svc); } + /* now start the data providers */ + ret = confdb_get_domains(cdb, ctx, &doms); + if (ret != EOK) { + DEBUG(2, ("No domains configured. LOCAL should always exist!\n")); + return ret; + } + + for (i = 0; doms[i]; i++) { + svc = talloc_zero(ctx, struct mt_svc); + if (!svc) { + talloc_free(ctx); + return ENOMEM; + } + svc->name = talloc_strdup(svc, doms[i]); + svc->mt_ctx = ctx; + + path = talloc_asprintf(svc, "config/domains/%s", svc->name); + if (!path) { + talloc_free(ctx); + return ENOMEM; + } + ret = confdb_get_string(cdb, svc, path, + "command", NULL, &svc->command); + if (ret != EOK) { + DEBUG(0, ("Failed to find provider [%s] configuration\n", + svc->name)); + talloc_free(svc); + continue; + } + + /* if no command is present to not run the domain */ + if (svc->command == NULL) { + /* the LOCAL domain does not need a backend at the moment */ + if (strcasecmp(svc->name, "LOCAL") != 0) { + DEBUG(0, ("Missing command to run provider [%s]\n")); + } + talloc_free(svc); + continue; + } + + ret = start_service(svc->name, svc->command, &svc->pid); + if (ret != EOK) { + DEBUG(0,("Failed to start provider '%s'\n", svc->name)); + talloc_free(svc); + continue; + } + + DLIST_ADD(ctx->svc_list, svc); + + set_tasks_checker(svc); + } + return EOK; } diff --git a/server/nss/nsssrv.c b/server/nss/nsssrv.c index ccbd7ba80..a3fd67266 100644 --- a/server/nss/nsssrv.c +++ b/server/nss/nsssrv.c @@ -43,14 +43,14 @@ #define SSS_NSS_PIPE_NAME "nss" -static int provide_identity(DBusMessage *message, void *data, DBusMessage **r); -static int reply_ping(DBusMessage *message, void *data, DBusMessage **r); +static int service_identity(DBusMessage *message, void *data, DBusMessage **r); +static int service_pong(DBusMessage *message, void *data, DBusMessage **r); static int nss_init_domains(struct nss_ctx *nctx); static int _domain_comparator(void *key1, void *key2); struct sbus_method nss_sbus_methods[] = { - {SERVICE_METHOD_IDENTITY, provide_identity}, - {SERVICE_METHOD_PING, reply_ping}, + {SERVICE_METHOD_IDENTITY, service_identity}, + {SERVICE_METHOD_PING, service_pong}, {NULL, NULL} }; @@ -211,7 +211,7 @@ static void accept_fd_handler(struct event_context *ev, return; } -static int provide_identity(DBusMessage *message, void *data, DBusMessage **r) +static int service_identity(DBusMessage *message, void *data, DBusMessage **r) { dbus_uint16_t version = NSS_SBUS_SERVICE_VERSION; const char *name = NSS_SBUS_SERVICE_NAME; @@ -231,7 +231,7 @@ static int provide_identity(DBusMessage *message, void *data, DBusMessage **r) return EOK; } -static int reply_ping(DBusMessage *message, void *data, DBusMessage **r) +static int service_pong(DBusMessage *message, void *data, DBusMessage **r) { DBusMessage *reply; dbus_bool_t ret; @@ -252,8 +252,7 @@ static int nss_sbus_init(struct nss_ctx *nctx) /* Set up SBUS connection to the monitor */ ss_ctx = sssd_service_sbus_init(nctx, nctx->ev, nctx->cdb, - provide_identity, - reply_ping); + nss_sbus_methods); if (ss_ctx == NULL) { DEBUG(0, ("Could not initialize D-BUS.\n")); return ENOMEM; diff --git a/server/providers/data_provider.c b/server/providers/data_provider.c index bfc37a7c3..181e865ab 100644 --- a/server/providers/data_provider.c +++ b/server/providers/data_provider.c @@ -41,16 +41,57 @@ #include "data_provider.h" #include "util/service_helpers.h" -static int provide_identity(DBusMessage *message, void *data, DBusMessage **r); -static int reply_ping(DBusMessage *message, void *data, DBusMessage **r); +struct dp_backend; +struct dp_frontend; + +struct dp_ctx { + struct event_context *ev; + struct confdb_ctx *cdb; + struct ldb_context *ldb; + struct service_sbus_ctx *ss_ctx; + struct dp_backend *be_list; + struct dp_frontend *fe_list; +}; + +struct dp_client { + struct dp_ctx *dpctx; + struct sbus_conn_ctx *conn_ctx; + const char *domain; +}; + +struct dp_backend { + struct dp_backend *prev; + struct dp_backend *next; + char *name; + char *domain; + struct dp_client *dpcli; +}; + +struct dp_frontend { + struct dp_frontend *prev; + struct dp_frontend *next; + char *name; + uint16_t flags; + struct dp_client *dpcli; +}; + +static int dp_backend_destructor(void *ctx); +static int dp_frontend_destructor(void *ctx); + +static int service_identity(DBusMessage *message, void *data, DBusMessage **r); +static int service_pong(DBusMessage *message, void *data, DBusMessage **r); struct sbus_method mon_sbus_methods[] = { - {SERVICE_METHOD_IDENTITY, provide_identity}, - {SERVICE_METHOD_PING, reply_ping}, + {SERVICE_METHOD_IDENTITY, service_identity}, + {SERVICE_METHOD_PING, service_pong}, {NULL, NULL} }; -static int provide_identity(DBusMessage *message, void *data, DBusMessage **r) +struct sbus_method dp_sbus_methods[] = { + {NULL, NULL} +}; + +static int service_identity(DBusMessage *message, void *data, DBusMessage **r) { dbus_uint16_t version = DATA_PROVIDER_VERSION; const char *name = DATA_PROVIDER_SERVICE_NAME; @@ -70,7 +111,7 @@ static int provide_identity(DBusMessage *message, void *data, DBusMessage **r) return EOK; } -static int reply_ping(DBusMessage *message, void *data, DBusMessage **r) +static int service_pong(DBusMessage *message, void *data, DBusMessage **r) { DBusMessage *reply; dbus_bool_t ret; @@ -91,8 +132,7 @@ static int dp_monitor_init(struct dp_ctx *dpctx) /* Set up SBUS connection to the monitor */ ss_ctx = sssd_service_sbus_init(dpctx, dpctx->ev, dpctx->cdb, - provide_identity, - reply_ping); + mon_sbus_methods); if (ss_ctx == NULL) { DEBUG(0, ("Could not initialize D-BUS.\n")); return ENOMEM; @@ -150,19 +190,18 @@ static int dp_db_init(struct dp_ctx *dpctx) 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 void identity_check(DBusPendingCall *pending, void *data); +static void online_check(DBusPendingCall *pending, void *data); static int dbus_dp_init(struct sbus_conn_ctx *conn_ctx, void *data) { struct dp_ctx *dpctx; struct dp_client *dpcli; + DBusMessage *msg; + DBusPendingCall *pending_reply; DBusConnection *conn; DBusError dbus_error; + dbus_bool_t dbret; dpctx = talloc_get_type(data, struct dp_ctx); conn = sbus_get_connection(conn_ctx); @@ -178,15 +217,186 @@ static int dbus_dp_init(struct sbus_conn_ctx *conn_ctx, void *data) return ENOMEM; } dpcli->dpctx = dpctx; - dpcli->conn = conn; + dpcli->conn_ctx = conn_ctx; /* 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); + /* identify the connecting client */ + msg = dbus_message_new_method_call(NULL, + DP_CLI_PATH, + DP_CLI_INTERFACE, + DP_CLI_METHOD_IDENTITY); + if (msg == NULL) { + DEBUG(0,("Out of memory?!\n")); + talloc_free(conn_ctx); + return ENOMEM; + } + dbret = dbus_connection_send_with_reply(conn, msg, &pending_reply, + -1 /* TODO: set timeout */); + if (!dbret) { + /* + * Critical Failure + * We can't communicate on this connection + * We'll drop it using the default destructor. + */ + DEBUG(0, ("D-BUS send failed.\n")); + talloc_free(conn_ctx); + return EIO; + } + + /* Set up the reply handler */ + dbus_pending_call_set_notify(pending_reply, identity_check, dpcli, NULL); + dbus_message_unref(msg); + return EOK; } +static void identity_check(DBusPendingCall *pending, void *data) +{ + struct dp_backend *dpbe; + struct dp_frontend *dpfe; + struct dp_client *dpcli; + DBusMessage *reply; + DBusConnection *conn; + DBusError dbus_error; + dbus_uint16_t cli_ver; + dbus_uint16_t cli_type; + char *cli_name; + char *cli_domain; + dbus_bool_t ret; + int type; + + dpcli = talloc_get_type(data, struct dp_client); + conn = sbus_get_connection(dpcli->conn_ctx); + dbus_error_init(&dbus_error); + + reply = dbus_pending_call_steal_reply(pending); + if (!reply) { + /* reply should never be null. This function shouldn't be called + * until reply is valid or timeout has occurred. If reply is NULL + * here, something is seriously wrong and we should bail out. + */ + DEBUG(0, ("Serious error. A reply callback was called but no reply was received and no timeout occurred\n")); + + /* Destroy this connection */ + sbus_disconnect(dpcli->conn_ctx); + return; + } + + type = dbus_message_get_type(reply); + switch (type) { + case DBUS_MESSAGE_TYPE_METHOD_RETURN: + ret = dbus_message_get_args(reply, &dbus_error, + DBUS_TYPE_UINT16, &cli_type, + DBUS_TYPE_UINT16, &cli_ver, + DBUS_TYPE_STRING, &cli_name, + DBUS_TYPE_STRING, &cli_domain, + DBUS_TYPE_INVALID); + if (!ret) { + DEBUG(1,("Failed, to parse message, killing connection\n")); + sbus_disconnect(dpcli->conn_ctx); + return; + } + + switch (cli_type && DP_CLI_TYPE_MASK) { + case DP_CLI_BACKEND: + dpbe = talloc_zero(dpcli->dpctx, struct dp_backend); + if (!dpbe) { + DEBUG(0, ("Out of memory!\n")); + sbus_disconnect(dpcli->conn_ctx); + return; + } + + dpbe->name = talloc_strdup(dpbe, cli_name); + dpbe->domain = talloc_strdup(dpbe, cli_domain); + if (!dpbe->name || !dpbe->domain) { + DEBUG(0, ("Out of memory!\n")); + sbus_disconnect(dpcli->conn_ctx); + return; + } + + dpbe->dpcli = dpcli; + + DLIST_ADD(dpcli->dpctx->be_list, dpbe); + + talloc_set_destructor((TALLOC_CTX *)dpbe, dp_backend_destructor); + break; + + case DP_CLI_FRONTEND: + dpfe = talloc_zero(dpcli->dpctx, struct dp_frontend); + if (!dpfe) { + DEBUG(0, ("Out of memory!\n")); + sbus_disconnect(dpcli->conn_ctx); + return; + } + + dpfe->name = talloc_strdup(dpfe, cli_name); + if (!dpfe->name) { + DEBUG(0, ("Out of memory!\n")); + sbus_disconnect(dpcli->conn_ctx); + return; + } + + dpfe->dpcli = dpcli; + + DLIST_ADD(dpcli->dpctx->fe_list, dpfe); + + talloc_set_destructor((TALLOC_CTX *)dpfe, dp_frontend_destructor); + break; + + default: + DEBUG(1, ("Unknown client type, killing connection\n")); + sbus_disconnect(dpcli->conn_ctx); + return; + } + + /* Set up the destructor for this service */ + break; + + case DBUS_MESSAGE_TYPE_ERROR: + DEBUG(0,("getIdentity returned an error [%s], closing connection.\n", + dbus_message_get_error_name(reply))); + /* Falling through to default intentionally*/ + default: + /* + * Timeout or other error occurred or something + * unexpected happened. + * It doesn't matter which, because either way we + * know that this connection isn't trustworthy. + * We'll destroy it now. + */ + sbus_disconnect(dpcli->conn_ctx); + return; + } +} + +static void online_check(DBusPendingCall *pending, void *data) +{ + return; +} + +static int dp_backend_destructor(void *ctx) +{ + struct dp_backend *dpbe = talloc_get_type(ctx, struct dp_backend); + if (dpbe->dpcli && dpbe->dpcli && + dpbe->dpcli->dpctx && dpbe->dpcli->dpctx->be_list) { + DLIST_REMOVE(dpbe->dpcli->dpctx->be_list, dpbe); + } + return 0; +} + +static int dp_frontend_destructor(void *ctx) +{ + struct dp_frontend *dpfe = talloc_get_type(ctx, struct dp_frontend); + if (dpfe->dpcli && dpfe->dpcli && + dpfe->dpcli->dpctx && dpfe->dpcli->dpctx->fe_list) { + DLIST_REMOVE(dpfe->dpcli->dpctx->fe_list, dpfe); + } + return 0; +} + /* monitor_dbus_init * Set up the monitor service as a D-BUS Server */ static int dp_srv_init(struct dp_ctx *dpctx) @@ -247,116 +457,6 @@ done: 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_mod_ctx *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_mod_ctx *, num_mods +1); - if (!dpctx->modules) { - ret = ENOMEM; - goto done; - } - module = talloc(dpctx->modules, struct dp_mod_ctx); - if (!module) { - ret = ENOMEM; - goto done; - } - dpctx->modules[num_mods] = module; - - module->dp_ctx = dpctx; - module->domain = talloc_strdup(dpctx->modules, doms[i]); - module->name = talloc_steal(dpctx->modules, mod_name); - - ret = mod_init_fn(module); - 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; -} - int dp_process_init(TALLOC_CTX *mem_ctx, struct event_context *ev, struct confdb_ctx *cdb) @@ -390,12 +490,6 @@ int dp_process_init(TALLOC_CTX *mem_ctx, return ret; } - ret = init_data_providers(dpctx); - if (ret != EOK) { - DEBUG(0, ("fatal error initializing data providers\n")); - return ret; - } - return EOK; } diff --git a/server/providers/data_provider.h b/server/providers/data_provider.h index 68c6db976..cd8098ba0 100644 --- a/server/providers/data_provider.h +++ b/server/providers/data_provider.h @@ -29,41 +29,24 @@ #include "ldb.h" #define DATA_PROVIDER_VERSION 0x0001 +#define BE_VERSION 0x0001 #define DATA_PROVIDER_SERVICE_NAME "dp" #define DATA_PROVIDER_PIPE "private/sbus-dp" #define DATA_PROVIDER_DB_FILE "sssd.ldb" #define DATA_PROVIDER_DB_CONF_SEC "config/services/nss" -struct dp_mod_ops { - int (*check_online)(void *pvt_data, int *reply); -}; - #define MOD_OFFLINE 0x0000 #define MOD_ONLINE 0x0001 -struct dp_mod_ctx; -typedef int (*sssm_init_fn_t)(struct dp_mod_ctx *); - -struct dp_mod_ctx { - struct dp_ctx *dp_ctx; - const char *name; - const char *domain; - struct dp_mod_ops *ops; - void *pvt_data; -}; +#define DP_CLI_INTERFACE "org.freeipa.sssd.dataprovider" +#define DP_CLI_PATH "/org/freeipa/sssd/dataprovider" -struct dp_ctx { - struct event_context *ev; - struct confdb_ctx *cdb; - struct ldb_context *ldb; - struct service_sbus_ctx *ss_ctx; - struct dp_mod_ctx **modules; -}; +#define DP_CLI_BACKEND 0x0001 +#define DP_CLI_FRONTEND 0x0002 +#define DP_CLI_TYPE_MASK 0x0003 -struct dp_client { - struct dp_ctx *dpctx; - DBusConnection *conn; -}; +#define DP_CLI_METHOD_IDENTITY "getIdentity" +#define DP_CLI_METHOD_ONLINE "getOnline" #endif /* __DATA_PROVIDER_ */ diff --git a/server/providers/data_provider_be.c b/server/providers/data_provider_be.c new file mode 100644 index 000000000..83659bee9 --- /dev/null +++ b/server/providers/data_provider_be.c @@ -0,0 +1,515 @@ +/* + SSSD + + Data Provider Runner + + 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 "popt.h" +#include "ldb.h" +#include "ldb_errors.h" +#include "util/util.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" +#include "util/service_helpers.h" + +struct dp_mod_ops { + int (*check_online)(void *pvt_data, int *reply); +}; + +struct be_ctx { + struct event_context *ev; + struct confdb_ctx *cdb; + struct ldb_context *ldb; + struct service_sbus_ctx *ss_ctx; + struct service_sbus_ctx *dp_ctx; + const char *name; + const char *domain; + const char *identity; + struct dp_mod_ops *ops; + void *pvt_data; +}; + +typedef int (*be_init_fn_t)(struct be_ctx *, struct dp_mod_ops **, void **); + +static int service_identity(DBusMessage *message, void *data, DBusMessage **r); +static int service_pong(DBusMessage *message, void *data, DBusMessage **r); + +struct sbus_method mon_sbus_methods[] = { + {SERVICE_METHOD_IDENTITY, service_identity}, + {SERVICE_METHOD_PING, service_pong}, + {NULL, NULL} +}; + +static int be_identity(DBusMessage *message, void *data, DBusMessage **r); +static int check_online(DBusMessage *message, void *data, DBusMessage **r); + +struct sbus_method be_methods[] = { + { DP_CLI_METHOD_IDENTITY, be_identity }, + { DP_CLI_METHOD_ONLINE, check_online }, + { NULL, NULL } +}; + +static int service_identity(DBusMessage *message, void *data, DBusMessage **r) +{ + dbus_uint16_t version = BE_VERSION; + struct sbus_message_handler_ctx *smh_ctx; + struct be_ctx *ctx; + DBusMessage *reply; + dbus_bool_t ret; + void *user_data; + + if (!data) return EINVAL; + smh_ctx = talloc_get_type(data, struct sbus_message_handler_ctx); + if (!smh_ctx) return EINVAL; + user_data = sbus_conn_get_private_data(smh_ctx->conn_ctx); + if (!user_data) return EINVAL; + ctx = talloc_get_type(user_data, struct be_ctx); + if (!ctx) return EINVAL; + + reply = dbus_message_new_method_return(message); + ret = dbus_message_append_args(reply, + DBUS_TYPE_STRING, &ctx->identity, + DBUS_TYPE_UINT16, &version, + DBUS_TYPE_INVALID); + if (!ret) { + return EIO; + } + + *r = reply; + return EOK; +} + +static int service_pong(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 be_identity(DBusMessage *message, void *data, DBusMessage **r) +{ + dbus_uint16_t version = BE_VERSION; + dbus_uint16_t clitype = DP_CLI_BACKEND; + struct sbus_message_handler_ctx *smh_ctx; + struct be_ctx *ctx; + DBusMessage *reply; + dbus_bool_t ret; + void *user_data; + + if (!data) return EINVAL; + smh_ctx = talloc_get_type(data, struct sbus_message_handler_ctx); + if (!smh_ctx) return EINVAL; + user_data = sbus_conn_get_private_data(smh_ctx->conn_ctx); + if (!user_data) return EINVAL; + ctx = talloc_get_type(user_data, struct be_ctx); + if (!ctx) return EINVAL; + + reply = dbus_message_new_method_return(message); + ret = dbus_message_append_args(reply, + DBUS_TYPE_UINT16, &clitype, + DBUS_TYPE_UINT16, &version, + DBUS_TYPE_STRING, &ctx->name, + DBUS_TYPE_STRING, &ctx->domain, + DBUS_TYPE_INVALID); + if (!ret) { + return EIO; + } + + *r = reply; + return EOK; +} + +static int check_online(DBusMessage *message, void *data, DBusMessage **r) +{ + struct sbus_message_handler_ctx *smh_ctx; + struct be_ctx *ctx; + DBusMessage *reply; + dbus_bool_t dbret; + void *user_data; + int online = 0; + int ret; + + if (!data) return EINVAL; + smh_ctx = talloc_get_type(data, struct sbus_message_handler_ctx); + if (!smh_ctx) return EINVAL; + user_data = sbus_conn_get_private_data(smh_ctx->conn_ctx); + if (!user_data) return EINVAL; + ctx = talloc_get_type(user_data, struct be_ctx); + if (!ctx) return EINVAL; + + ret = ctx->ops->check_online(ctx->pvt_data, &online); + if (ret != EOK) return ret; + + reply = dbus_message_new_method_return(message); + dbret = dbus_message_append_args(reply, + DBUS_TYPE_UINT16, &online, + DBUS_TYPE_INVALID); + if (!dbret) return EIO; + + *r = reply; + return EOK; +} + +/* mon_cli_init + * sbus channel to the monitor daemon */ +static int mon_cli_init(struct be_ctx *ctx) +{ + struct service_sbus_ctx *ss_ctx; + + /* Set up SBUS connection to the monitor */ + ss_ctx = sssd_service_sbus_init(ctx, ctx->ev, ctx->cdb, + mon_sbus_methods); + if (ss_ctx == NULL) { + DEBUG(0, ("Could not initialize D-BUS.\n")); + return ENOMEM; + } + + ctx->ss_ctx = ss_ctx; + + /* attach be context to the connection */ + sbus_conn_set_private_data(ss_ctx->scon_ctx, ctx); + + return EOK; +} + +static int be_dp_sbus_init(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct confdb_ctx *cdb, + const char *address, + struct sbus_method *methods, + struct service_sbus_ctx **srvs_ctx) +{ + struct service_sbus_ctx *ss_ctx; + struct sbus_method_ctx *sm_ctx; + TALLOC_CTX *tmp_ctx; + char *default_monitor_address; + char *sbus_address; + DBusConnection *conn; + int ret; + + tmp_ctx = talloc_new(mem_ctx); + if (tmp_ctx == NULL) { + ret = ENOMEM; + goto done; + } + + ss_ctx = talloc_zero(tmp_ctx, struct service_sbus_ctx); + if (ss_ctx == NULL) { + ret = ENOMEM; + goto done; + } + ss_ctx->ev = ev; + + default_monitor_address = talloc_asprintf(tmp_ctx, "unix:path=%s/%s", + PIPE_PATH, SSSD_SERVICE_PIPE); + if (default_monitor_address == NULL) { + ret = ENOMEM; + goto done; + } + + ret = confdb_get_string(cdb, tmp_ctx, + "config/services/monitor", "sbusAddress", + default_monitor_address, &sbus_address); + if (ret != EOK) goto done; + + ret = sbus_new_connection(ss_ctx, ss_ctx->ev, + sbus_address, &ss_ctx->scon_ctx, + NULL); + if (ret != EOK) goto done; + + conn = sbus_get_connection(ss_ctx->scon_ctx); + + /* set up handler for service methods */ + sm_ctx = talloc_zero(ss_ctx, struct sbus_method_ctx); + if (sm_ctx == NULL) { + ret = ENOMEM; + goto done; + } + + sm_ctx->interface = talloc_strdup(sm_ctx, SERVICE_INTERFACE); + sm_ctx->path = talloc_strdup(sm_ctx, SERVICE_PATH); + if (!sm_ctx->interface || !sm_ctx->path) { + ret = ENOMEM; + goto done; + } + + /* Set up required monitor methods */ + sm_ctx->methods = methods; + + sm_ctx->message_handler = sbus_message_handler; + sbus_conn_add_method_ctx(ss_ctx->scon_ctx, sm_ctx); + + talloc_steal(mem_ctx, ss_ctx); + *srvs_ctx = ss_ctx; + ret = EOK; + +done: + talloc_free(tmp_ctx); + return ret; +} + +/* be_cli_init + * sbus channel to the data provider daemon */ +static int be_cli_init(struct be_ctx *ctx) +{ + struct service_sbus_ctx *dp_ctx; + char *default_dp_address; + int ret; + + default_dp_address = talloc_asprintf(ctx, "unix:path=%s/%s", + PIPE_PATH, DATA_PROVIDER_PIPE); + if (!default_dp_address) return ENOMEM; + + ret = be_dp_sbus_init(ctx, ctx->ev, ctx->cdb, + default_dp_address, be_methods, + &dp_ctx); + if (ret != EOK) { + talloc_free(default_dp_address); + return ret; + } + + ctx->dp_ctx = dp_ctx; + + /* attach be context to the connection */ + sbus_conn_set_private_data(dp_ctx->scon_ctx, ctx); + + talloc_free(default_dp_address); + return EOK; +} + +static int be_db_init(struct be_ctx *ctx) +{ + TALLOC_CTX *tmp_ctx; + char *ldb_file; + char *default_db_file; + int ret; + + tmp_ctx = talloc_new(ctx); + if (!tmp_ctx) { + return ENOMEM; + } + + default_db_file = talloc_asprintf(tmp_ctx, "%s/%s", DB_PATH, DATA_PROVIDER_DB_FILE); + if (!default_db_file) { + talloc_free(tmp_ctx); + return ENOMEM; + } + + ret = confdb_get_string(ctx->cdb, tmp_ctx, + DATA_PROVIDER_DB_CONF_SEC, "ldbFile", + default_db_file, &ldb_file); + if (ret != EOK) { + talloc_free(tmp_ctx); + return ret; + } + + ctx->ldb = ldb_init(tmp_ctx, ctx->ev); + if (!ctx->ldb) { + talloc_free(tmp_ctx); + return EIO; + } + + ret = ldb_connect(ctx->ldb, ldb_file, 0, NULL); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return EIO; + } + + talloc_steal(ctx, ctx->ldb); + + talloc_free(tmp_ctx); + return EOK; +} + +static int load_backend(struct be_ctx *ctx) +{ + TALLOC_CTX *tmp_ctx; + char *path; + void *handle; + char *mod_init_fn_name; + be_init_fn_t mod_init_fn; + int ret; + + tmp_ctx = talloc_new(ctx); + if (!tmp_ctx) { + return ENOMEM; + } + + path = talloc_asprintf(tmp_ctx, "%s/libsss_%s.so", + DATA_PROVIDER_PLUGINS_PATH, ctx->name); + + handle = dlopen(path, RTLD_NOW); + if (!handle) { + DEBUG(0, ("Unable to load %s module with path (%s), error: %s\n", + ctx->name, path, dlerror())); + ret = ELIBACC; + goto done; + } + + mod_init_fn_name = talloc_asprintf(tmp_ctx, "sssm_%s_init", ctx->name); + if (!mod_init_fn_name) { + ret = ENOMEM; + goto done; + } + + mod_init_fn = (be_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", + ctx->name, dlerror())); + ret = ELIBBAD; + goto done; + } + + ret = mod_init_fn(ctx, &ctx->ops, &ctx->pvt_data); + if (ret != EOK) { + DEBUG(0, ("Error (%d) in module (%s) initialization!\n", + ret, ctx->name)); + goto done; + } + + ret = EOK; + +done: + talloc_free(tmp_ctx); + return ret; +} + +int be_process_init(TALLOC_CTX *mem_ctx, + const char *be_name, + const char *be_domain, + struct event_context *ev, + struct confdb_ctx *cdb) +{ + struct be_ctx *ctx; + int ret; + + ctx = talloc_zero(mem_ctx, struct be_ctx); + if (!ctx) { + DEBUG(0, ("fatal error initializing be_ctx\n")); + return ENOMEM; + } + ctx->ev = ev; + ctx->cdb = cdb; + ctx->domain = talloc_strdup(ctx, be_domain); + ctx->identity = talloc_asprintf(ctx, "%%BE_%s", be_domain); + if (!ctx->domain || !ctx->identity) { + DEBUG(0, ("Out of memory!?\n")); + return ENOMEM; + } + + ret = be_db_init(ctx); + if (ret != EOK) { + DEBUG(0, ("fatal error opening database\n")); + return ret; + } + + ret = mon_cli_init(ctx); + if (ret != EOK) { + DEBUG(0, ("fatal error setting up monitor bus\n")); + return ret; + } + + ret = be_cli_init(ctx); + if (ret != EOK) { + DEBUG(0, ("fatal error setting up server bus\n")); + return ret; + } + + ret = load_backend(ctx); + if (ret != EOK) { + DEBUG(0, ("fatal error initializing data providers\n")); + return ret; + } + + return EOK; +} + +int main(int argc, const char *argv[]) +{ + int opt; + poptContext pc; + char *be_name; + char *be_domain; + char *srv_name; + struct main_context *main_ctx; + int ret; + + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_MAIN_OPTS + {"provider", 0, POPT_ARG_STRING, &be_name, 0, + "Information Provider", NULL }, + {"domain", 0, POPT_ARG_STRING, &be_domain, 0, + "Domain of the information provider", NULL }, + { NULL } + }; + + pc = poptGetContext(argv[0], argc, argv, long_options, 0); + while((opt = poptGetNextOpt(pc)) != -1) { + switch(opt) { + default: + fprintf(stderr, "\nInvalid option %s: %s\n\n", + poptBadOption(pc, 0), poptStrerror(opt)); + poptPrintUsage(pc, stderr, 0); + return 1; + } + } + + poptFreeContext(pc); + + /* set up things like debug , signals, daemonization, etc... */ + srv_name = talloc_asprintf(NULL, "sssd[be[%s]]", be_name); + if (!srv_name) return 2; + + ret = server_setup(srv_name, 0, &main_ctx); + if (ret != EOK) return 2; + + ret = be_process_init(main_ctx, + be_name, be_domain, + main_ctx->event_ctx, + main_ctx->confdb_ctx); + if (ret != EOK) return 3; + + /* loop on main */ + server_loop(main_ctx); + + return 0; +} + diff --git a/server/server.mk b/server/server.mk index 480e58fe6..7f9274d92 100644 --- a/server/server.mk +++ b/server/server.mk @@ -16,6 +16,9 @@ SERVER_OBJ = \ DP_OBJ = \ providers/data_provider.o +DP_BE_OBJ = \ + providers/data_provider_be.o + NSSSRV_OBJ = \ nss/nsssrv.o \ nss/nsssrv_packet.o \ @@ -34,3 +37,6 @@ sbin/sssd_nss: $(NSSSRV_OBJ) $(UTIL_OBJ) sbin/sssd_dp: $(DP_OBJ) $(UTIL_OBJ) $(CC) -o sbin/sssd_dp $(DP_OBJ) $(UTIL_OBJ) $(LDFLAGS) $(LIBS) + +sbin/sssd_be: $(DP_BE_OBJ) $(UTIL_OBJ) + $(CC) -o sbin/sssd_be $(DP_BE_OBJ) $(UTIL_OBJ) $(LDFLAGS) $(LIBS) diff --git a/server/util/server.c b/server/util/server.c index def44f038..6983fcaab 100644 --- a/server/util/server.c +++ b/server/util/server.c @@ -242,7 +242,10 @@ int server_setup(const char *name, int flags, uint16_t stdin_event_flags; int ret = EOK; - debug_prg_name = name; + debug_prg_name = strdup(name); + if (!debug_prg_name) { + return ENOMEM; + } setup_signals(); diff --git a/server/util/service_helpers.c b/server/util/service_helpers.c index 623210832..1630946f7 100644 --- a/server/util/service_helpers.c +++ b/server/util/service_helpers.c @@ -33,8 +33,7 @@ struct service_sbus_ctx *sssd_service_sbus_init(TALLOC_CTX *mem_ctx, struct event_context *ev, struct confdb_ctx *cdb, - sbus_msg_handler_fn get_identity, - sbus_msg_handler_fn ping) + struct sbus_method *methods) { struct service_sbus_ctx *ss_ctx; struct sbus_method_ctx *sm_ctx; @@ -75,22 +74,8 @@ struct service_sbus_ctx *sssd_service_sbus_init(TALLOC_CTX *mem_ctx, sm_ctx->path = talloc_strdup(sm_ctx, SERVICE_PATH); if (!sm_ctx->interface || !sm_ctx->path) goto error; - /* Set up required monitor methods */ - sm_ctx->methods = talloc_array(sm_ctx, struct sbus_method, 3); - if (sm_ctx->methods == NULL) goto error; - - /* Handle getIdentity */ - sm_ctx->methods[0].method = SERVICE_METHOD_IDENTITY; - sm_ctx->methods[0].fn = get_identity; - - /* Handle ping */ - sm_ctx->methods[1].method = SERVICE_METHOD_PING; - sm_ctx->methods[1].fn = ping; - - /* Terminate the list */ - sm_ctx->methods[2].method = NULL; - sm_ctx->methods[2].fn = NULL; - + /* Set up required monitor methods and handlers */ + sm_ctx->methods = methods; sm_ctx->message_handler = sbus_message_handler; sbus_conn_add_method_ctx(ss_ctx->scon_ctx, sm_ctx); diff --git a/server/util/service_helpers.h b/server/util/service_helpers.h index 440186db1..f2701d516 100644 --- a/server/util/service_helpers.h +++ b/server/util/service_helpers.h @@ -33,7 +33,6 @@ struct service_sbus_ctx { struct service_sbus_ctx *sssd_service_sbus_init(TALLOC_CTX *mem_ctx, struct event_context *ev, struct confdb_ctx *cdb, - sbus_msg_handler_fn get_identity, - sbus_msg_handler_fn ping); + struct sbus_method *methods); #endif /*SERVICE_HELPERS_H_*/ -- cgit