From 5aa5391dcd8a7d593757c0af3a765bbce1ce2138 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Tue, 6 Jan 2009 18:23:59 -0500 Subject: Add more infrastructure to data provider to dispatch requests (still untested). Add helper functions to connect to the data provider. Add some plumbing to the ldap provider (still untested). --- server/providers/data_provider.c | 343 ++++++++++++++++++++++++++++++++- server/providers/data_provider.h | 34 +++- server/providers/data_provider_be.c | 240 +++++++++--------------- server/providers/dp_backend.h | 57 ++++++ server/providers/dp_backend_store.c | 364 ++++++++++++++++++++++++++++++++++++ server/providers/dp_helpers.c | 98 ++++++++++ server/providers/ldap_provider.c | 97 +++++++++- server/server.mk | 4 +- 8 files changed, 1064 insertions(+), 173 deletions(-) create mode 100644 server/providers/dp_backend.h create mode 100644 server/providers/dp_backend_store.c create mode 100644 server/providers/dp_helpers.c diff --git a/server/providers/data_provider.c b/server/providers/data_provider.c index 823054ab7..645c14250 100644 --- a/server/providers/data_provider.c +++ b/server/providers/data_provider.c @@ -57,7 +57,6 @@ struct dp_ctx { struct dp_client { struct dp_ctx *dpctx; struct sbus_conn_ctx *conn_ctx; - const char *domain; }; struct dp_backend { @@ -83,13 +82,30 @@ 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} + { SERVICE_METHOD_IDENTITY, service_identity }, + { SERVICE_METHOD_PING, service_pong }, + { NULL, NULL } }; +static int dp_get_account_info(DBusMessage *message, void *data, DBusMessage **r); + struct sbus_method dp_sbus_methods[] = { - {NULL, NULL} + { DP_SRV_METHOD_GETACCTINFO, dp_get_account_info }, + { NULL, NULL } +}; + +struct dp_request { + /* reply message to send when request is done */ + DBusMessage *reply; + /* frontend client that made the request */ + struct dp_client *src_cli; + + int pending_replies; +}; + +struct dp_be_request { + struct dp_request *req; + struct dp_client *be_cli; }; static int service_identity(DBusMessage *message, void *data, DBusMessage **r) @@ -193,6 +209,7 @@ static int dp_db_init(struct dp_ctx *dpctx) static void be_identity_check(DBusPendingCall *pending, void *data); static void be_online_check(DBusPendingCall *pending, void *data); +static void be_got_account_info(DBusPendingCall *pending, void *data); static int dbus_dp_init(struct sbus_conn_ctx *conn_ctx, void *data) { @@ -280,7 +297,7 @@ static void be_identity_check(DBusPendingCall *pending, void *data) * 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")); + DEBUG(0, ("Severe error. A reply callback was called but no reply was received and no timeout occurred\n")); /* Destroy this connection */ sbus_disconnect(dpcli->conn_ctx); @@ -382,6 +399,314 @@ static void be_online_check(DBusPendingCall *pending, void *data) return; } +static void be_got_account_info(DBusPendingCall *pending, void *data) +{ + struct dp_be_request *bereq; + DBusMessage *reply; + DBusConnection *conn; + DBusError dbus_error; + dbus_uint16_t cli_err_maj; + dbus_uint32_t cli_err_min; + char *cli_err_msg; + dbus_bool_t ret; + int type; + + bereq = talloc_get_type(data, struct dp_be_request); + 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, ("Severe error. A reply callback was called but no reply was received and no timeout occurred\n")); + + /* Destroy this connection */ + sbus_disconnect(bereq->be_cli->conn_ctx); + goto done; + } + + 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_err_maj, + DBUS_TYPE_UINT32, &cli_err_min, + DBUS_TYPE_STRING, &cli_err_msg, + DBUS_TYPE_INVALID); + if (!ret) { + DEBUG(1,("be_identity_check failed, to parse message, killing connection\n")); + sbus_disconnect(bereq->be_cli->conn_ctx); + goto done; + } + + /* Set up the destructor for this service */ + break; + + case DBUS_MESSAGE_TYPE_ERROR: + DEBUG(0,("getAccountInfo 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(bereq->be_cli->conn_ctx); + } + + /* TODO: handle errors !! */ + if (bereq->req->pending_replies > 1) { + bereq->req->pending_replies--; + talloc_free(bereq); + } else { + conn = sbus_get_connection(bereq->be_cli->conn_ctx); + ret = dbus_message_append_args(bereq->req->reply, + DBUS_TYPE_UINT16, 0, + DBUS_TYPE_UINT32, 0, + DBUS_TYPE_STRING, "Success", + DBUS_TYPE_INVALID); + if (!ret) { + DEBUG(1, ("Failed to build reply ... frontend will wait for timeout ...\n")); + talloc_free(bereq->req); + goto done; + } + + /* finally send it */ + dbus_connection_send(conn, bereq->req->reply, NULL); + dbus_message_unref(bereq->req->reply); + talloc_free(bereq->req); + } + +done: + dbus_pending_call_unref(pending); + dbus_message_unref(reply); +} + +static int dp_send_acct_req(struct dp_be_request *bereq, + uint32_t type, char *attrs, char *filter) +{ + DBusMessage *msg; + DBusPendingCall *pending_reply; + DBusConnection *conn; + DBusError dbus_error; + dbus_bool_t ret; + + conn = sbus_get_connection(bereq->be_cli->conn_ctx); + dbus_error_init(&dbus_error); + + /* create the message */ + msg = dbus_message_new_method_call(NULL, + DP_CLI_PATH, + DP_CLI_INTERFACE, + DP_CLI_METHOD_GETACCTINFO); + if (msg == NULL) { + DEBUG(0,("Out of memory?!\n")); + return ENOMEM; + } + + ret = dbus_message_append_args(msg, + DBUS_TYPE_UINT32, &type, + DBUS_TYPE_STRING, &attrs, + DBUS_TYPE_STRING, &filter, + DBUS_TYPE_INVALID); + if (!ret) { + DEBUG(1,("Failed to build message\n")); + return EIO; + } + + ret = dbus_connection_send_with_reply(conn, msg, &pending_reply, + -1 /* TODO: set timeout */); + if (!ret) { + /* + * Critical Failure + * We can't communicate on this connection + * We'll drop it using the default destructor. + */ + DEBUG(0, ("D-BUS send failed.\n")); + dbus_message_unref(msg); + return EIO; + } + + /* Set up the reply handler */ + dbus_pending_call_set_notify(pending_reply, be_got_account_info, + bereq, NULL); + dbus_message_unref(msg); + + return EOK; +} + +static int dp_get_account_info(DBusMessage *message, void *data, DBusMessage **r) +{ + struct sbus_message_handler_ctx *smh_ctx; + struct dp_client *dpcli; + struct dp_be_request *bereq; + struct dp_request *dpreq = NULL; + struct dp_backend *dpbe; + DBusMessage *reply; + DBusError dbus_error; + dbus_bool_t dbret; + void *user_data; + uint32_t type; + char *domain, *attrs, *filter; + const char *errmsg = NULL; + int dpret = 0, ret = 0; + + 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; + dpcli = talloc_get_type(user_data, struct dp_client); + if (!dpcli) return EINVAL; + + dbus_error_init(&dbus_error); + + ret = dbus_message_get_args(message, &dbus_error, + DBUS_TYPE_STRING, &domain, + DBUS_TYPE_UINT32, &type, + DBUS_TYPE_STRING, &attrs, + DBUS_TYPE_STRING, &filter, + DBUS_TYPE_INVALID); + if (!ret) { + DEBUG(1,("Failed, to parse message!\n")); + return EIO; + } + + reply = dbus_message_new_method_return(message); + + /* search for domain */ + if (!domain) { + dpret = DP_ERR_FATAL; + errmsg = "Invalid Domain"; + ret = EINVAL; + goto respond; + } + + /* nothing to do for local */ + if (strcasecmp(domain, "LOCAL") == 0) { + dpret = DP_ERR_OK; + errmsg = "Success"; + ret = EOK; + goto respond; + } + + /* all domains, fire off a request for each backend */ + if (strcmp(domain, "*") == 0) { + dpreq = talloc(dpcli->dpctx, struct dp_request); + if (!dpreq) { + dpret = DP_ERR_FATAL; + errmsg = "Out of memory"; + ret = ENOMEM; + goto respond; + } + + dpreq->reply = reply; + dpreq->src_cli = dpcli; + dpreq->pending_replies = 0; + + /* now fire off requests */ + dpbe = dpcli->dpctx->be_list; + while (dpbe) { + bereq = talloc(dpreq, struct dp_be_request); + if (!bereq) { + DEBUG(1, ("Out of memory while sending requests\n")); + dpbe = dpbe->next; + continue; + } + bereq->req = dpreq; + bereq->be_cli = dpbe->dpcli; + ret = dp_send_acct_req(bereq, type, attrs, filter); + if (ret != EOK) { + DEBUG(2,("Failed to dispatch request to %s", dpbe->domain)); + dpbe = dpbe->next; + continue; + } + dpreq->pending_replies++; + dpbe = dpbe->next; + } + + if (dpreq->pending_replies == 0) { + dpret = DP_ERR_FATAL; + errmsg = "Unable to contact backends"; + ret = EIO; + talloc_free(dpreq); + goto respond; + } + + return EOK; + } + + dpbe = dpcli->dpctx->be_list; + while (dpbe) { + if (strcasecmp(dpbe->domain, domain) == 0) { + break; + } + + dpbe = dpbe->next; + } + + if (dpbe) { + dpreq = talloc(dpcli->dpctx, struct dp_request); + if (!dpreq) { + DEBUG(1, ("Out of memory while sending request\n")); + dpret = DP_ERR_FATAL; + errmsg = "Out of memory"; + ret = ENOMEM; + goto respond; + } + + dpreq->reply = reply; + dpreq->src_cli = dpcli; + dpreq->pending_replies = 1; + + bereq = talloc(dpreq, struct dp_be_request); + if (!bereq) { + DEBUG(1, ("Out of memory while sending request\n")); + dpret = DP_ERR_FATAL; + errmsg = "Out of memory"; + ret = ENOMEM; + talloc_free(dpreq); + goto respond; + } + bereq->req = dpreq; + bereq->be_cli = dpbe->dpcli; + + ret = dp_send_acct_req(bereq, type, attrs, filter); + if (ret != EOK) { + DEBUG(2,("Failed to dispatch request to %s", dpbe->domain)); + dpret = DP_ERR_FATAL; + errmsg = "Dispatch Failed"; + talloc_free(dpreq); + goto respond; + } + + } else { + + dpret = DP_ERR_FATAL; + errmsg = "Invalid Domain"; + ret = EINVAL; + goto respond; + } + + return EOK; + +respond: + dbret = dbus_message_append_args(reply, + DBUS_TYPE_UINT16, dpret, + DBUS_TYPE_UINT32, ret, + DBUS_TYPE_STRING, errmsg, + DBUS_TYPE_INVALID); + if (!dbret) return EIO; + + *r = reply; + return EOK; +} + static int dp_backend_destructor(void *ctx) { struct dp_backend *dpbe = talloc_get_type(ctx, struct dp_backend); @@ -466,9 +791,9 @@ done: return ret; } -int dp_process_init(TALLOC_CTX *mem_ctx, - struct event_context *ev, - struct confdb_ctx *cdb) +static int dp_process_init(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct confdb_ctx *cdb) { struct dp_ctx *dpctx; int ret; diff --git a/server/providers/data_provider.h b/server/providers/data_provider.h index a7712d082..bd610a539 100644 --- a/server/providers/data_provider.h +++ b/server/providers/data_provider.h @@ -24,12 +24,18 @@ #include #include +#include #include "talloc.h" #include "tevent.h" #include "ldb.h" +#include "util/util.h" +#include "confdb/confdb.h" +#include "dbus/dbus.h" +#include "sbus/sssd_dbus.h" +#include "sbus_interfaces.h" +#include "util/service_helpers.h" #define DATA_PROVIDER_VERSION 0x0001 -#define BE_VERSION 0x0001 #define DATA_PROVIDER_SERVICE_NAME "dp" #define DATA_PROVIDER_PIPE "private/sbus-dp" @@ -48,9 +54,29 @@ #define DP_CLI_METHOD_IDENTITY "getIdentity" #define DP_CLI_METHOD_ONLINE "getOnline" +#define DP_CLI_METHOD_GETACCTINFO "getAccountInfo" -struct dp_be_mod_ops { - int (*check_online)(void *pvt_data, int *reply); -}; +#define DP_SRV_METHOD_GETACCTINFO "getAccountInfo" + +#define DP_ERR_OK 0 +#define DP_ERR_OFFLINE 1 +#define DP_ERR_TIMEOUT 2 +#define DP_ERR_FATAL 3 + +#define BE_ATTR_CORE 1 +#define BE_ATTR_MEM 2 +#define BE_ATTR_ALL 3 + +#define BE_FILTER_NAME 1 +#define BE_FILTER_IDNUM 2 + +#define BE_REQ_USER 1 +#define BE_REQ_GROUP 2 + +int dp_sbus_cli_init(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct confdb_ctx *cdb, + struct sbus_method *methods, + struct service_sbus_ctx **srvs_ctx); #endif /* __DATA_PROVIDER_ */ diff --git a/server/providers/data_provider_be.c b/server/providers/data_provider_be.c index 060b4e7a4..6f3f841f9 100644 --- a/server/providers/data_provider_be.c +++ b/server/providers/data_provider_be.c @@ -1,7 +1,7 @@ /* SSSD - Data Provider Runner + Data Provider Process Copyright (C) Simo Sorce 2008 @@ -38,45 +38,35 @@ #include "sbus/sssd_dbus.h" #include "sbus_interfaces.h" #include "util/btreemap.h" -#include "providers/data_provider.h" +#include "providers/dp_backend.h" #include "util/service_helpers.h" -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_be_mod_ops *ops; - void *pvt_data; -}; -typedef int (*be_init_fn_t)(TALLOC_CTX *, struct dp_be_mod_ops **, void **); +typedef int (*be_init_fn_t)(TALLOC_CTX *, struct be_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} + { SERVICE_METHOD_IDENTITY, service_identity }, + { SERVICE_METHOD_PING, service_pong }, + { NULL, NULL } }; static int be_identity(DBusMessage *message, void *data, DBusMessage **r); static int be_check_online(DBusMessage *message, void *data, DBusMessage **r); +static int be_get_account_info(DBusMessage *message, void *data, DBusMessage **r); struct sbus_method be_methods[] = { { DP_CLI_METHOD_IDENTITY, be_identity }, { DP_CLI_METHOD_ONLINE, be_check_online }, + { DP_CLI_METHOD_GETACCTINFO, be_get_account_info }, { NULL, NULL } }; static int service_identity(DBusMessage *message, void *data, DBusMessage **r) { - dbus_uint16_t version = BE_VERSION; + dbus_uint16_t version = DATA_PROVIDER_VERSION; struct sbus_message_handler_ctx *smh_ctx; struct be_ctx *ctx; DBusMessage *reply; @@ -123,7 +113,7 @@ static int service_pong(DBusMessage *message, void *data, DBusMessage **r) static int be_identity(DBusMessage *message, void *data, DBusMessage **r) { - dbus_uint16_t version = BE_VERSION; + dbus_uint16_t version = DATA_PROVIDER_VERSION; dbus_uint16_t clitype = DP_CLI_BACKEND; struct sbus_message_handler_ctx *smh_ctx; struct be_ctx *ctx; @@ -175,7 +165,7 @@ static int be_check_online(DBusMessage *message, void *data, DBusMessage **r) ctx = talloc_get_type(user_data, struct be_ctx); if (!ctx) return EINVAL; - ret = ctx->ops->check_online(ctx->pvt_data, &online); + ret = ctx->ops->check_online(ctx, &online); if (ret != EOK) return ret; reply = dbus_message_new_method_return(message); @@ -188,6 +178,76 @@ static int be_check_online(DBusMessage *message, void *data, DBusMessage **r) return EOK; } +static int be_get_account_info(DBusMessage *message, void *data, DBusMessage **r) +{ + struct sbus_message_handler_ctx *smh_ctx; + struct be_ctx *ctx; + DBusMessage *reply; + DBusError dbus_error; + dbus_bool_t dbret; + void *user_data; + uint32_t type; + char *attrs, *search_exp; + int attr_type, filter_type; + char *filter_val; + 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; + + dbus_error_init(&dbus_error); + + ret = dbus_message_get_args(message, &dbus_error, + DBUS_TYPE_UINT32, &type, + DBUS_TYPE_STRING, &attrs, + DBUS_TYPE_STRING, &search_exp, + DBUS_TYPE_INVALID); + if (!ret) { + DEBUG(1,("Failed, to parse message!\n")); + return EIO; + } + + if (!attrs) { + if (strcmp(attrs, "core") == 0) attr_type = BE_ATTR_CORE; + else if (strcmp(attrs, "membership") == 0) attr_type = BE_ATTR_MEM; + else if (strcmp(attrs, "all") == 0) attr_type = BE_ATTR_ALL; + else return EINVAL; + } + else return EINVAL; + + if (!search_exp) { + if (strncmp(search_exp, "name=", 5) == 0) { + filter_type = BE_FILTER_NAME; + filter_val = &search_exp[5]; + } else if (strncmp(search_exp, "idnumber=", 9) == 0) { + filter_type = BE_FILTER_IDNUM; + filter_val = &search_exp[9]; + } else return EINVAL; + } + else return EINVAL; + + /* process request */ + ret = ctx->ops->get_account_info(ctx, type, attr_type, + filter_type, filter_val); + if (ret != EOK) return ret; + + reply = dbus_message_new_method_return(message); + dbret = dbus_message_append_args(reply, + DBUS_TYPE_UINT16, 0, + DBUS_TYPE_UINT32, 0, + DBUS_TYPE_STRING, "Success", + 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) @@ -210,99 +270,16 @@ static int mon_cli_init(struct be_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_dp_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_dp_address = talloc_asprintf(tmp_ctx, "unix:path=%s/%s", - PIPE_PATH, DATA_PROVIDER_PIPE); - if (default_dp_address == NULL) { - ret = ENOMEM; - goto done; - } - - ret = confdb_get_string(cdb, tmp_ctx, - "config/services/dp", "sbusAddress", - default_dp_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, DATA_PROVIDER_INTERFACE); - sm_ctx->path = talloc_strdup(sm_ctx, DATA_PROVIDER_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); + ret = dp_sbus_cli_init(ctx, ctx->ev, ctx->cdb, + be_methods, &dp_ctx); if (ret != EOK) { - talloc_free(default_dp_address); return ret; } @@ -311,51 +288,6 @@ static int be_cli_init(struct be_ctx *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; } @@ -440,9 +372,9 @@ int be_process_init(TALLOC_CTX *mem_ctx, return ENOMEM; } - ret = be_db_init(ctx); + ret = dp_be_cachedb_init(ctx); if (ret != EOK) { - DEBUG(0, ("fatal error opening database\n")); + DEBUG(0, ("fatal error opening cache database\n")); return ret; } @@ -513,6 +445,8 @@ int main(int argc, const char *argv[]) main_ctx->confdb_ctx); if (ret != EOK) return 3; + DEBUG(1, ("Backend provider %s(%s) started!", be_name, be_domain)); + /* loop on main */ server_loop(main_ctx); diff --git a/server/providers/dp_backend.h b/server/providers/dp_backend.h new file mode 100644 index 000000000..81df6b7d1 --- /dev/null +++ b/server/providers/dp_backend.h @@ -0,0 +1,57 @@ +/* + 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 __DP_BACKEND_H__ +#define __DP_BACKEND_H__ + +#include "providers/data_provider.h" + +struct be_mod_ops; + +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 be_mod_ops *ops; + void *pvt_data; +}; + +struct be_mod_ops { + int (*check_online)(struct be_ctx *, int *reply); + int (*get_account_info)(struct be_ctx *, + int entry_type, int attr_type, + int filter_type, char *filter_value); +}; + +int dp_be_store_account_posix(struct be_ctx *ctx, + char *name, char *pwd, + uint64_t uid, uint64_t gid, + char *gecos, char *homedir, char *shell); +int dp_be_remove_account_posix(struct be_ctx *ctx, char *name); + +int dp_be_cachedb_init(struct be_ctx *ctx); + +#endif /* __DP_BACKEND_H___ */ diff --git a/server/providers/dp_backend_store.c b/server/providers/dp_backend_store.c new file mode 100644 index 000000000..e518f4387 --- /dev/null +++ b/server/providers/dp_backend_store.c @@ -0,0 +1,364 @@ +/* + SSSD + + Data Provider Backend Storage helper funcitons + + 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 "ldb.h" +#include "ldb_errors.h" +#include "util/util.h" +#include "providers/dp_backend.h" +#include + +int dp_be_store_account_posix(struct be_ctx *ctx, + char *name, char *pwd, + uint64_t uid, uint64_t gid, + char *gecos, char *homedir, char *shell) +{ + TALLOC_CTX *tmp_ctx; + const char *attrs[] = { "uid", NULL }; + struct ldb_dn *account_dn; + struct ldb_message *msg; + struct ldb_request *req; + struct ldb_result *res; + int lret, ret; + int flags; + + tmp_ctx = talloc_new(ctx); + if (!tmp_ctx) { + return ENOMEM; + } + + account_dn = ldb_dn_new_fmt(tmp_ctx, ctx->ldb, + "uid=%s,cn=users,cn=%s,cn=remote", + name, ctx->domain); + if (!account_dn) { + talloc_free(tmp_ctx); + return ENOMEM; + } + + lret = ldb_transaction_start(ctx->ldb); + if (lret != LDB_SUCCESS) { + DEBUG(1, ("Failed ldb transaction start !? (%d)\n", lret)); + ret = EIO; + goto done; + } + + res = talloc_zero(tmp_ctx, struct ldb_result); + if (!res) { + ret = ENOMEM; + goto done; + } + + lret = ldb_build_search_req(&req, ctx->ldb, tmp_ctx, + account_dn, LDB_SCOPE_BASE, + "(objectClass=User)", attrs, NULL, + res, ldb_search_default_callback, NULL); + if (!lret) { + DEBUG(1, ("Failed to build search request (%d) !?\n", lret)); + ret = EIO; + goto done; + } + + lret = ldb_request(ctx->ldb, req); + if (lret == LDB_SUCCESS) { + lret = ldb_wait(req->handle, LDB_WAIT_ALL); + } + if (lret != LDB_SUCCESS) { + DEBUG(1, ("Failed to make search request: %s(%d)[%s]\n", + ldb_strerror(lret), lret, ldb_errstring(ctx->ldb))); + ret = EIO; + goto done; + } + + talloc_free(req); + req = NULL; + + msg = ldb_msg_new(tmp_ctx); + if (!msg) { + ret = ENOMEM; + goto done; + } + msg->dn = account_dn; + + switch (res->count) { + case 0: + flags = LDB_FLAG_MOD_ADD; + break; + case 1: + flags = LDB_FLAG_MOD_REPLACE; + break; + default: + DEBUG(0, ("Cache DB corrupted, base search returned %d results\n", + res->count)); + ret = EIO; + goto done; + } + + talloc_free(res); + res = NULL; + + if (flags == LDB_FLAG_MOD_ADD) { + /* TODO: retrieve user objectclass list from configuration */ + lret = ldb_msg_add_empty(msg, "objectClass", flags, NULL); + if (lret == LDB_SUCCESS) { + lret = ldb_msg_add_string(msg, "objectClass", "user"); + } + if (lret != LDB_SUCCESS) { + ret = errno; + goto done; + } + + /* TODO: retrieve user name attribute from configuration */ + lret = ldb_msg_add_empty(msg, "uid", flags, NULL); + if (lret == LDB_SUCCESS) { + lret = ldb_msg_add_string(msg, "uid", name); + } + if (lret != LDB_SUCCESS) { + ret = errno; + goto done; + } + } + + /* TODO: retrieve attribute name mappings from configuration */ + + /* pwd */ + if (pwd && *pwd) { + lret = ldb_msg_add_empty(msg, "userPassword", flags, NULL); + if (lret == LDB_SUCCESS) { + lret = ldb_msg_add_string(msg, "userPassword", pwd); + } + } else { + lret = ldb_msg_add_empty(msg, "userPassword", + LDB_FLAG_MOD_DELETE, NULL); + } + if (lret != LDB_SUCCESS) { + ret = errno; + goto done; + } + + /* uid */ + if (uid) { + lret = ldb_msg_add_empty(msg, "uidNumber", flags, NULL); + if (lret == LDB_SUCCESS) { + lret = ldb_msg_add_fmt(msg, "uidNumber", + "%lu", (long unsigned)uid); + } + if (lret != LDB_SUCCESS) { + ret = errno; + goto done; + } + } else { + DEBUG(0, ("Cached users can't have UID == 0\n")); + ret = EINVAL; + goto done; + } + + /* gid */ + if (gid) { + lret = ldb_msg_add_empty(msg, "gidNumber", flags, NULL); + if (lret == LDB_SUCCESS) { + lret = ldb_msg_add_fmt(msg, "gidNumber", + "%lu", (long unsigned)gid); + } + if (lret != LDB_SUCCESS) { + ret = errno; + goto done; + } + } else { + DEBUG(0, ("Cached users can't have GID == 0\n")); + ret = EINVAL; + goto done; + } + + /* gecos */ + if (gecos && *gecos) { + lret = ldb_msg_add_empty(msg, "fullName", flags, NULL); + if (lret == LDB_SUCCESS) { + lret = ldb_msg_add_string(msg, "fullName", gecos); + } + } else { + lret = ldb_msg_add_empty(msg, "fullName", + LDB_FLAG_MOD_DELETE, NULL); + } + if (lret != LDB_SUCCESS) { + ret = errno; + goto done; + } + + /* homedir */ + if (homedir && *homedir) { + lret = ldb_msg_add_empty(msg, "homeDirectory", flags, NULL); + if (lret == LDB_SUCCESS) { + lret = ldb_msg_add_string(msg, "homeDirectory", homedir); + } + } else { + lret = ldb_msg_add_empty(msg, "homeDirectory", + LDB_FLAG_MOD_DELETE, NULL); + } + if (lret != LDB_SUCCESS) { + ret = errno; + goto done; + } + + /* shell */ + if (shell && *shell) { + lret = ldb_msg_add_empty(msg, "loginShell", flags, NULL); + if (lret == LDB_SUCCESS) { + lret = ldb_msg_add_string(msg, "loginShell", shell); + } + } else { + lret = ldb_msg_add_empty(msg, "loginShell", + LDB_FLAG_MOD_DELETE, NULL); + } + if (lret != LDB_SUCCESS) { + ret = errno; + goto done; + } + + /* modification time */ + lret = ldb_msg_add_empty(msg, "lastUpdate", flags, NULL); + if (lret == LDB_SUCCESS) { + lret = ldb_msg_add_fmt(msg, "lastUpdate", + "%ld", (long int)time(NULL)); + } + if (lret != LDB_SUCCESS) { + ret = errno; + goto done; + } + + if (flags == LDB_FLAG_MOD_ADD) { + lret = ldb_build_add_req(&req, ctx->ldb, tmp_ctx, msg, NULL, + NULL, ldb_op_default_callback, NULL); + } else { + lret = ldb_build_mod_req(&req, ctx->ldb, tmp_ctx, msg, NULL, + NULL, ldb_op_default_callback, NULL); + } + if (lret == LDB_SUCCESS) { + lret = ldb_request(ctx->ldb, req); + if (lret == LDB_SUCCESS) { + lret = ldb_wait(req->handle, LDB_WAIT_ALL); + } + } + if (lret != LDB_SUCCESS) { + DEBUG(1, ("Failed to make modify request: %s(%d)[%s]\n", + ldb_strerror(lret), lret, ldb_errstring(ctx->ldb))); + ret = EIO; + goto done; + } + + lret = ldb_transaction_commit(ctx->ldb); + if (lret != LDB_SUCCESS) { + DEBUG(1, ("Failed ldb transaction start !? (%d)\n", lret)); + ret = EIO; + goto done; + } + + ret = EOK; + +done: + if (ret != EOK) { + lret = ldb_transaction_cancel(ctx->ldb); + if (lret != LDB_SUCCESS) { + DEBUG(1, ("Failed to cancel ldb transaction (%d)\n", lret)); + } + } + + talloc_free(tmp_ctx); + return ret; +} + +int dp_be_remove_account_posix(struct be_ctx *ctx, char *name) +{ + TALLOC_CTX *tmp_ctx; + struct ldb_dn *account_dn; + int ret; + + tmp_ctx = talloc_new(ctx); + if (!tmp_ctx) { + return ENOMEM; + } + + account_dn = ldb_dn_new_fmt(tmp_ctx, ctx->ldb, + "uid=%s,cn=users,cn=%s,cn=remote", + name, ctx->domain); + if (!account_dn) { + talloc_free(tmp_ctx); + return ENOMEM; + } + + ret = ldb_delete(ctx->ldb, account_dn); + + if (ret != LDB_SUCCESS) { + DEBUG(2, ("LDB Error: %s(%d)\nError Message: [%s]\n", + ldb_strerror(ret), ret, ldb_errstring(ctx->ldb))); + ret = EIO; + } + + talloc_free(tmp_ctx); + return ret; +} + +/* TODO: Unify with nss_ldb and provide a single cachedb interface */ + +int dp_be_cachedb_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; +} + diff --git a/server/providers/dp_helpers.c b/server/providers/dp_helpers.c new file mode 100644 index 000000000..99d65f45e --- /dev/null +++ b/server/providers/dp_helpers.c @@ -0,0 +1,98 @@ +/* + SSSD + + Data Provider Helpers + + 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 "providers/data_provider.h" + +int dp_sbus_cli_init(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct confdb_ctx *cdb, + 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_dp_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_dp_address = talloc_asprintf(tmp_ctx, "unix:path=%s/%s", + PIPE_PATH, DATA_PROVIDER_PIPE); + if (default_dp_address == NULL) { + ret = ENOMEM; + goto done; + } + + ret = confdb_get_string(cdb, tmp_ctx, + "config/services/dp", "sbusAddress", + default_dp_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, DATA_PROVIDER_INTERFACE); + sm_ctx->path = talloc_strdup(sm_ctx, DATA_PROVIDER_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; +} + diff --git a/server/providers/ldap_provider.c b/server/providers/ldap_provider.c index a6628f40a..884f843e0 100644 --- a/server/providers/ldap_provider.c +++ b/server/providers/ldap_provider.c @@ -24,7 +24,7 @@ #include #include #include "util/util.h" -#include "providers/data_provider.h" +#include "providers/dp_backend.h" struct ldap_nss_ops { enum nss_status (*getpwnam_r)(const char *name, struct passwd *result, @@ -54,19 +54,104 @@ struct ldap_ctx { struct ldap_nss_ops ops; }; -static int ldap_check_online(void *pvt_data, int *reply); +static int get_pw_name(struct be_ctx *be_ctx, struct ldap_ctx *ldap_ctx, char *name) +{ + struct ldap_nss_ops *ops = &ldap_ctx->ops; + enum nss_status status; + struct passwd result; + char *buffer; + int ret; + + buffer = talloc_size(NULL, 4096); + if (!buffer) return ENOMEM; + + status = ops->getpwnam_r(name, &result, buffer, 4096, &ret); + + switch (status) { + case NSS_STATUS_NOTFOUND: + ret = dp_be_remove_account_posix(be_ctx, name); + break; + case NSS_STATUS_SUCCESS: + ret = dp_be_store_account_posix(be_ctx, name, result.pw_passwd, + result.pw_uid, result.pw_gid, + result.pw_gecos, result.pw_dir, + result.pw_shell); + break; + default: + DEBUG(2, ("ldap->getpwnam_r failed for '%s' (%d)[%s]\n", + name, ret, strerror(ret))); + talloc_free(buffer); + return ret; + } + + if (ret != EOK) { + DEBUG(1, ("Failed to update LDB Cache for '%s' (%d) !?\n", + name, ret)); + } + + talloc_free(buffer); + return ret; +} -struct dp_be_mod_ops ldap_mod_ops = { - .check_online = ldap_check_online +static int ldap_check_online(struct be_ctx *be_ctx, int *reply); +static int ldap_get_account_info(struct be_ctx *be_ctx, + int entry_type, int attr_type, + int filter_type, char *filter_value); + +struct be_mod_ops ldap_mod_ops = { + .check_online = ldap_check_online, + .get_account_info = ldap_get_account_info }; -static int ldap_check_online(void *pvt_data, int *reply) +static int ldap_check_online(struct be_ctx *be_ctx, int *reply) { *reply = MOD_ONLINE; return EOK; } -int sssm_ldap_init(TALLOC_CTX *bectx, struct dp_be_mod_ops **ops, void **pvt_data) +static int ldap_get_account_info(struct be_ctx *be_ctx, + int entry_type, int attr_type, + int filter_type, char *filter_value) +{ + struct ldap_ctx *ctx; + + ctx = talloc_get_type(be_ctx->pvt_data, struct ldap_ctx); + + switch (entry_type) { + case BE_REQ_USER: /* user */ + switch (filter_type) { + case BE_FILTER_NAME: + switch (attr_type) { + case BE_ATTR_CORE: + if (strchr(filter_value, '*')) { + /* TODO */ + } else { + return get_pw_name(be_ctx, ctx, filter_value); + } + break; + default: + return EINVAL; + } + break; + case BE_FILTER_IDNUM: + break; + default: + return EINVAL; + } + break; + + case BE_REQ_GROUP: /* group */ + /* TODO */ + return EOK; + + default: /*fail*/ + return EINVAL; + } + + return EOK; +} + +int sssm_ldap_init(struct be_ctx *bectx, struct be_mod_ops **ops, void **pvt_data) { struct ldap_ctx *ctx; void *handle; diff --git a/server/server.mk b/server/server.mk index f41c247ac..c63ec7ed6 100644 --- a/server/server.mk +++ b/server/server.mk @@ -5,6 +5,7 @@ UTIL_OBJ = \ util/memory.o \ util/btreemap.o \ util/service_helpers.o \ + providers/dp_helpers.o \ confdb/confdb.o \ sbus/sssd_dbus_common.o \ sbus/sssd_dbus_connection.o \ @@ -17,7 +18,8 @@ DP_OBJ = \ providers/data_provider.o DP_BE_OBJ = \ - providers/data_provider_be.o + providers/data_provider_be.o \ + providers/dp_backend_store.o LDAP_BE_OBJ = \ providers/ldap_provider.o -- cgit