From 60bbc5034e546b7df7a6f782e3353b863f49618b Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 25 Feb 2009 19:36:43 -0500 Subject: Serialize access to sysdb and also exposes ldb transactions. This is necessary because in ldb only 1 transaction per context is possible and all operations (or new transactions) are nested within it. Will revisit this later when ldb will addresses the problem. --- server/db/sysdb.c | 745 +------------------------------------- server/db/sysdb.h | 14 +- server/db/sysdb_internal.h | 70 ---- server/db/sysdb_private.h | 95 +++++ server/db/sysdb_req.c | 241 ++++++++++++ server/db/sysdb_search.c | 731 +++++++++++++++++++++++++++++++++++++ server/db/sysdb_sync.c | 2 +- server/responder/nss/nsssrv.c | 10 +- server/responder/nss/nsssrv_cmd.c | 73 ++-- server/server.mk | 2 + 10 files changed, 1133 insertions(+), 850 deletions(-) delete mode 100644 server/db/sysdb_internal.h create mode 100644 server/db/sysdb_private.h create mode 100644 server/db/sysdb_req.c create mode 100644 server/db/sysdb_search.c diff --git a/server/db/sysdb.c b/server/db/sysdb.c index ddd7fbe4..1c91f122 100644 --- a/server/db/sysdb.c +++ b/server/db/sysdb.c @@ -20,743 +20,13 @@ */ #include "util/util.h" -#include "db/sysdb.h" -#include "db/sysdb_internal.h" +#include "db/sysdb_private.h" #include "confdb/confdb.h" #include -struct sysdb_search_ctx { - struct sysdb_ctx *dbctx; - const char *domain; - bool legacy; - sysdb_callback_t callback; - void *ptr; - struct ldb_result *res; -}; - -static int sysdb_error_to_errno(int lerr) -{ - /* fake it up for now, requires a mapping table */ - return EIO; -} - -static void request_error(struct sysdb_search_ctx *sctx, int ldb_error) -{ - sctx->callback(sctx->ptr, sysdb_error_to_errno(ldb_error), sctx->res); -} - -static void request_done(struct sysdb_search_ctx *sctx) -{ - sctx->callback(sctx->ptr, EOK, sctx->res); -} - -static int get_gen_callback(struct ldb_request *req, - struct ldb_reply *ares) -{ - struct sysdb_search_ctx *sctx; - struct ldb_result *res; - int n; - - sctx = talloc_get_type(req->context, struct sysdb_search_ctx); - res = sctx->res; - - if (!ares) { - request_error(sctx, LDB_ERR_OPERATIONS_ERROR); - return LDB_ERR_OPERATIONS_ERROR; - } - if (ares->error != LDB_SUCCESS) { - request_error(sctx, ares->error); - return ares->error; - } - - switch (ares->type) { - case LDB_REPLY_ENTRY: - res->msgs = talloc_realloc(res, res->msgs, - struct ldb_message *, - res->count + 2); - if (!res->msgs) { - request_error(sctx, LDB_ERR_OPERATIONS_ERROR); - return LDB_ERR_OPERATIONS_ERROR; - } - - res->msgs[res->count + 1] = NULL; - - res->msgs[res->count] = talloc_steal(res->msgs, ares->message); - res->count++; - break; - - case LDB_REPLY_REFERRAL: - if (res->refs) { - for (n = 0; res->refs[n]; n++) /*noop*/ ; - } else { - n = 0; - } - - res->refs = talloc_realloc(res, res->refs, char *, n + 2); - if (! res->refs) { - request_error(sctx, LDB_ERR_OPERATIONS_ERROR); - return LDB_ERR_OPERATIONS_ERROR; - } - - res->refs[n] = talloc_steal(res->refs, ares->referral); - res->refs[n + 1] = NULL; - break; - - case LDB_REPLY_DONE: - res->controls = talloc_steal(res, ares->controls); - - /* this is the last message, and means the request is done */ - request_done(sctx); - return LDB_SUCCESS; - } - - talloc_free(ares); - return LDB_SUCCESS; -} - -static struct sysdb_search_ctx *init_src_ctx(TALLOC_CTX *mem_ctx, - const char *domain, - bool legacy, - struct sysdb_ctx *ctx, - sysdb_callback_t fn, - void *ptr) -{ - struct sysdb_search_ctx *sctx; - - sctx = talloc(mem_ctx, struct sysdb_search_ctx); - if (!sctx) { - return NULL; - } - sctx->dbctx = ctx; - sctx->callback = fn; - sctx->ptr = ptr; - sctx->res = talloc_zero(sctx, struct ldb_result); - if (!sctx->res) { - talloc_free(sctx); - return NULL; - } - sctx->domain = talloc_strdup(sctx, domain); - if (!sctx->domain) { - talloc_free(sctx); - return NULL; - } - sctx->legacy = legacy; - - return sctx; -} - -/* users */ - -static int pwd_search(struct sysdb_search_ctx *sctx, - struct sysdb_ctx *ctx, - const char *expression) -{ - static const char *attrs[] = SYSDB_PW_ATTRS; - struct ldb_request *req; - struct ldb_dn *base_dn; - int ret; - - base_dn = ldb_dn_new_fmt(sctx, ctx->ldb, - SYSDB_TMPL_USER_BASE, sctx->domain); - if (!base_dn) { - return ENOMEM; - } - - ret = ldb_build_search_req(&req, ctx->ldb, sctx, - base_dn, LDB_SCOPE_SUBTREE, - expression, attrs, NULL, - sctx, get_gen_callback, - NULL); - if (ret != LDB_SUCCESS) { - return sysdb_error_to_errno(ret); - } - - ret = ldb_request(ctx->ldb, req); - if (ret != LDB_SUCCESS) { - return sysdb_error_to_errno(ret); - } - - return EOK; -} - -int sysdb_getpwnam(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct sysdb_ctx *ctx, - const char *domain, - const char *name, - bool legacy, - sysdb_callback_t fn, void *ptr) -{ - struct sysdb_search_ctx *sctx; - char *expression; - - if (!domain) { - return EINVAL; - } - - sctx = init_src_ctx(mem_ctx, domain, legacy, ctx, fn, ptr); - if (!sctx) { - return ENOMEM; - } - - expression = talloc_asprintf(sctx, SYSDB_PWNAM_FILTER, name); - if (!expression) { - talloc_free(sctx); - return ENOMEM; - } - - return pwd_search(sctx, ctx, expression); -} - -int sysdb_getpwuid(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct sysdb_ctx *ctx, - const char *domain, - uid_t uid, - bool legacy, - sysdb_callback_t fn, void *ptr) -{ - struct sysdb_search_ctx *sctx; - unsigned long int filter_uid = uid; - char *expression; - - if (!domain) { - return EINVAL; - } - - sctx = init_src_ctx(mem_ctx, domain, legacy, ctx, fn, ptr); - if (!sctx) { - return ENOMEM; - } - - expression = talloc_asprintf(sctx, SYSDB_PWUID_FILTER, filter_uid); - if (!expression) { - talloc_free(sctx); - return ENOMEM; - } - - return pwd_search(sctx, ctx, expression); -} - -int sysdb_enumpwent(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct sysdb_ctx *ctx, - const char *domain, - bool legacy, - sysdb_callback_t fn, void *ptr) -{ - struct sysdb_search_ctx *sctx; - - if (!domain) { - return EINVAL; - } - - sctx = init_src_ctx(mem_ctx, domain, legacy, ctx, fn, ptr); - if (!sctx) { - return ENOMEM; - } - - return pwd_search(sctx, ctx, SYSDB_PWENT_FILTER); -} - -/* groups */ - -struct get_mem_ctx { - struct sysdb_search_ctx *ret_sctx; - struct ldb_message **grps; - int num_grps; -}; - -static void get_members(void *ptr, int status, struct ldb_result *res) -{ - struct sysdb_ctx *ctx; - struct sysdb_search_ctx *sctx; - struct get_mem_ctx *gmctx; - struct sysdb_search_ctx *mem_sctx; - struct ldb_request *req; - struct ldb_message *msg; - struct ldb_result *ret_res; - struct ldb_dn *dn; - static const char *attrs[] = SYSDB_GRPW_ATTRS; - const char *expression; - int ret, i; - - sctx = talloc_get_type(ptr, struct sysdb_search_ctx); - gmctx = talloc_get_type(sctx->ptr, struct get_mem_ctx); - ctx = sctx->dbctx; - - if (status != LDB_SUCCESS) { - return request_error(gmctx->ret_sctx, status); - } - - ret_res = gmctx->ret_sctx->res; - - /* append previous search results to final (if any) */ - if (res && res->count != 0) { - ret_res->msgs = talloc_realloc(ret_res, ret_res->msgs, - struct ldb_message *, - ret_res->count + res->count + 1); - for(i = 0; i < res->count; i++) { - ret_res->msgs[ret_res->count] = talloc_steal(ret_res, res->msgs[i]); - ret_res->count++; - } - ret_res->msgs[ret_res->count] = NULL; - } - - if (gmctx->grps[0] == NULL) { - return request_done(gmctx->ret_sctx); - } - - mem_sctx = init_src_ctx(gmctx, sctx->domain, sctx->legacy, - ctx, get_members, sctx); - if (!mem_sctx) { - return request_error(gmctx->ret_sctx, LDB_ERR_OPERATIONS_ERROR); - } - - /* fetch next group to search for members */ - gmctx->num_grps--; - msg = gmctx->grps[gmctx->num_grps]; - gmctx->grps[gmctx->num_grps] = NULL; - - /* queue the group entry on the final result structure */ - ret_res->msgs = talloc_realloc(ret_res, ret_res->msgs, - struct ldb_message *, - ret_res->count + 2); - if (!ret_res->msgs) { - return request_error(gmctx->ret_sctx, LDB_ERR_OPERATIONS_ERROR); - } - ret_res->msgs[ret_res->count + 1] = NULL; - ret_res->msgs[ret_res->count] = talloc_steal(ret_res->msgs, msg); - ret_res->count++; - - /* search for this group members */ - expression = talloc_asprintf(mem_sctx, SYSDB_GRNA2_FILTER, - ldb_dn_get_linearized(msg->dn)); - if (!expression) { - return request_error(gmctx->ret_sctx, LDB_ERR_OPERATIONS_ERROR); - } - - dn = ldb_dn_new_fmt(mem_sctx, ctx->ldb, - SYSDB_TMPL_USER_BASE, sctx->domain); - if (!dn) { - return request_error(gmctx->ret_sctx, LDB_ERR_OPERATIONS_ERROR); - } - - ret = ldb_build_search_req(&req, ctx->ldb, mem_sctx, - dn, LDB_SCOPE_SUBTREE, - expression, attrs, NULL, - mem_sctx, get_gen_callback, - NULL); - if (ret != LDB_SUCCESS) { - return request_error(gmctx->ret_sctx, ret); - } - - ret = ldb_request(ctx->ldb, req); - if (ret != LDB_SUCCESS) { - return request_error(gmctx->ret_sctx, ret); - } -} - -static int get_grp_callback(struct ldb_request *req, - struct ldb_reply *ares) -{ - struct sysdb_search_ctx *sctx; - struct sysdb_ctx *ctx; - struct ldb_result *res; - int n; - - sctx = talloc_get_type(req->context, struct sysdb_search_ctx); - ctx = sctx->dbctx; - res = sctx->res; - - if (!ares) { - request_error(sctx, LDB_ERR_OPERATIONS_ERROR); - return LDB_ERR_OPERATIONS_ERROR; - } - if (ares->error != LDB_SUCCESS) { - request_error(sctx, ares->error); - return ares->error; - } - - switch (ares->type) { - case LDB_REPLY_ENTRY: - res->msgs = talloc_realloc(res, res->msgs, - struct ldb_message *, - res->count + 2); - if (!res->msgs) { - request_error(sctx, LDB_ERR_OPERATIONS_ERROR); - return LDB_ERR_OPERATIONS_ERROR; - } - - res->msgs[res->count + 1] = NULL; - - res->msgs[res->count] = talloc_steal(res->msgs, ares->message); - res->count++; - break; - - case LDB_REPLY_REFERRAL: - if (res->refs) { - for (n = 0; res->refs[n]; n++) /*noop*/ ; - } else { - n = 0; - } - - res->refs = talloc_realloc(res, res->refs, char *, n + 2); - if (! res->refs) { - request_error(sctx, LDB_ERR_OPERATIONS_ERROR); - return LDB_ERR_OPERATIONS_ERROR; - } - - res->refs[n] = talloc_steal(res->refs, ares->referral); - res->refs[n + 1] = NULL; - break; - - case LDB_REPLY_DONE: - res->controls = talloc_steal(res, ares->controls); - - /* no results, return */ - if (res->count == 0) { - request_done(sctx); - return LDB_SUCCESS; - } - if (res->count > 0) { - struct get_mem_ctx *gmctx; - - gmctx = talloc_zero(req, struct get_mem_ctx); - if (!gmctx) { - request_error(sctx, LDB_ERR_OPERATIONS_ERROR); - return LDB_ERR_OPERATIONS_ERROR; - } - gmctx->ret_sctx = sctx; - gmctx->grps = talloc_steal(gmctx, res->msgs); - gmctx->num_grps = res->count; - res->msgs = NULL; - res->count = 0; - - /* re-use sctx to create a fake handler for the first call to - * get_members() */ - sctx = init_src_ctx(gmctx, - sctx->domain, sctx->legacy, - ctx, get_members, gmctx); - - get_members(sctx, LDB_SUCCESS, NULL); - return LDB_SUCCESS; - } - - /* anything else is an error */ - request_error(sctx, LDB_ERR_OPERATIONS_ERROR); - return LDB_ERR_OPERATIONS_ERROR; - } - - talloc_free(ares); - return LDB_SUCCESS; -} - -static int grp_search(struct sysdb_search_ctx *sctx, - struct sysdb_ctx *ctx, - const char *expression) -{ - ldb_request_callback_t callback; - static const char *attrs[] = SYSDB_GRNAM_ATTRS; - struct ldb_request *req; - struct ldb_dn *base_dn; - int ret; - - if (sctx->legacy) { - callback = get_gen_callback; - } else { - callback = get_grp_callback; - } - - base_dn = ldb_dn_new_fmt(sctx, ctx->ldb, - SYSDB_TMPL_GROUP_BASE, sctx->domain); - if (!base_dn) { - return ENOMEM; - } - - ret = ldb_build_search_req(&req, ctx->ldb, sctx, - base_dn, LDB_SCOPE_SUBTREE, - expression, attrs, NULL, - sctx, callback, - NULL); - if (ret != LDB_SUCCESS) { - return sysdb_error_to_errno(ret); - } - - ret = ldb_request(ctx->ldb, req); - if (ret != LDB_SUCCESS) { - return sysdb_error_to_errno(ret); - } - - return EOK; -} - -int sysdb_getgrnam(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct sysdb_ctx *ctx, - const char *domain, - const char *name, - bool legacy, - sysdb_callback_t fn, void *ptr) -{ - struct sysdb_search_ctx *sctx; - char *expression; - - if (!domain) { - return EINVAL; - } - - sctx = init_src_ctx(mem_ctx, domain, legacy, ctx, fn, ptr); - if (!sctx) { - return ENOMEM; - } - - expression = talloc_asprintf(sctx, SYSDB_GRNAM_FILTER, name); - if (!expression) { - talloc_free(sctx); - return ENOMEM; - } - - return grp_search(sctx, ctx, expression); -} - -int sysdb_getgrgid(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct sysdb_ctx *ctx, - const char *domain, - gid_t gid, - bool legacy, - sysdb_callback_t fn, void *ptr) -{ - struct sysdb_search_ctx *sctx; - unsigned long int filter_gid = gid; - char *expression; - - if (!domain) { - return EINVAL; - } - - sctx = init_src_ctx(mem_ctx, domain, legacy, ctx, fn, ptr); - if (!sctx) { - return ENOMEM; - } - - expression = talloc_asprintf(sctx, SYSDB_GRGID_FILTER, filter_gid); - if (!expression) { - talloc_free(sctx); - return ENOMEM; - } - - return grp_search(sctx, ctx, expression); -} - -int sysdb_enumgrent(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct sysdb_ctx *ctx, - const char *domain, - bool legacy, - sysdb_callback_t fn, void *ptr) -{ - struct sysdb_search_ctx *sctx; - - if (!domain) { - return EINVAL; - } - - sctx = init_src_ctx(mem_ctx, domain, legacy, ctx, fn, ptr); - if (!sctx) { - return ENOMEM; - } - - return grp_search(sctx, ctx, SYSDB_GRENT_FILTER); -} - -static void sysdb_initgr_legacy(void *ptr, int status, - struct ldb_result *res) -{ - struct sysdb_ctx *ctx; - struct sysdb_search_ctx *sctx; - char *expression; - struct ldb_request *req; - struct ldb_dn *base_dn; - static const char *attrs[] = SYSDB_INITGR_ATTRS; - const char *userid; - int ret; - - sctx = talloc_get_type(ptr, struct sysdb_search_ctx); - ctx = sctx->dbctx; - - if (res->count == 0) { - return request_done(sctx); - } - if (res->count > 1) { - return request_error(sctx, LDB_ERR_OPERATIONS_ERROR); - } - - userid = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_PW_NAME, NULL); - if (!userid) { - return request_error(sctx, LDB_ERR_OPERATIONS_ERROR); - } - - expression = talloc_asprintf(sctx, SYSDB_INITGR_LEGACY_FILTER, userid); - if (!expression) { - return request_error(sctx, LDB_ERR_OPERATIONS_ERROR); - } - - base_dn = ldb_dn_new_fmt(sctx, ctx->ldb, - SYSDB_TMPL_GROUP_BASE, sctx->domain); - if (!base_dn) { - return request_error(sctx, LDB_ERR_OPERATIONS_ERROR); - } - - ret = ldb_build_search_req(&req, ctx->ldb, sctx, - base_dn, LDB_SCOPE_SUBTREE, - expression, attrs, NULL, - sctx, get_gen_callback, - NULL); - if (ret != LDB_SUCCESS) { - return request_error(sctx, ret); - } - - ret = ldb_request(ctx->ldb, req); - if (ret != LDB_SUCCESS) { - return request_error(sctx, ret); - } -} - -static void sysdb_initgr_search(void *ptr, int status, - struct ldb_result *res) -{ - struct sysdb_ctx *ctx; - struct sysdb_search_ctx *sctx; - char *expression; - struct ldb_request *req; - struct ldb_control **ctrl; - struct ldb_asq_control *control; - static const char *attrs[] = SYSDB_INITGR_ATTRS; - int ret; - - sctx = talloc_get_type(ptr, struct sysdb_search_ctx); - ctx = sctx->dbctx; - - if (res->count == 0) { - return request_done(sctx); - } - if (res->count > 1) { - return request_error(sctx, LDB_ERR_OPERATIONS_ERROR); - } - - expression = talloc_asprintf(sctx, SYSDB_INITGR_FILTER); - if (!expression) { - return request_error(sctx, LDB_ERR_OPERATIONS_ERROR); - } - - ctrl = talloc_array(sctx, struct ldb_control *, 2); - if (!ctrl) { - return request_error(sctx, LDB_ERR_OPERATIONS_ERROR); - } - ctrl[1] = NULL; - ctrl[0] = talloc(ctrl, struct ldb_control); - if (!ctrl[0]) { - return request_error(sctx, LDB_ERR_OPERATIONS_ERROR); - } - ctrl[0]->oid = LDB_CONTROL_ASQ_OID; - ctrl[0]->critical = 1; - control = talloc(ctrl[0], struct ldb_asq_control); - if (!control) { - return request_error(sctx, LDB_ERR_OPERATIONS_ERROR); - } - control->request = 1; - control->source_attribute = talloc_strdup(control, SYSDB_INITGR_ATTR); - if (!control->source_attribute) { - return request_error(sctx, LDB_ERR_OPERATIONS_ERROR); - } - control->src_attr_len = strlen(control->source_attribute); - ctrl[0]->data = control; - - ret = ldb_build_search_req(&req, ctx->ldb, sctx, - res->msgs[0]->dn, - LDB_SCOPE_BASE, - expression, attrs, ctrl, - sctx, get_gen_callback, - NULL); - if (ret != LDB_SUCCESS) { - return request_error(sctx, ret); - } - - ret = ldb_request(ctx->ldb, req); - if (ret != LDB_SUCCESS) { - return request_error(sctx, ret); - } -} - -int sysdb_initgroups(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct sysdb_ctx *ctx, - const char *domain, - const char *name, - bool legacy, - sysdb_callback_t fn, void *ptr) -{ - sysdb_callback_t second_callback; - static const char *attrs[] = SYSDB_PW_ATTRS; - struct sysdb_search_ctx *ret_sctx; - struct sysdb_search_ctx *sctx; - char *expression; - struct ldb_request *req; - struct ldb_dn *base_dn; - int ret; - - if (!domain) { - return EINVAL; - } - - ret_sctx = init_src_ctx(mem_ctx, domain, legacy, ctx, fn, ptr); - if (!ret_sctx) { - return ENOMEM; - } - - if (legacy) { - second_callback = sysdb_initgr_legacy; - } else { - second_callback = sysdb_initgr_search; - } - - sctx = init_src_ctx(ret_sctx, domain, legacy, - ctx, second_callback, ret_sctx); - if (!sctx) { - talloc_free(ret_sctx); - return ENOMEM; - } - - expression = talloc_asprintf(sctx, SYSDB_PWNAM_FILTER, name); - if (!expression) { - talloc_free(ret_sctx); - return ENOMEM; - } - - base_dn = ldb_dn_new_fmt(sctx, ctx->ldb, SYSDB_TMPL_USER_BASE, domain); - if (!base_dn) { - talloc_free(ret_sctx); - return ENOMEM; - } - - ret = ldb_build_search_req(&req, ctx->ldb, sctx, - base_dn, LDB_SCOPE_SUBTREE, - expression, attrs, NULL, - sctx, get_gen_callback, - NULL); - if (ret != LDB_SUCCESS) { - return sysdb_error_to_errno(ret); - } - - ret = ldb_request(ctx->ldb, req); - if (ret != LDB_SUCCESS) { - return sysdb_error_to_errno(ret); - } - - return LDB_SUCCESS; -} +/************************************************ + * Initialiazation stuff + */ static int sysdb_read_var(TALLOC_CTX *mem_ctx, struct confdb_ctx *cdb, @@ -896,15 +166,18 @@ int sysdb_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct confdb_ctx *cdb, const char *alt_db_path, - struct sysdb_ctx **dbctx) + struct sysdb_ctx **_ctx) { struct sysdb_ctx *ctx; int ret; + if (!ev) return EINVAL; + ctx = talloc_zero(mem_ctx, struct sysdb_ctx); if (!ctx) { return ENOMEM; } + ctx->ev = ev; if (!alt_db_path) { ret = sysdb_get_db_path(ctx, cdb, &ctx->ldb_file); @@ -938,7 +211,7 @@ int sysdb_init(TALLOC_CTX *mem_ctx, return ret; } - *dbctx = ctx; + *_ctx = ctx; return EOK; } diff --git a/server/db/sysdb.h b/server/db/sysdb.h index c6cc4deb..c0ef361b 100644 --- a/server/db/sysdb.h +++ b/server/db/sysdb.h @@ -23,7 +23,6 @@ #define __SYS_DB_H__ #include "ldb.h" -#include "ldb_errors.h" #define SYSDB_CONF_SECTION "config/sysdb" #define SYSDB_FILE "sssd.ldb" @@ -77,12 +76,8 @@ #define SYSDB_INITGR_ATTRS {SYSDB_GR_GIDNUM, SYSDB_LAST_UPDATE, \ NULL} -struct sysdb_ctx { - struct ldb_context *ldb; - char *ldb_file; -}; - struct confdb_ctx; +struct sysdb_ctx; typedef void (*sysdb_callback_t)(void *, int, struct ldb_result *); @@ -93,7 +88,6 @@ int sysdb_init(TALLOC_CTX *mem_ctx, struct sysdb_ctx **dbctx); int sysdb_getpwnam(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, struct sysdb_ctx *ctx, const char *domain, const char *name, @@ -101,7 +95,6 @@ int sysdb_getpwnam(TALLOC_CTX *mem_ctx, sysdb_callback_t fn, void *ptr); int sysdb_getpwuid(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, struct sysdb_ctx *ctx, const char *domain, uid_t uid, @@ -109,14 +102,12 @@ int sysdb_getpwuid(TALLOC_CTX *mem_ctx, sysdb_callback_t fn, void *ptr); int sysdb_enumpwent(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, struct sysdb_ctx *ctx, const char *domain, bool legacy, sysdb_callback_t fn, void *ptr); int sysdb_getgrnam(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, struct sysdb_ctx *ctx, const char *domain, const char *name, @@ -124,7 +115,6 @@ int sysdb_getgrnam(TALLOC_CTX *mem_ctx, sysdb_callback_t fn, void *ptr); int sysdb_getgrgid(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, struct sysdb_ctx *ctx, const char *domain, gid_t gid, @@ -132,14 +122,12 @@ int sysdb_getgrgid(TALLOC_CTX *mem_ctx, sysdb_callback_t fn, void *ptr); int sysdb_enumgrent(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, struct sysdb_ctx *ctx, const char *domain, bool legacy, sysdb_callback_t fn, void *ptr); int sysdb_initgroups(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, struct sysdb_ctx *ctx, const char *domain, const char *name, diff --git a/server/db/sysdb_internal.h b/server/db/sysdb_internal.h deleted file mode 100644 index 719f6606..00000000 --- a/server/db/sysdb_internal.h +++ /dev/null @@ -1,70 +0,0 @@ - -/* - SSSD - - Private System Database Header - - 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 __INT_SYS_DB_H__ -#define __INT_SYS_DB_H__ - -#define SYSDB_VERSION "0.1" - -#define SYSDB_BASE_LDIF \ - "dn: @ATTRIBUTES\n" \ - "userPrincipalName: CASE_INSENSITIVE\n" \ - "cn: CASE_INSENSITIVE\n" \ - "dc: CASE_INSENSITIVE\n" \ - "dn: CASE_INSENSITIVE\n" \ - "name: CASE_INSENSITIVE\n" \ - "objectclass: CASE_INSENSITIVE\n" \ - "\n" \ - "dn: @INDEXLIST\n" \ - "@IDXATTR: cn\n" \ - "@IDXATTR: objectclass\n" \ - "@IDXATTR: member\n" \ - "@IDXATTR: memberof\n" \ - "@IDXATTR: memberuid\n" \ - "@IDXATTR: uid\n" \ - "@IDXATTR: gid\n" \ - "@IDXATTR: uidNumber\n" \ - "@IDXATTR: gidNumber\n" \ - "@IDXATTR: lastUpdate\n" \ - "\n" \ - "dn: @MODULES\n" \ - "@LIST: asq,memberof\n" \ - "\n" \ - "dn: cn=sysdb\n" \ - "cn: sysdb\n" \ - "version: 0.1\n" \ - "description: base object\n" \ - "\n" \ - "dn: cn=LOCAL,cn=sysdb\n" \ - "cn: local\n" \ - "description: Local system data\n" \ - "\n" \ - "dn: cn=Users,cn=LOCAL,cn=sysdb\n" \ - "cn: users\n" \ - "description: Local POSIX users\n" \ - "\n" \ - "dn: cn=Groups,cn=LOCAL,cn=sysdb\n" \ - "cn: groups\n" \ - "description: Local POSIX groups\n" \ - "\n" - -#endif /* __INT_SYS_DB_H__ */ diff --git a/server/db/sysdb_private.h b/server/db/sysdb_private.h new file mode 100644 index 00000000..c649af4a --- /dev/null +++ b/server/db/sysdb_private.h @@ -0,0 +1,95 @@ + +/* + SSSD + + Private System Database Header + + 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 __INT_SYS_DB_H__ +#define __INT_SYS_DB_H__ + +#define SYSDB_VERSION "0.1" + +#define SYSDB_BASE_LDIF \ + "dn: @ATTRIBUTES\n" \ + "userPrincipalName: CASE_INSENSITIVE\n" \ + "cn: CASE_INSENSITIVE\n" \ + "dc: CASE_INSENSITIVE\n" \ + "dn: CASE_INSENSITIVE\n" \ + "name: CASE_INSENSITIVE\n" \ + "objectclass: CASE_INSENSITIVE\n" \ + "\n" \ + "dn: @INDEXLIST\n" \ + "@IDXATTR: cn\n" \ + "@IDXATTR: objectclass\n" \ + "@IDXATTR: member\n" \ + "@IDXATTR: memberof\n" \ + "@IDXATTR: memberuid\n" \ + "@IDXATTR: uid\n" \ + "@IDXATTR: gid\n" \ + "@IDXATTR: uidNumber\n" \ + "@IDXATTR: gidNumber\n" \ + "@IDXATTR: lastUpdate\n" \ + "\n" \ + "dn: @MODULES\n" \ + "@LIST: asq,memberof\n" \ + "\n" \ + "dn: cn=sysdb\n" \ + "cn: sysdb\n" \ + "version: 0.1\n" \ + "description: base object\n" \ + "\n" \ + "dn: cn=LOCAL,cn=sysdb\n" \ + "cn: local\n" \ + "description: Local system data\n" \ + "\n" \ + "dn: cn=Users,cn=LOCAL,cn=sysdb\n" \ + "cn: users\n" \ + "description: Local POSIX users\n" \ + "\n" \ + "dn: cn=Groups,cn=LOCAL,cn=sysdb\n" \ + "cn: groups\n" \ + "description: Local POSIX groups\n" \ + "\n" + +#include "db/sysdb.h" + +struct sysdb_req; + +struct sysdb_ctx { + struct tevent_context *ev; + struct ldb_context *ldb; + char *ldb_file; + struct sysdb_req *queue; +}; + +typedef void (*sysdb_req_fn_t)(struct sysdb_req *, void *pvt); + +int sysdb_error_to_errno(int ldberr); + +int sysdb_transaction(TALLOC_CTX *mem_ctx, + struct sysdb_ctx *ctx, + sysdb_req_fn_t fn, void *pvt); +void sysdb_transaction_done(struct sysdb_req *req, int status); + +int sysdb_operation(TALLOC_CTX *mem_ctx, + struct sysdb_ctx *ctx, + sysdb_req_fn_t fn, void *pvt); +void sysdb_operation_done(struct sysdb_req *req); + +#endif /* __INT_SYS_DB_H__ */ diff --git a/server/db/sysdb_req.c b/server/db/sysdb_req.c new file mode 100644 index 00000000..fcbd17b8 --- /dev/null +++ b/server/db/sysdb_req.c @@ -0,0 +1,241 @@ +/* + SSSD + + System Database + + Copyright (C) Simo Sorce 2009 + + 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 "util/util.h" +#include "util/dlinklist.h" +#include "db/sysdb_private.h" +#include "ldb.h" + +struct sysdb_req { + struct sysdb_req *next, *prev; + struct sysdb_ctx *ctx; + sysdb_req_fn_t fn; + void *pvt; + int status; + bool transaction_active; +}; + +static void sysdb_req_run(struct tevent_context *ev, + struct tevent_timer *te, + struct timeval tv, void *ptr) +{ + struct sysdb_req *req = talloc_get_type(ptr, struct sysdb_req); + + if (req != req->ctx->queue) abort(); + + req->fn(req, req->pvt); +} + +static int sysdb_req_schedule(struct sysdb_req *req) +{ + struct tevent_timer *te = NULL; + struct timeval tv; + + /* call it asap */ + tv.tv_sec = 0; + tv.tv_usec = 0; + + te = tevent_add_timer(req->ctx->ev, req, tv, sysdb_req_run, req); + if (te == NULL) { + return EIO; + } + + return EOK; +} + +static int sysdb_req_enqueue(struct sysdb_req *req) +{ + int ret = EOK; + + DLIST_ADD_END(req->ctx->queue, req, struct sysdb_req *); + + if (req->ctx->queue == req) { + ret = sysdb_req_schedule(req); + } + + return ret; +} + +static void sysdb_transaction_end(struct sysdb_req *req); + +static int sysdb_req_destructor(void *ptr) +{ + struct sysdb_req *req; + int ret; + + req = talloc_get_type(ptr, struct sysdb_req); + + if (req->ctx->queue != req) { + DLIST_REMOVE(req->ctx->queue, req); + return 0; + } + + /* req is the currently running operation or + * scheduled to run operation */ + + if (req->transaction_active) { + /* freeing before the transaction is complete */ + req->status = ETIMEDOUT; + sysdb_transaction_end(req); + } + + DLIST_REMOVE(req->ctx->queue, req); + + /* make sure we schedule the next in line if any */ + if (req->ctx->queue) { + ret = sysdb_req_schedule(req->ctx->queue); + if (ret != EOK) abort(); + } + + return 0; +} + +static struct sysdb_req *sysdb_new_req(TALLOC_CTX *memctx, + struct sysdb_ctx *ctx, + sysdb_req_fn_t fn, void *pvt) +{ + struct sysdb_req *req; + + req = talloc_zero(memctx, struct sysdb_req); + if (!req) return NULL; + + req->ctx = ctx; + req->fn = fn; + req->pvt = pvt; + + talloc_set_destructor((TALLOC_CTX *)req, sysdb_req_destructor); + + return req; +} + +static void sysdb_transaction_int(struct sysdb_req *intreq, void *pvt) +{ + struct sysdb_req *req = talloc_get_type(pvt, struct sysdb_req); + int ret; + + /* first of all swap this internal request with the real one on the queue + * otherwise request_done() will later abort */ + DLIST_REMOVE(req->ctx->queue, intreq); + DLIST_ADD(req->ctx->queue, req); + + if (intreq->status != EOK) { + req->status = intreq->status; + req->fn(req, req->pvt); + return; + } + + ret = ldb_transaction_start(req->ctx->ldb); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Failed to start ldb transaction! (%d)\n", ret)); + req->status = sysdb_error_to_errno(ret); + } + req->transaction_active = true; + + req->fn(req, req->pvt); +} + +static void sysdb_transaction_end(struct sysdb_req *req) +{ + int ret; + + if (req->status == EOK) { + ret = ldb_transaction_commit(req->ctx->ldb); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Failed to commit ldb transaction! (%d)\n", ret)); + } + } else { + DEBUG(4, ("Canceling transaction (%d[%s)\n", + req->status, strerror(req->status))); + ret = ldb_transaction_cancel(req->ctx->ldb); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Failed to cancel ldb transaction! (%d)\n", ret)); + /* FIXME: abort() ? */ + } + } + req->transaction_active = false; +} + +int sysdb_transaction(TALLOC_CTX *memctx, struct sysdb_ctx *ctx, + sysdb_req_fn_t fn, void *pvt) +{ + struct sysdb_req *req, *intreq; + + req = sysdb_new_req(memctx, ctx, fn, pvt); + if (!req) return ENOMEM; + + intreq = sysdb_new_req(req, ctx, sysdb_transaction_int, req); + if (!intreq) { + talloc_free(intreq); + return ENOMEM; + } + + return sysdb_req_enqueue(intreq); +} + +void sysdb_transaction_done(struct sysdb_req *req, int status) +{ + int ret; + + if (req->ctx->queue != req) abort(); + if (!req->transaction_active) abort(); + + req->status = status; + + sysdb_transaction_end(req); + + DLIST_REMOVE(req->ctx->queue, req); + + if (req->ctx->queue) { + ret = sysdb_req_schedule(req->ctx->queue); + if (ret != EOK) abort(); + } + + talloc_free(req); +} + +int sysdb_operation(TALLOC_CTX *memctx, struct sysdb_ctx *ctx, + sysdb_req_fn_t fn, void *pvt) +{ + struct sysdb_req *req; + + req = sysdb_new_req(memctx, ctx, fn, pvt); + if (!req) return ENOMEM; + + return sysdb_req_enqueue(req); +} + +void sysdb_operation_done(struct sysdb_req *req) +{ + int ret; + + if (req->ctx->queue != req) abort(); + + DLIST_REMOVE(req->ctx->queue, req); + + if (req->ctx->queue) { + ret = sysdb_req_schedule(req->ctx->queue); + if (ret != EOK) abort(); + } + + talloc_free(req); +} + diff --git a/server/db/sysdb_search.c b/server/db/sysdb_search.c new file mode 100644 index 00000000..5a355a0f --- /dev/null +++ b/server/db/sysdb_search.c @@ -0,0 +1,731 @@ +/* + SSSD + + System Database + + 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 "util/util.h" +#include "db/sysdb_private.h" +#include "confdb/confdb.h" +#include + +struct sysdb_search_ctx; + +typedef void (*gen_callback)(struct sysdb_search_ctx *); + +struct sysdb_search_ctx { + struct sysdb_ctx *ctx; + struct sysdb_req *req; + + const char *expression; + const char *domain; + bool legacy; + + sysdb_callback_t callback; + void *ptr; + + gen_callback gen_aux_fn; + + struct get_mem_ctx *gmctx; + + struct ldb_result *res; +}; + +static struct sysdb_search_ctx *init_src_ctx(TALLOC_CTX *mem_ctx, + const char *domain, + bool legacy, + struct sysdb_ctx *ctx, + sysdb_callback_t fn, + void *ptr) +{ + struct sysdb_search_ctx *sctx; + + sctx = talloc_zero(mem_ctx, struct sysdb_search_ctx); + if (!sctx) { + return NULL; + } + sctx->ctx = ctx; + sctx->callback = fn; + sctx->ptr = ptr; + sctx->res = talloc_zero(sctx, struct ldb_result); + if (!sctx->res) { + talloc_free(sctx); + return NULL; + } + sctx->domain = talloc_strdup(sctx, domain); + if (!sctx->domain) { + talloc_free(sctx); + return NULL; + } + sctx->legacy = legacy; + + return sctx; +} + +int sysdb_error_to_errno(int ldberr) +{ + /* fake it up for now, requires a mapping table */ + return EIO; +} + +static void request_ldberror(struct sysdb_search_ctx *sctx, int error) +{ + sysdb_operation_done(sctx->req); + sctx->callback(sctx->ptr, sysdb_error_to_errno(error), NULL); +} + +static void request_error(struct sysdb_search_ctx *sctx, int error) +{ + sysdb_operation_done(sctx->req); + sctx->callback(sctx->ptr, error, NULL); +} + +static void request_done(struct sysdb_search_ctx *sctx) +{ + sysdb_operation_done(sctx->req); + sctx->callback(sctx->ptr, EOK, sctx->res); +} + +static int get_gen_callback(struct ldb_request *req, + struct ldb_reply *ares) +{ + struct sysdb_search_ctx *sctx; + struct ldb_result *res; + int n; + + sctx = talloc_get_type(req->context, struct sysdb_search_ctx); + res = sctx->res; + + if (!ares) { + request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR); + return LDB_ERR_OPERATIONS_ERROR; + } + if (ares->error != LDB_SUCCESS) { + request_ldberror(sctx, ares->error); + return ares->error; + } + + switch (ares->type) { + case LDB_REPLY_ENTRY: + res->msgs = talloc_realloc(res, res->msgs, + struct ldb_message *, + res->count + 2); + if (!res->msgs) { + request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR); + return LDB_ERR_OPERATIONS_ERROR; + } + + res->msgs[res->count + 1] = NULL; + + res->msgs[res->count] = talloc_steal(res->msgs, ares->message); + res->count++; + break; + + case LDB_REPLY_REFERRAL: + if (res->refs) { + for (n = 0; res->refs[n]; n++) /*noop*/ ; + } else { + n = 0; + } + + res->refs = talloc_realloc(res, res->refs, char *, n + 2); + if (! res->refs) { + request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR); + return LDB_ERR_OPERATIONS_ERROR; + } + + res->refs[n] = talloc_steal(res->refs, ares->referral); + res->refs[n + 1] = NULL; + break; + + case LDB_REPLY_DONE: + res->controls = talloc_steal(res, ares->controls); + + /* check if we need to call any aux function */ + if (sctx->gen_aux_fn) { + sctx->gen_aux_fn(sctx); + } else { + /* no aux functions, this means the request is done */ + request_done(sctx); + } + return LDB_SUCCESS; + } + + talloc_free(ares); + return LDB_SUCCESS; +} + +/* users */ + +static void pwd_search(struct sysdb_req *sysreq, void *ptr) +{ + struct sysdb_search_ctx *sctx; + static const char *attrs[] = SYSDB_PW_ATTRS; + struct ldb_request *req; + struct ldb_dn *base_dn; + int ret; + + sctx = talloc_get_type(ptr, struct sysdb_search_ctx); + sctx->req = sysreq; + + base_dn = ldb_dn_new_fmt(sctx, sctx->ctx->ldb, + SYSDB_TMPL_USER_BASE, sctx->domain); + if (!base_dn) { + return request_error(sctx, ENOMEM); + } + + ret = ldb_build_search_req(&req, sctx->ctx->ldb, sctx, + base_dn, LDB_SCOPE_SUBTREE, + sctx->expression, attrs, NULL, + sctx, get_gen_callback, + NULL); + if (ret != LDB_SUCCESS) { + return request_ldberror(sctx, ret); + } + + ret = ldb_request(sctx->ctx->ldb, req); + if (ret != LDB_SUCCESS) { + return request_ldberror(sctx, ret); + } +} + +int sysdb_getpwnam(TALLOC_CTX *mem_ctx, + struct sysdb_ctx *ctx, + const char *domain, + const char *name, + bool legacy, + sysdb_callback_t fn, void *ptr) +{ + struct sysdb_search_ctx *sctx; + + if (!domain) { + return EINVAL; + } + + sctx = init_src_ctx(mem_ctx, domain, legacy, ctx, fn, ptr); + if (!sctx) { + return ENOMEM; + } + + sctx->expression = talloc_asprintf(sctx, SYSDB_PWNAM_FILTER, name); + if (!sctx->expression) { + talloc_free(sctx); + return ENOMEM; + } + + return sysdb_operation(mem_ctx, ctx, pwd_search, sctx); +} + +int sysdb_getpwuid(TALLOC_CTX *mem_ctx, + struct sysdb_ctx *ctx, + const char *domain, + uid_t uid, + bool legacy, + sysdb_callback_t fn, void *ptr) +{ + struct sysdb_search_ctx *sctx; + unsigned long int filter_uid = uid; + + if (!domain) { + return EINVAL; + } + + sctx = init_src_ctx(mem_ctx, domain, legacy, ctx, fn, ptr); + if (!sctx) { + return ENOMEM; + } + + sctx->expression = talloc_asprintf(sctx, SYSDB_PWUID_FILTER, filter_uid); + if (!sctx->expression) { + talloc_free(sctx); + return ENOMEM; + } + + return sysdb_operation(mem_ctx, ctx, pwd_search, sctx); +} + +int sysdb_enumpwent(TALLOC_CTX *mem_ctx, + struct sysdb_ctx *ctx, + const char *domain, + bool legacy, + sysdb_callback_t fn, void *ptr) +{ + struct sysdb_search_ctx *sctx; + + if (!domain) { + return EINVAL; + } + + sctx = init_src_ctx(mem_ctx, domain, legacy, ctx, fn, ptr); + if (!sctx) { + return ENOMEM; + } + + sctx->expression = SYSDB_PWENT_FILTER; + + return sysdb_operation(mem_ctx, ctx, pwd_search, sctx); +} + +/* groups */ + +struct get_mem_ctx { + struct sysdb_search_ctx *ret_sctx; + struct ldb_message **grps; + int num_grps; +}; + +static void get_members(struct sysdb_search_ctx *sctx) +{ + struct get_mem_ctx *gmctx; + struct ldb_request *req; + struct ldb_message *msg; + struct ldb_dn *dn; + static const char *attrs[] = SYSDB_GRPW_ATTRS; + int ret; + + gmctx = sctx->gmctx; + + if (gmctx->grps[0] == NULL) { + return request_done(sctx); + } + + /* fetch next group to search for members */ + gmctx->num_grps--; + msg = gmctx->grps[gmctx->num_grps]; + gmctx->grps[gmctx->num_grps] = NULL; + + /* queue the group entry on the final result structure */ + sctx->res->msgs = talloc_realloc(sctx->res, sctx->res->msgs, + struct ldb_message *, + sctx->res->count + 2); + if (!sctx->res->msgs) { + return request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR); + } + sctx->res->msgs[sctx->res->count + 1] = NULL; + sctx->res->msgs[sctx->res->count] = talloc_steal(sctx->res->msgs, msg); + sctx->res->count++; + + /* search for this group members */ + sctx->expression = talloc_asprintf(sctx, SYSDB_GRNA2_FILTER, + ldb_dn_get_linearized(msg->dn)); + if (!sctx->expression) { + return request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR); + } + + dn = ldb_dn_new_fmt(sctx, sctx->ctx->ldb, + SYSDB_TMPL_USER_BASE, sctx->domain); + if (!dn) { + return request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR); + } + + sctx->gen_aux_fn = get_members; + + ret = ldb_build_search_req(&req, sctx->ctx->ldb, sctx, + dn, LDB_SCOPE_SUBTREE, + sctx->expression, attrs, NULL, + sctx, get_gen_callback, + NULL); + if (ret != LDB_SUCCESS) { + return request_ldberror(sctx, ret); + } + + ret = ldb_request(sctx->ctx->ldb, req); + if (ret != LDB_SUCCESS) { + return request_ldberror(sctx, ret); + } +} + +static int get_grp_callback(struct ldb_request *req, + struct ldb_reply *ares) +{ + struct sysdb_search_ctx *sctx; + struct sysdb_ctx *ctx; + struct ldb_result *res; + int n; + + sctx = talloc_get_type(req->context, struct sysdb_search_ctx); + ctx = sctx->ctx; + res = sctx->res; + + if (!ares) { + request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR); + return LDB_ERR_OPERATIONS_ERROR; + } + if (ares->error != LDB_SUCCESS) { + request_ldberror(sctx, ares->error); + return ares->error; + } + + switch (ares->type) { + case LDB_REPLY_ENTRY: + res->msgs = talloc_realloc(res, res->msgs, + struct ldb_message *, + res->count + 2); + if (!res->msgs) { + request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR); + return LDB_ERR_OPERATIONS_ERROR; + } + + res->msgs[res->count + 1] = NULL; + + res->msgs[res->count] = talloc_steal(res->msgs, ares->message); + res->count++; + break; + + case LDB_REPLY_REFERRAL: + if (res->refs) { + for (n = 0; res->refs[n]; n++) /*noop*/ ; + } else { + n = 0; + } + + res->refs = talloc_realloc(res, res->refs, char *, n + 2); + if (! res->refs) { + request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR); + return LDB_ERR_OPERATIONS_ERROR; + } + + res->refs[n] = talloc_steal(res->refs, ares->referral); + res->refs[n + 1] = NULL; + break; + + case LDB_REPLY_DONE: + res->controls = talloc_steal(res, ares->controls); + + /* no results, return */ + if (res->count == 0) { + request_done(sctx); + return LDB_SUCCESS; + } + if (res->count > 0) { + + sctx->gmctx = talloc_zero(req, struct get_mem_ctx); + if (!sctx->gmctx) { + request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR); + return LDB_ERR_OPERATIONS_ERROR; + } + sctx->gmctx->grps = res->msgs; + sctx->gmctx->num_grps = res->count; + res->msgs = NULL; + res->count = 0; + + /* now get members */ + get_members(sctx); + return LDB_SUCCESS; + } + + /* anything else is an error */ + request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR); + return LDB_ERR_OPERATIONS_ERROR; + } + + talloc_free(ares); + return LDB_SUCCESS; +} + +static void grp_search(struct sysdb_req *sysreq, void *ptr) +{ + struct sysdb_search_ctx *sctx; + ldb_request_callback_t callback; + static const char *attrs[] = SYSDB_GRNAM_ATTRS; + struct ldb_request *req; + struct ldb_dn *base_dn; + int ret; + + sctx = talloc_get_type(ptr, struct sysdb_search_ctx); + sctx->req = sysreq; + + if (sctx->legacy) { + callback = get_gen_callback; + } else { + callback = get_grp_callback; + } + + base_dn = ldb_dn_new_fmt(sctx, sctx->ctx->ldb, + SYSDB_TMPL_GROUP_BASE, sctx->domain); + if (!base_dn) { + return request_error(sctx, ENOMEM); + } + + ret = ldb_build_search_req(&req, sctx->ctx->ldb, sctx, + base_dn, LDB_SCOPE_SUBTREE, + sctx->expression, attrs, NULL, + sctx, callback, + NULL); + if (ret != LDB_SUCCESS) { + return request_ldberror(sctx, ret); + } + + ret = ldb_request(sctx->ctx->ldb, req); + if (ret != LDB_SUCCESS) { + return request_ldberror(sctx, ret); + } +} + +int sysdb_getgrnam(TALLOC_CTX *mem_ctx, + struct sysdb_ctx *ctx, + const char *domain, + const char *name, + bool legacy, + sysdb_callback_t fn, void *ptr) +{ + struct sysdb_search_ctx *sctx; + + if (!domain) { + return EINVAL; + } + + sctx = init_src_ctx(mem_ctx, domain, legacy, ctx, fn, ptr); + if (!sctx) { + return ENOMEM; + } + + sctx->expression = talloc_asprintf(sctx, SYSDB_GRNAM_FILTER, name); + if (!sctx->expression) { + talloc_free(sctx); + return ENOMEM; + } + + return sysdb_operation(mem_ctx, ctx, grp_search, sctx); +} + +int sysdb_getgrgid(TALLOC_CTX *mem_ctx, + struct sysdb_ctx *ctx, + const char *domain, + gid_t gid, + bool legacy, + sysdb_callback_t fn, void *ptr) +{ + struct sysdb_search_ctx *sctx; + unsigned long int filter_gid = gid; + + if (!domain) { + return EINVAL; + } + + sctx = init_src_ctx(mem_ctx, domain, legacy, ctx, fn, ptr); + if (!sctx) { + return ENOMEM; + } + + sctx->expression = talloc_asprintf(sctx, SYSDB_GRGID_FILTER, filter_gid); + if (!sctx->expression) { + talloc_free(sctx); + return ENOMEM; + } + + return sysdb_operation(mem_ctx, ctx, grp_search, sctx); +} + +int sysdb_enumgrent(TALLOC_CTX *mem_ctx, + struct sysdb_ctx *ctx, + const char *domain, + bool legacy, + sysdb_callback_t fn, void *ptr) +{ + struct sysdb_search_ctx *sctx; + + if (!domain) { + return EINVAL; + } + + sctx = init_src_ctx(mem_ctx, domain, legacy, ctx, fn, ptr); + if (!sctx) { + return ENOMEM; + } + + sctx->expression = SYSDB_GRENT_FILTER; + + return sysdb_operation(mem_ctx, ctx, grp_search, sctx); +} + +static void initgr_mem_legacy(struct sysdb_search_ctx *sctx) +{ + struct sysdb_ctx *ctx = sctx->ctx; + struct ldb_result *res = sctx->res; + struct ldb_request *req; + struct ldb_dn *base_dn; + static const char *attrs[] = SYSDB_INITGR_ATTRS; + const char *userid; + int ret; + + if (res->count == 0) { + return request_done(sctx); + } + if (res->count > 1) { + return request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR); + } + + userid = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_PW_NAME, NULL); + if (!userid) { + return request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR); + } + + sctx->expression = talloc_asprintf(sctx, + SYSDB_INITGR_LEGACY_FILTER, userid); + if (!sctx->expression) { + return request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR); + } + + base_dn = ldb_dn_new_fmt(sctx, ctx->ldb, + SYSDB_TMPL_GROUP_BASE, sctx->domain); + if (!base_dn) { + return request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR); + } + + ret = ldb_build_search_req(&req, ctx->ldb, sctx, + base_dn, LDB_SCOPE_SUBTREE, + sctx->expression, attrs, NULL, + sctx, get_gen_callback, + NULL); + if (ret != LDB_SUCCESS) { + return request_ldberror(sctx, ret); + } + + ret = ldb_request(ctx->ldb, req); + if (ret != LDB_SUCCESS) { + return request_ldberror(sctx, ret); + } +} + +static void initgr_mem_search(struct sysdb_search_ctx *sctx) +{ + struct sysdb_ctx *ctx = sctx->ctx; + struct ldb_result *res = sctx->res; + struct ldb_request *req; + struct ldb_control **ctrl; + struct ldb_asq_control *control; + static const char *attrs[] = SYSDB_INITGR_ATTRS; + int ret; + + if (res->count == 0) { + return request_done(sctx); + } + if (res->count > 1) { + return request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR); + } + + sctx->expression = talloc_asprintf(sctx, SYSDB_INITGR_FILTER); + if (!sctx->expression) { + return request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR); + } + + ctrl = talloc_array(sctx, struct ldb_control *, 2); + if (!ctrl) { + return request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR); + } + ctrl[1] = NULL; + ctrl[0] = talloc(ctrl, struct ldb_control); + if (!ctrl[0]) { + return request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR); + } + ctrl[0]->oid = LDB_CONTROL_ASQ_OID; + ctrl[0]->critical = 1; + control = talloc(ctrl[0], struct ldb_asq_control); + if (!control) { + return request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR); + } + control->request = 1; + control->source_attribute = talloc_strdup(control, SYSDB_INITGR_ATTR); + if (!control->source_attribute) { + return request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR); + } + control->src_attr_len = strlen(control->source_attribute); + ctrl[0]->data = control; + + ret = ldb_build_search_req(&req, ctx->ldb, sctx, + res->msgs[0]->dn, + LDB_SCOPE_BASE, + sctx->expression, attrs, ctrl, + sctx, get_gen_callback, + NULL); + if (ret != LDB_SUCCESS) { + return request_ldberror(sctx, ret); + } + + ret = ldb_request(ctx->ldb, req); + if (ret != LDB_SUCCESS) { + return request_ldberror(sctx, ret); + } +} + +static void initgr_search(struct sysdb_req *sysreq, void *ptr) +{ + struct sysdb_search_ctx *sctx; + static const char *attrs[] = SYSDB_PW_ATTRS; + struct ldb_request *req; + struct ldb_dn *base_dn; + int ret; + + sctx = talloc_get_type(ptr, struct sysdb_search_ctx); + sctx->req = sysreq; + + if (sctx->legacy) { + sctx->gen_aux_fn = initgr_mem_legacy; + } else { + sctx->gen_aux_fn = initgr_mem_search; + } + + base_dn = ldb_dn_new_fmt(sctx, sctx->ctx->ldb, + SYSDB_TMPL_USER_BASE, sctx->domain); + if (!base_dn) { + return request_error(sctx, ENOMEM); + } + + ret = ldb_build_search_req(&req, sctx->ctx->ldb, sctx, + base_dn, LDB_SCOPE_SUBTREE, + sctx->expression, attrs, NULL, + sctx, get_gen_callback, + NULL); + if (ret != LDB_SUCCESS) { + return request_ldberror(sctx, ret); + } + + ret = ldb_request(sctx->ctx->ldb, req); + if (ret != LDB_SUCCESS) { + return request_ldberror(sctx, ret); + } +} + +int sysdb_initgroups(TALLOC_CTX *mem_ctx, + struct sysdb_ctx *ctx, + const char *domain, + const char *name, + bool legacy, + sysdb_callback_t fn, void *ptr) +{ + struct sysdb_search_ctx *sctx; + + if (!domain) { + return EINVAL; + } + + sctx = init_src_ctx(mem_ctx, domain, legacy, ctx, fn, ptr); + if (!sctx) { + return ENOMEM; + } + + sctx->expression = talloc_asprintf(sctx, SYSDB_PWNAM_FILTER, name); + if (!sctx->expression) { + talloc_free(sctx); + return ENOMEM; + } + + return sysdb_operation(mem_ctx, ctx, initgr_search, sctx); +} + diff --git a/server/db/sysdb_sync.c b/server/db/sysdb_sync.c index f2c992fc..1910e9fc 100644 --- a/server/db/sysdb_sync.c +++ b/server/db/sysdb_sync.c @@ -20,7 +20,7 @@ */ #include "util/util.h" -#include "db/sysdb.h" +#include "db/sysdb_private.h" #include /* the following are all SYNCHRONOUS calls diff --git a/server/responder/nss/nsssrv.c b/server/responder/nss/nsssrv.c index 0c5fd4cc..2fbe3970 100644 --- a/server/responder/nss/nsssrv.c +++ b/server/responder/nss/nsssrv.c @@ -397,7 +397,15 @@ failed: * only ASCII names for now */ static int _domain_comparator(const void *key1, const void *key2) { - return strcasecmp((const char *)key1, (const char *)key2); + int ret; + + ret = strcasecmp((const char *)key1, (const char *)key2); + if (ret) { + /* special case LOCAL to be always the first domain */ + if (strcmp(key1, "LOCAL") == 0) return 1; + if (strcmp(key2, "LOCAL") == 0) return -1; + } + return ret; } static int nss_init_domains(struct nss_ctx *nctx) diff --git a/server/responder/nss/nsssrv_cmd.c b/server/responder/nss/nsssrv_cmd.c index c61eb4f2..16146585 100644 --- a/server/responder/nss/nsssrv_cmd.c +++ b/server/responder/nss/nsssrv_cmd.c @@ -97,6 +97,9 @@ static int nss_parse_name(struct nss_dom_ctx *dctx, const char *fullname) char *delim; char *domain; + /* TODO: add list of names to filter to configuration */ + if (strcmp(fullname, "root") == 0) return ECANCELED; + domain_map = nctx->domain_map; if ((delim = strchr(fullname, NSS_DOMAIN_DELIM)) != NULL) { @@ -367,7 +370,7 @@ static void nss_cmd_getpwnam_dp_callback(uint16_t err_maj, uint32_t err_min, (unsigned int)err_maj, (unsigned int)err_min, err_msg)); } - ret = sysdb_getpwnam(cmdctx, cctx->ev, cctx->nctx->sysdb, + ret = sysdb_getpwnam(cmdctx, cctx->nctx->sysdb, dctx->domain, cmdctx->name, dctx->legacy, nss_cmd_getpwnam_callback, dctx); @@ -386,6 +389,7 @@ static int nss_cmd_getpwnam(struct cli_ctx *cctx) { struct nss_cmd_ctx *cmdctx; struct nss_dom_ctx *dctx; + const char *rawname; uint8_t *body; size_t blen; int ret; @@ -407,23 +411,27 @@ static int nss_cmd_getpwnam(struct cli_ctx *cctx) talloc_free(cmdctx); return EINVAL; } + rawname = (const char *)body; - ret = nss_parse_name(dctx, (const char *)body); + ret = nss_parse_name(dctx, rawname); if (ret != EOK) { - DEBUG(1, ("Invalid name received\n")); - talloc_free(cmdctx); - return ret; + DEBUG(2, ("Invalid name received [%s]\n", rawname)); + goto done; } DEBUG(4, ("Requesting info for [%s] from [%s]\n", cmdctx->name, dctx->domain)); - ret = sysdb_getpwnam(cmdctx, cctx->ev, cctx->nctx->sysdb, + ret = sysdb_getpwnam(cmdctx, cctx->nctx->sysdb, dctx->domain, cmdctx->name, dctx->legacy, nss_cmd_getpwnam_callback, dctx); + if (ret != EOK) { DEBUG(1, ("Failed to make request to our cache!\n")); + } +done: + if (ret != EOK) { ret = nss_cmd_send_error(cmdctx, ret); if (ret == EOK) { nss_cmd_done(cmdctx); @@ -586,7 +594,7 @@ static void nss_cmd_getpwuid_dp_callback(uint16_t err_maj, uint32_t err_min, (unsigned int)err_maj, (unsigned int)err_min, err_msg)); } - ret = sysdb_getpwuid(cmdctx, cctx->ev, cctx->nctx->sysdb, + ret = sysdb_getpwuid(cmdctx, cctx->nctx->sysdb, dctx->domain, cmdctx->id, dctx->legacy, nss_cmd_getpwuid_callback, dctx); @@ -656,7 +664,7 @@ static int nss_cmd_getpwuid(struct cli_ctx *cctx) DEBUG(4, ("Requesting info for [%lu@%s]\n", cmdctx->id, dctx->domain)); - ret = sysdb_getpwuid(cmdctx, cctx->ev, cctx->nctx->sysdb, + ret = sysdb_getpwuid(cmdctx, cctx->nctx->sysdb, dctx->domain, cmdctx->id, dctx->legacy, nss_cmd_getpwuid_callback, dctx); @@ -773,7 +781,7 @@ static void nss_cmd_setpw_dp_callback(uint16_t err_maj, uint32_t err_min, (unsigned int)err_maj, (unsigned int)err_min, err_msg)); } - ret = sysdb_enumpwent(cmdctx, cctx->ev, cctx->nctx->sysdb, + ret = sysdb_enumpwent(cmdctx, cctx->nctx->sysdb, dctx->domain, dctx->legacy, nss_cmd_setpwent_callback, cmdctx); if (ret != EOK) { @@ -854,7 +862,7 @@ static int nss_cmd_setpwent_ext(struct cli_ctx *cctx, bool immediate) timeout, domains[i], NSS_DP_USER, NULL, 0); } else { - ret = sysdb_enumpwent(dctx, cctx->ev, cctx->nctx->sysdb, + ret = sysdb_enumpwent(dctx, cctx->nctx->sysdb, dctx->domain, dctx->legacy, nss_cmd_setpwent_callback, cmdctx); } @@ -1280,7 +1288,7 @@ static void nss_cmd_getgrnam_dp_callback(uint16_t err_maj, uint32_t err_min, (unsigned int)err_maj, (unsigned int)err_min, err_msg)); } - ret = sysdb_getgrnam(cmdctx, cctx->ev, cctx->nctx->sysdb, + ret = sysdb_getgrnam(cmdctx, cctx->nctx->sysdb, dctx->domain, cmdctx->name, dctx->legacy, nss_cmd_getgrnam_callback, dctx); @@ -1299,6 +1307,7 @@ static int nss_cmd_getgrnam(struct cli_ctx *cctx) { struct nss_cmd_ctx *cmdctx; struct nss_dom_ctx *dctx; + const char *rawname; uint8_t *body; size_t blen; int ret; @@ -1320,23 +1329,26 @@ static int nss_cmd_getgrnam(struct cli_ctx *cctx) talloc_free(cmdctx); return EINVAL; } + rawname = (const char *)body; - ret = nss_parse_name(dctx, (const char *)body); + ret = nss_parse_name(dctx, rawname); if (ret != EOK) { - DEBUG(1, ("Invalid name received\n")); - talloc_free(cmdctx); - return ret; + DEBUG(2, ("Invalid name received [%s]\n", rawname)); + goto done; } DEBUG(4, ("Requesting info for [%s] from [%s]\n", cmdctx->name, dctx->domain)); - ret = sysdb_getgrnam(cmdctx, cctx->ev, cctx->nctx->sysdb, + ret = sysdb_getgrnam(cmdctx, cctx->nctx->sysdb, dctx->domain, cmdctx->name, dctx->legacy, nss_cmd_getgrnam_callback, dctx); if (ret != EOK) { DEBUG(1, ("Failed to make request to our cache!\n")); + } +done: + if (ret != EOK) { ret = nss_cmd_send_error(cmdctx, ret); if (ret == EOK) { nss_cmd_done(cmdctx); @@ -1484,7 +1496,7 @@ static void nss_cmd_getgrgid_dp_callback(uint16_t err_maj, uint32_t err_min, (unsigned int)err_maj, (unsigned int)err_min, err_msg)); } - ret = sysdb_getgrgid(cmdctx, cctx->ev, cctx->nctx->sysdb, + ret = sysdb_getgrgid(cmdctx, cctx->nctx->sysdb, dctx->domain, cmdctx->id, dctx->legacy, nss_cmd_getgrgid_callback, dctx); @@ -1549,7 +1561,7 @@ static int nss_cmd_getgrgid(struct cli_ctx *cctx) DEBUG(4, ("Requesting info for [%lu@%s]\n", cmdctx->id, dctx->domain)); - ret = sysdb_getgrgid(cmdctx, cctx->ev, cctx->nctx->sysdb, + ret = sysdb_getgrgid(cmdctx, cctx->nctx->sysdb, dctx->domain, cmdctx->id, dctx->legacy, nss_cmd_getgrgid_callback, dctx); @@ -1665,7 +1677,7 @@ static void nss_cmd_setgr_dp_callback(uint16_t err_maj, uint32_t err_min, (unsigned int)err_maj, (unsigned int)err_min, err_msg)); } - ret = sysdb_enumgrent(dctx, cctx->ev, cctx->nctx->sysdb, + ret = sysdb_enumgrent(dctx, cctx->nctx->sysdb, dctx->domain, dctx->legacy, nss_cmd_setgrent_callback, cmdctx); if (ret != EOK) { @@ -1746,7 +1758,7 @@ static int nss_cmd_setgrent_ext(struct cli_ctx *cctx, bool immediate) timeout, domains[i], NSS_DP_GROUP, NULL, 0); } else { - ret = sysdb_enumgrent(dctx, cctx->ev, cctx->nctx->sysdb, + ret = sysdb_enumgrent(dctx, cctx->nctx->sysdb, dctx->domain, dctx->legacy, nss_cmd_setgrent_callback, cmdctx); } @@ -1994,7 +2006,7 @@ static void nss_cmd_getinitgr_callback(uint16_t err_maj, uint32_t err_min, (unsigned int)err_maj, (unsigned int)err_min, err_msg)); } - ret = sysdb_initgroups(cmdctx, cctx->ev, cctx->nctx->sysdb, + ret = sysdb_initgroups(cmdctx, cctx->nctx->sysdb, dctx->domain, cmdctx->name, dctx->legacy, nss_cmd_initgr_callback, cmdctx); @@ -2027,7 +2039,7 @@ static void nss_cmd_getinitnam_callback(uint16_t err_maj, uint32_t err_min, (unsigned int)err_maj, (unsigned int)err_min, err_msg)); } - ret = sysdb_getpwnam(cmdctx, cctx->ev, cctx->nctx->sysdb, + ret = sysdb_getpwnam(cmdctx, cctx->nctx->sysdb, dctx->domain, cmdctx->name, dctx->legacy, nss_cmd_getinit_callback, dctx); @@ -2155,6 +2167,7 @@ static int nss_cmd_initgroups(struct cli_ctx *cctx) { struct nss_cmd_ctx *cmdctx; struct nss_dom_ctx *dctx; + const char *rawname; uint8_t *body; size_t blen; int ret; @@ -2171,28 +2184,30 @@ static int nss_cmd_initgroups(struct cli_ctx *cctx) /* get user name to query */ sss_packet_get_body(cctx->creq->in, &body, &blen); - cmdctx->name = (const char *)body; /* if not terminated fail */ - if (cmdctx->name[blen -1] != '\0') { + if (body[blen -1] != '\0') { return EINVAL; } + rawname = (const char *)body; - ret = nss_parse_name(dctx, (const char *)body); + ret = nss_parse_name(dctx, rawname); if (ret != EOK) { - DEBUG(1, ("Invalid name received\n")); - talloc_free(cmdctx); - return ret; + DEBUG(2, ("Invalid name received [%s]\n", rawname)); + goto done; } DEBUG(4, ("Requesting info for [%s] from [%s]\n", cmdctx->name, dctx->domain)); - ret = sysdb_getpwnam(cmdctx, cctx->ev, cctx->nctx->sysdb, + ret = sysdb_getpwnam(cmdctx, cctx->nctx->sysdb, dctx->domain, cmdctx->name, dctx->legacy, nss_cmd_getinit_callback, dctx); if (ret != EOK) { DEBUG(1, ("Failed to make request to our cache!\n")); + } +done: + if (ret != EOK) { ret = nss_cmd_send_error(cmdctx, ret); if (ret == EOK) { nss_cmd_done(cmdctx); diff --git a/server/server.mk b/server/server.mk index 386f56f1..e029d4a5 100644 --- a/server/server.mk +++ b/server/server.mk @@ -13,6 +13,8 @@ UTIL_OBJ = \ sbus/sbus_client.o \ confdb/confdb.o \ db/sysdb.o \ + db/sysdb_req.o \ + db/sysdb_search.o \ db/sysdb_sync.o RESPONDER_UTIL_OBJ = \ -- cgit