diff options
author | Simo Sorce <idra@samba.org> | 2009-01-06 18:23:59 -0500 |
---|---|---|
committer | Simo Sorce <idra@samba.org> | 2009-01-06 18:23:59 -0500 |
commit | 5aa5391dcd8a7d593757c0af3a765bbce1ce2138 (patch) | |
tree | 6fe184bed37e97e72e9dfd59739aef0785e29fd8 /server/providers | |
parent | c1f2536bac22d17ab658050f0cacb0528b01a87f (diff) | |
download | sssd-5aa5391dcd8a7d593757c0af3a765bbce1ce2138.tar.gz sssd-5aa5391dcd8a7d593757c0af3a765bbce1ce2138.tar.xz sssd-5aa5391dcd8a7d593757c0af3a765bbce1ce2138.zip |
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).
Diffstat (limited to 'server/providers')
-rw-r--r-- | server/providers/data_provider.c | 343 | ||||
-rw-r--r-- | server/providers/data_provider.h | 34 | ||||
-rw-r--r-- | server/providers/data_provider_be.c | 240 | ||||
-rw-r--r-- | server/providers/dp_backend.h | 57 | ||||
-rw-r--r-- | server/providers/dp_backend_store.c | 364 | ||||
-rw-r--r-- | server/providers/dp_helpers.c | 98 | ||||
-rw-r--r-- | server/providers/ldap_provider.c | 97 |
7 files changed, 1061 insertions, 172 deletions
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 <stdint.h> #include <sys/un.h> +#include <errno.h> #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 <ssorce@redhat.com> 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 <ssorce@redhat.com> 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 <http://www.gnu.org/licenses/>. +*/ + +#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 <ssorce@redhat.com> 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 <http://www.gnu.org/licenses/>. +*/ + + +#include <errno.h> +#include "ldb.h" +#include "ldb_errors.h" +#include "util/util.h" +#include "providers/dp_backend.h" +#include <time.h> + +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 <ssorce@redhat.com> 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 <http://www.gnu.org/licenses/>. +*/ + +#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 <pwd.h> #include <grp.h> #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; |