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_search.c | 731 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 731 insertions(+) create mode 100644 server/db/sysdb_search.c (limited to 'server/db/sysdb_search.c') 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); +} + -- cgit