From 94ec51d8b53f636d41a879ed1d0d39127168cb21 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 24 Jun 2009 16:40:56 -0400 Subject: Rework transaction code to use tevent_req This is part of a set of patches to rewrite sysdb to a hopefully better API, that will also let use use tevent_req async style calls to manipulate our cache. --- server/Makefile.am | 1 - server/db/sysdb.c | 364 ++- server/db/sysdb.h | 371 +++- server/db/sysdb_ops.c | 3705 ++++++++++++++++++++----------- server/db/sysdb_private.h | 25 +- server/db/sysdb_req.c | 252 --- server/db/sysdb_search.c | 122 +- server/ldb_modules/memberof.c | 2 +- server/providers/ldap/ldap_auth.c | 86 +- server/providers/proxy.c | 717 ++++-- server/responder/pam/pam_LOCAL_domain.c | 115 +- server/tests/sysdb-tests.c | 1036 ++++----- server/tools/sss_groupadd.c | 82 +- server/tools/sss_groupdel.c | 79 +- server/tools/sss_groupmod.c | 266 ++- server/tools/sss_useradd.c | 166 +- server/tools/sss_userdel.c | 82 +- server/tools/sss_usermod.c | 256 ++- 18 files changed, 4929 insertions(+), 2798 deletions(-) delete mode 100644 server/db/sysdb_req.c diff --git a/server/Makefile.am b/server/Makefile.am index 01f3037c9..ab7027f30 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -144,7 +144,6 @@ SSSD_UTIL_OBJ = \ confdb/confdb.c \ db/sysdb.c \ db/sysdb_ops.c \ - db/sysdb_req.c \ db/sysdb_search.c \ monitor/monitor_sbus.c \ providers/dp_auth_util.c \ diff --git a/server/db/sysdb.c b/server/db/sysdb.c index a86a966b3..bb39c0643 100644 --- a/server/db/sysdb.c +++ b/server/db/sysdb.c @@ -140,6 +140,46 @@ int sysdb_attrs_add_long(struct sysdb_attrs *attrs, return ret; } +int sysdb_attrs_add_uint32(struct sysdb_attrs *attrs, + const char *name, uint32_t value) +{ + unsigned long val = value; + struct ldb_val v; + char *str; + int ret; + + str = talloc_asprintf(attrs, "%lu", val); + if (!str) return ENOMEM; + + v.data = (uint8_t *)str; + v.length = strlen(str); + + ret = sysdb_attrs_add_val(attrs, name, &v); + talloc_free(str); + + return ret; +} + +int sysdb_attrs_add_time_t(struct sysdb_attrs *attrs, + const char *name, time_t value) +{ + long long val = value; + struct ldb_val v; + char *str; + int ret; + + str = talloc_asprintf(attrs, "%lld", val); + if (!str) return ENOMEM; + + v.data = (uint8_t *)str; + v.length = strlen(str); + + ret = sysdb_attrs_add_val(attrs, name, &v); + talloc_free(str); + + return ret; +} + /* TODO: make a more complete and precise mapping */ int sysdb_error_to_errno(int ldberr) { @@ -159,9 +199,327 @@ int sysdb_error_to_errno(int ldberr) } } -/************************************************ - * Initialiazation stuff - */ +/* =Internal-Operations-Queue============================================= */ + +static void sysdb_run_operation(struct tevent_context *ev, + struct tevent_timer *te, + struct timeval tv, void *pvt) +{ + struct sysdb_handle *handle = talloc_get_type(pvt, struct sysdb_handle); + + tevent_req_done(handle->subreq); +} + +static void sysdb_schedule_operation(struct sysdb_handle *handle) +{ + struct timeval tv = { 0, 0 }; + struct tevent_timer *te; + + te = tevent_add_timer(handle->ctx->ev, handle, tv, + sysdb_run_operation, handle); + if (!te) { + DEBUG(1, ("Failed to add critical timer to run next handle!\n")); + } +} + +static int sysdb_handle_destructor(void *mem) +{ + struct sysdb_handle *handle = talloc_get_type(mem, struct sysdb_handle); + bool start_next = false; + int ret; + + /* if this was the current op start next */ + if (handle->ctx->queue == handle) { + start_next = true; + } + + DLIST_REMOVE(handle->ctx->queue, handle); + + if (start_next && handle->ctx->queue) { + /* run next */ + sysdb_schedule_operation(handle->ctx->queue); + } + + if (handle->transaction_active) { + ret = ldb_transaction_cancel(handle->ctx->ldb); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Failed to cancel ldb transaction! (%d)\n", ret)); + } + /* FIXME: abort() ? */ + handle->transaction_active = false; + } + + return 0; +} + +struct sysdb_get_handle_state { + struct tevent_context *ev; + struct sysdb_ctx *ctx; + + struct sysdb_handle *handle; +}; + +struct tevent_req *sysdb_get_handle_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_ctx *ctx) +{ + struct tevent_req *req; + struct sysdb_get_handle_state *state; + struct sysdb_handle *handle; + + req = tevent_req_create(mem_ctx, &state, struct sysdb_get_handle_state); + if (!req) return NULL; + + state->ev = ev; + state->ctx = ctx; + + handle = talloc_zero(state, struct sysdb_handle); + if (!handle) { + talloc_zfree(req); + return NULL; + } + + handle->ctx = ctx; + handle->subreq = req; + + talloc_set_destructor((TALLOC_CTX *)handle, sysdb_handle_destructor); + + DLIST_ADD_END(ctx->queue, handle, struct sysdb_handle *); + + if (ctx->queue == handle) { + /* this is the first in the queue, schedule an immediate run */ + sysdb_schedule_operation(handle); + } + + state->handle = handle; + + return req; +} + +static int sysdb_get_handle_recv(struct tevent_req *req, TALLOC_CTX *memctx, + struct sysdb_handle **handle) +{ + struct sysdb_get_handle_state *state = tevent_req_data(req, + struct sysdb_get_handle_state); + enum tevent_req_state tstate; + uint64_t err; + + if (tevent_req_is_error(req, &tstate, &err)) { + return err; + } + + *handle = talloc_steal(memctx, state->handle); + if (!*handle) return ENOMEM; + + return EOK; +} + +/* =Transactions========================================================== */ + +struct sysdb_transaction_state { + struct tevent_context *ev; + struct sysdb_ctx *ctx; + + struct sysdb_handle *handle; +}; + +static void sysdb_transaction_done(struct tevent_req *subreq); + +struct tevent_req *sysdb_transaction_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_ctx *ctx) +{ + struct tevent_req *req, *subreq; + struct sysdb_transaction_state *state; + + req = tevent_req_create(mem_ctx, &state, struct sysdb_transaction_state); + if (!req) return NULL; + + state->ev = ev; + state->ctx = ctx; + + subreq = sysdb_get_handle_send(state, ev, ctx); + if (!subreq) { + talloc_zfree(req); + return NULL; + } + + tevent_req_set_callback(subreq, sysdb_transaction_done, req); + + return req; +} + +static void sysdb_transaction_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_transaction_state *state = tevent_req_data(req, + struct sysdb_transaction_state); + int ret; + + ret = sysdb_get_handle_recv(subreq, state, &state->handle); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + ret = ldb_transaction_start(state->ctx->ldb); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Failed to start ldb transaction! (%d)\n", ret)); + tevent_req_error(req, sysdb_error_to_errno(ret)); + return; + } + state->handle->transaction_active = true; + + tevent_req_done(req); +} + +int sysdb_transaction_recv(struct tevent_req *req, TALLOC_CTX *memctx, + struct sysdb_handle **handle) +{ + struct sysdb_transaction_state *state = tevent_req_data(req, + struct sysdb_transaction_state); + enum tevent_req_state tstate; + uint64_t err; + + if (tevent_req_is_error(req, &tstate, &err)) { + return err; + } + + *handle = talloc_steal(memctx, state->handle); + if (!*handle) return ENOMEM; + + return EOK; +} + +struct tevent_req *sysdb_transaction_commit_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle) +{ + struct tevent_req *req; + struct sysdb_transaction_state *state; + int ret; + + req = tevent_req_create(mem_ctx, &state, struct sysdb_transaction_state); + if (!req) return NULL; + + state->ev = ev; + state->ctx = handle->ctx; + state->handle = handle; + + ret = ldb_transaction_commit(handle->ctx->ldb); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Failed to commit ldb transaction! (%d)\n", ret)); + tevent_req_error(req, sysdb_error_to_errno(ret)); + } + handle->transaction_active = false; + + /* the following may seem weird but it is actually fine. + * _done() will not actually call the callback as it will not be set + * until we return. But it will mark the request as done. + * _post() will trigger the callback as it schedules after we returned + * and actually set the callback */ + tevent_req_done(req); + tevent_req_post(req, ev); + return req; +} + +int sysdb_transaction_commit_recv(struct tevent_req *req) +{ + struct sysdb_transaction_state *state = tevent_req_data(req, + struct sysdb_transaction_state); + enum tevent_req_state tstate; + uint64_t err; + + /* finally free handle + * this will also trigger the next transaction in the queue if any */ + talloc_free(state->handle); + + if (tevent_req_is_error(req, &tstate, &err)) { + return err; + } + + return EOK; +} + +/* =Operations============================================================ */ + +struct sysdb_operation_state { + struct tevent_context *ev; + struct sysdb_ctx *ctx; + + struct sysdb_handle *handle; +}; + +static void sysdb_operation_process(struct tevent_req *subreq); + +struct tevent_req *sysdb_operation_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_ctx *ctx) +{ + struct tevent_req *req, *subreq; + struct sysdb_operation_state *state; + + req = tevent_req_create(mem_ctx, &state, struct sysdb_operation_state); + if (!req) return NULL; + + state->ev = ev; + state->ctx = ctx; + + subreq = sysdb_get_handle_send(state, ev, ctx); + if (!subreq) { + talloc_zfree(req); + return NULL; + } + + tevent_req_set_callback(subreq, sysdb_operation_process, req); + + return req; +} + +static void sysdb_operation_process(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_operation_state *state = tevent_req_data(req, + struct sysdb_operation_state); + int ret; + + ret = sysdb_get_handle_recv(subreq, state, &state->handle); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + tevent_req_done(req); +} + +int sysdb_operation_recv(struct tevent_req *req, TALLOC_CTX *memctx, + struct sysdb_handle **handle) +{ + struct sysdb_operation_state *state = tevent_req_data(req, + struct sysdb_operation_state); + enum tevent_req_state tstate; + uint64_t err; + + if (tevent_req_is_error(req, &tstate, &err)) { + return err; + } + + *handle = talloc_steal(memctx, state->handle); + if (!*handle) return ENOMEM; + + return EOK; +} + +void sysdb_operation_done(struct sysdb_handle *handle) +{ + talloc_free(handle); +} + +/* =Initialization======================================================== */ static int sysdb_read_var(TALLOC_CTX *mem_ctx, struct confdb_ctx *cdb, diff --git a/server/db/sysdb.h b/server/db/sysdb.h index 6da833187..2696dfaf9 100644 --- a/server/db/sysdb.h +++ b/server/db/sysdb.h @@ -23,6 +23,7 @@ #define __SYS_DB_H__ #include "confdb/confdb.h" +#include #define SYSDB_CONF_SECTION "config/sysdb" #define SYSDB_FILE "sssd.ldb" @@ -88,8 +89,6 @@ #define SYSDB_GETCACHED_FILTER "(&"SYSDB_UC")("SYSDB_LAST_LOGIN">=%lu))" -#define SYSDB_CHECK_FILTER "(&(|("SYSDB_UC")("SYSDB_GC"))("SYSDB_NAME"=%s))" - #define SYSDB_PW_ATTRS {SYSDB_NAME, SYSDB_UIDNUM, \ SYSDB_GIDNUM, SYSDB_GECOS, \ SYSDB_HOMEDIR, SYSDB_SHELL, \ @@ -125,6 +124,10 @@ #define SYSDB_TMPL_USER SYSDB_NAME"=%s,"SYSDB_TMPL_USER_BASE #define SYSDB_TMPL_GROUP SYSDB_NAME"=%s,"SYSDB_TMPL_GROUP_BASE +#define SYSDB_MOD_ADD LDB_FLAG_MOD_ADD +#define SYSDB_MOD_DEL LDB_FLAG_MOD_DELETE +#define SYSDB_MOD_REP LDB_FLAG_MOD_REPLACE + struct confdb_ctx; struct sysdb_ctx; struct sysdb_handle; @@ -142,40 +145,15 @@ int sysdb_attrs_add_string(struct sysdb_attrs *attrs, const char *name, const char *str); int sysdb_attrs_add_long(struct sysdb_attrs *attrs, const char *name, long value); +int sysdb_attrs_add_uint32(struct sysdb_attrs *attrs, + const char *name, uint32_t value); +int sysdb_attrs_add_time_t(struct sysdb_attrs *attrs, + const char *name, time_t value); /* convert an ldb error into an errno error */ int sysdb_error_to_errno(int ldberr); -/* callbacks */ -typedef void (*sysdb_callback_t)(void *, int, struct ldb_result *); -typedef void (*sysdb_fn_t)(struct sysdb_handle *, void *pvt); - -/* service functions */ -struct ldb_context *sysdb_ctx_get_ldb(struct sysdb_ctx *ctx); -struct sysdb_ctx *sysdb_handle_get_ctx(struct sysdb_handle *req); - -/* function to start and finish a transaction - * After sysdb_transaction() is successfully called, - * it *MUST* be closed with a call to sysdb_transaction_done() - * if error is == 0 the transaction is committed otherwise it - * is canceled and all modifications to the db are thrown away - * - * Transactions are serialized, no other transaction or operation can be - * performed while a transaction is active. - */ -int sysdb_transaction(TALLOC_CTX *mem_ctx, - struct sysdb_ctx *ctx, - sysdb_fn_t fn, void *pvt); -void sysdb_transaction_done(struct sysdb_handle *req, int error); - -/* An operation blocks the transaction queue as well, but does not - * start a transaction, normally useful only for search type calls. - * Cannot be called within a transaction */ -int sysdb_operation(TALLOC_CTX *mem_ctx, - struct sysdb_ctx *ctx, - sysdb_fn_t fn, void *pvt); -void sysdb_operation_done(struct sysdb_handle *req); - +/* DNs related helper functions */ struct ldb_dn *sysdb_user_dn(struct sysdb_ctx *ctx, void *memctx, const char *domain, const char *name); struct ldb_dn *sysdb_group_dn(struct sysdb_ctx *ctx, void *memctx, @@ -183,12 +161,44 @@ struct ldb_dn *sysdb_group_dn(struct sysdb_ctx *ctx, void *memctx, struct ldb_dn *sysdb_domain_dn(struct sysdb_ctx *ctx, void *memctx, const char *domain); +/* function to start and finish a transaction + * sysdb_transaction_send() will queue a request for a transaction + * when it is done it will call the tevent_req callback, which must + * retrieve the transaction handle using sysdb_transaction_recv() + * + * A transaction must be completed either by sending a commit: + * sysdb_transaction_commit_send()/sysdb_transaction_commit_recv() + * or by freeing the transaction handle (this will implicitly cause + * a transaction cancelation). + * + * Transactions are serialized, no other transaction or operation can be + * performed while a transaction is active. Multiple transaction request + * are queued internally and served in order. + */ + +struct tevent_req *sysdb_transaction_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_ctx *ctx); +int sysdb_transaction_recv(struct tevent_req *req, TALLOC_CTX *memctx, + struct sysdb_handle **handle); + +struct tevent_req *sysdb_transaction_commit_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle); +int sysdb_transaction_commit_recv(struct tevent_req *req); + +/* Sysdb initialization. + * call this function *only* once to initialize the database and get + * the sysdb ctx */ int sysdb_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct confdb_ctx *cdb, const char *alt_db_path, struct sysdb_ctx **dbctx); +/* FIXME: REMOVE */ +typedef void (*sysdb_callback_t)(void *, int, struct ldb_result *); + /* functions to retrieve information from sysdb * These functions automatically starts an operation * therefore they cannot be called within a transaction */ @@ -243,84 +253,233 @@ int sysdb_get_user_attr(TALLOC_CTX *mem_ctx, /* functions that modify the databse * they have to be called within a transaction - * See sysdb_transaction() */ -int sysdb_add_group_member(struct sysdb_handle *handle, - struct ldb_dn *member_dn, - struct ldb_dn *group_dn, - sysdb_callback_t fn, void *pvt); - -int sysdb_remove_group_member(struct sysdb_handle *handle, - struct ldb_dn *member_dn, - struct ldb_dn *group_dn, - sysdb_callback_t fn, void *pvt); - -int sysdb_delete_entry(struct sysdb_handle *handle, - struct ldb_dn *dn, - sysdb_callback_t fn, void *pvt); - -int sysdb_delete_user_by_uid(struct sysdb_handle *handle, - struct sss_domain_info *domain, - uid_t uid, - sysdb_callback_t fn, void *pvt); - -int sysdb_delete_group_by_gid(struct sysdb_handle *handle, - struct sss_domain_info *domain, - gid_t gid, - sysdb_callback_t fn, void *pvt); - -int sysdb_set_user_attr(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *name, - struct sysdb_attrs *attributes, - sysdb_callback_t fn, void *ptr); - -int sysdb_add_user(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *name, - uid_t uid, gid_t gid, const char *fullname, - const char *homedir, const char *shell, - sysdb_callback_t fn, void *pvt); - -int sysdb_add_group(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *name, gid_t gid, - sysdb_callback_t fn, void *pvt); + * See sysdb_transaction_send()/_recv() */ + +/* Delete Entry */ +struct tevent_req *sysdb_delete_entry_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct ldb_dn *dn); +int sysdb_delete_entry_recv(struct tevent_req *req); + +/* Search Entry */ +struct tevent_req *sysdb_search_entry_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct ldb_dn *base_dn, + const char *filter, + const char **attrs); +int sysdb_search_entry_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + struct ldb_message **msg); + +/* Search User (by uid or name) */ +struct tevent_req *sysdb_search_user_by_name_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name); +struct tevent_req *sysdb_search_user_by_uid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + uid_t uid); +int sysdb_search_user_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + struct ldb_message **msg); + +/* Delete User by uid */ +struct tevent_req *sysdb_delete_user_by_uid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + uid_t uid); +int sysdb_delete_user_by_uid_recv(struct tevent_req *req); + +/* Search Group (gy gid or name) */ +struct tevent_req *sysdb_search_group_by_name_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name); +struct tevent_req *sysdb_search_group_by_gid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + gid_t gid); +int sysdb_search_group_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + struct ldb_message **msg); + +/* Delete group by gid */ +struct tevent_req *sysdb_delete_group_by_gid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + gid_t gid); +int sysdb_delete_group_by_gid_recv(struct tevent_req *req); + +/* Replace entry attrs */ +struct tevent_req *sysdb_set_entry_attr_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct ldb_dn *entry_dn, + struct sysdb_attrs *attrs, + int mod_op); +int sysdb_set_entry_attr_recv(struct tevent_req *req); + +/* Replace user attrs */ +struct tevent_req *sysdb_set_user_attr_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, + struct sysdb_attrs *attrs, + int mod_op); +int sysdb_set_user_attr_recv(struct tevent_req *req); + +/* Replace group attrs */ +struct tevent_req *sysdb_set_group_attr_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, + struct sysdb_attrs *attrs, + int mod_op); +int sysdb_set_group_attr_recv(struct tevent_req *req); + +/* Allocate a new id */ +struct tevent_req *sysdb_get_new_id_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain); +int sysdb_get_new_id_recv(struct tevent_req *req, uint32_t *id); + +/* Add user (only basic attrs and w/o checks) */ +struct tevent_req *sysdb_add_basic_user_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, + uid_t uid, gid_t gid, + const char *gecos, + const char *homedir, + const char *shell); +int sysdb_add_basic_user_recv(struct tevent_req *req); + +/* Add user (all checks) */ +struct tevent_req *sysdb_add_user_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, + uid_t uid, gid_t gid, + const char *gecos, + const char *homedir, + const char *shell, + struct sysdb_attrs *attrs); +int sysdb_add_user_recv(struct tevent_req *req); + +/* Add group (only basic attrs and w/o checks) */ +struct tevent_req *sysdb_add_basic_group_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, gid_t gid); +int sysdb_add_basic_group_recv(struct tevent_req *req); + +/* Add group (all checks) */ +struct tevent_req *sysdb_add_group_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, gid_t gid, + struct sysdb_attrs *attrs); +int sysdb_add_group_recv(struct tevent_req *req); + +/* mod_op must be either LDB_FLAG_MOD_ADD or LDB_FLAG_MOD_DELETE */ +struct tevent_req *sysdb_mod_group_member_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct ldb_dn *member_dn, + struct ldb_dn *group_dn, + int mod_op); +int sysdb_mod_group_member_recv(struct tevent_req *req); int sysdb_set_group_gid(struct sysdb_handle *handle, struct sss_domain_info *domain, const char *name, gid_t gid, sysdb_callback_t fn, void *pvt); -/* legacy functions for proxy providers */ - -int sysdb_legacy_store_user(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *name, const char *pwd, - uid_t uid, gid_t gid, const char *gecos, - const char *homedir, const char *shell, - sysdb_callback_t fn, void *pvt); - -int sysdb_legacy_store_group(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *name, gid_t gid, - const char **members, - sysdb_callback_t fn, void *pvt); - -int sysdb_legacy_add_group_member(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *group, - const char *member, - sysdb_callback_t fn, void *pvt); - -int sysdb_legacy_remove_group_member(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *group, - const char *member, - sysdb_callback_t fn, void *pvt); - -int sysdb_set_cached_password(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *user, - const char *password, - sysdb_callback_t fn, void *pvt); +struct tevent_req *sysdb_store_user_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, + const char *pwd, + uid_t uid, gid_t gid, + const char *gecos, + const char *homedir, + const char *shell); +int sysdb_store_user_recv(struct tevent_req *req); + +struct tevent_req *sysdb_store_group_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, + gid_t gid, + const char **members); +int sysdb_store_group_recv(struct tevent_req *req); + +struct tevent_req *sysdb_add_group_member_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *group, + const char *member); +int sysdb_add_group_member_recv(struct tevent_req *req); + +struct tevent_req *sysdb_remove_group_member_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *group, + const char *member); +int sysdb_remove_group_member_recv(struct tevent_req *req); + +struct tevent_req *sysdb_set_cached_password_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *user, + const char *password); +int sysdb_set_cached_password_recv(struct tevent_req *req); + +/* TODO: remove later + * These functions are available in the latest tevent and are the ones that + * should be used as tevent_req is rightfully opaque there */ +#ifndef tevent_req_data +#define tevent_req_data(req, type) ((type *)req->private_state) +#endif + +#ifndef tevent_req_set_callback +#define tevent_req_set_callback(req, func, data) \ + do { req->async.fn = func; req->async.private_data = data; } while(0) +#endif + +#ifndef tevent_req_callback_data +#define tevent_req_callback_data(req, type) ((type *)req->async.private_data) +#endif + +#ifndef tevent_req_notify_callback +#define tevent_req_notify_callback(req) \ + do { \ + if (req->async.fn != NULL) { \ + req->async.fn(req); \ + } \ + } while(0) +#endif + + #endif /* __SYS_DB_H__ */ diff --git a/server/db/sysdb_ops.c b/server/db/sysdb_ops.c index 9b3f28283..785ce15e0 100644 --- a/server/db/sysdb_ops.c +++ b/server/db/sysdb_ops.c @@ -24,25 +24,6 @@ #include "util/nss_sha512crypt.h" #include -struct sysdb_cb_ctx { - sysdb_callback_t fn; - void *pvt; - - bool ignore_not_found; -}; - -static int sysdb_ret_error(struct sysdb_cb_ctx *ctx, int ret, int lret) -{ - ctx->fn(ctx->pvt, ret, NULL); - return lret; -}; - -static int sysdb_ret_done(struct sysdb_cb_ctx *ctx) -{ - ctx->fn(ctx->pvt, EOK, NULL); - return LDB_SUCCESS; -}; - static int add_string(struct ldb_message *msg, int flags, const char *attr, const char *value) { @@ -51,8 +32,9 @@ static int add_string(struct ldb_message *msg, int flags, ret = ldb_msg_add_empty(msg, attr, flags, NULL); if (ret == LDB_SUCCESS) { ret = ldb_msg_add_string(msg, attr, value); + if (ret == LDB_SUCCESS) return EOK; } - return ret; + return ENOMEM; } static int add_ulong(struct ldb_message *msg, int flags, @@ -63,8 +45,9 @@ static int add_ulong(struct ldb_message *msg, int flags, ret = ldb_msg_add_empty(msg, attr, flags, NULL); if (ret == LDB_SUCCESS) { ret = ldb_msg_add_fmt(msg, attr, "%lu", value); + if (ret == LDB_SUCCESS) return EOK; } - return ret; + return ENOMEM; } static uint32_t get_attr_as_uint32(struct ldb_message *msg, const char *attr) @@ -89,1798 +72,2948 @@ static uint32_t get_attr_as_uint32(struct ldb_message *msg, const char *attr) return l; } -static int sysdb_op_callback(struct ldb_request *req, struct ldb_reply *rep) +#define ERROR_OUT(v, r, l) do { v = r; goto l; } while(0); + +/* =LDB-Request-(tevent_req-style)======================================== */ + +struct sldb_request_state { + struct tevent_context *ev; + struct ldb_context *ldbctx; + struct ldb_request *ldbreq; + struct ldb_reply *ldbreply; +}; + +static void sldb_request_wakeup(struct tevent_req *subreq); +static int sldb_request_callback(struct ldb_request *ldbreq, + struct ldb_reply *ldbreply); + +static struct tevent_req *sldb_request_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ldb_context *ldbctx, + struct ldb_request *ldbreq) { - struct sysdb_cb_ctx *cbctx; - int err; + struct tevent_req *req, *subreq; + struct sldb_request_state *state; + struct timeval tv = { 0, 0 }; - cbctx = talloc_get_type(req->context, struct sysdb_cb_ctx); + req = tevent_req_create(mem_ctx, &state, struct sldb_request_state); + if (!req) return NULL; - if (!rep) { - return sysdb_ret_error(cbctx, EIO, LDB_ERR_OPERATIONS_ERROR); - } - if (rep->error != LDB_SUCCESS) { - if (! (cbctx->ignore_not_found && - rep->error == LDB_ERR_NO_SUCH_OBJECT)) { - err = sysdb_error_to_errno(rep->error); - return sysdb_ret_error(cbctx, err, rep->error); - } - } + state->ev = ev; + state->ldbctx = ldbctx; + state->ldbreq = ldbreq; + state->ldbreply = NULL; - if (rep->type != LDB_REPLY_DONE) { - sysdb_ret_error(cbctx, EINVAL, LDB_ERR_OPERATIONS_ERROR); + subreq = tevent_wakeup_send(state, ev, tv); + if (!subreq) { + DEBUG(1, ("Failed to add critical timer to run next ldb operation!\n")); + talloc_zfree(req); + return NULL; } + tevent_req_set_callback(subreq, sldb_request_wakeup, req); - return sysdb_ret_done(cbctx); + return req; } -int sysdb_add_group_member(struct sysdb_handle *handle, - struct ldb_dn *member_dn, - struct ldb_dn *group_dn, - sysdb_callback_t fn, void *pvt) +static void sldb_request_wakeup(struct tevent_req *subreq) { - struct sysdb_ctx *ctx; - struct sysdb_cb_ctx *cbctx; - struct ldb_request *req; - struct ldb_message *msg; - const char *dn; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sldb_request_state *state = tevent_req_data(req, + struct sldb_request_state); int ret; - if (!sysdb_handle_check_running(handle)) { - DEBUG(2, ("Invalid request! Not running at this time.\n")); - return EINVAL; - } - - ctx = sysdb_handle_get_ctx(handle); + if (!tevent_wakeup_recv(subreq)) return; + talloc_zfree(subreq); - cbctx = talloc_zero(handle, struct sysdb_cb_ctx); - if (!cbctx) return ENOMEM; + state->ldbreq->callback = sldb_request_callback; + state->ldbreq->context = req; - cbctx->fn = fn; - cbctx->pvt = pvt; + ret = ldb_request(state->ldbctx, state->ldbreq); + if (ret != LDB_SUCCESS) { + tevent_req_error(req, sysdb_error_to_errno(ret)); + } +} - /* Add the member_dn as a member of the group */ - msg = ldb_msg_new(cbctx); - if(msg == NULL) return ENOMEM; +static int sldb_request_callback(struct ldb_request *ldbreq, + struct ldb_reply *ldbreply) +{ + struct tevent_req *req = talloc_get_type(ldbreq->context, + struct tevent_req); + struct sldb_request_state *state = tevent_req_data(req, + struct sldb_request_state); + int err; - msg->dn = group_dn; - ret = ldb_msg_add_empty(msg, SYSDB_MEMBER, - LDB_FLAG_MOD_ADD, NULL); - if (ret != LDB_SUCCESS) return ENOMEM; + if (!ldbreply) { + ERROR_OUT(err, EIO, fail); + } - dn = ldb_dn_get_linearized(member_dn); - if (!dn) return EINVAL; + state->ldbreply = talloc_steal(state, ldbreply); - ret = ldb_msg_add_fmt(msg, SYSDB_MEMBER, "%s", dn); - if (ret != LDB_SUCCESS) return EINVAL; + if (ldbreply->error != LDB_SUCCESS) { + ERROR_OUT(err, sysdb_error_to_errno(ldbreply->error), fail); + } - ret = ldb_build_mod_req(&req, ctx->ldb, cbctx, msg, - NULL, cbctx, sysdb_op_callback, NULL); - if (ret != LDB_SUCCESS) { - DEBUG(1, ("Failed to build modify request: %s(%d)[%s]\n", - ldb_strerror(ret), ret, ldb_errstring(ctx->ldb))); - return sysdb_error_to_errno(ret); + if (ldbreply->type == LDB_REPLY_DONE) { + tevent_req_done(req); + return EOK; } - ret = ldb_request(ctx->ldb, req); - if (ret != LDB_SUCCESS) return sysdb_error_to_errno(ret); + tevent_req_notify_callback(req); + return EOK; +fail: + tevent_req_error(req, err); return EOK; } -int sysdb_remove_group_member(struct sysdb_handle *handle, - struct ldb_dn *member_dn, - struct ldb_dn *group_dn, - sysdb_callback_t fn, void *pvt) +static int sldb_request_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + struct ldb_reply **ldbreply) { - struct sysdb_ctx *ctx; - struct sysdb_cb_ctx *cbctx; - struct ldb_request *req; - struct ldb_message *msg; - const char *dn; - int ret; + struct sldb_request_state *state = tevent_req_data(req, + struct sldb_request_state); + enum tevent_req_state tstate; + uint64_t err = 0; - if (!sysdb_handle_check_running(handle)) { - DEBUG(2, ("Invalid request! Not running at this time.\n")); - return EINVAL; + if (state->ldbreply) { + *ldbreply = talloc_move(mem_ctx, &state->ldbreply); } - ctx = sysdb_handle_get_ctx(handle); + if (tevent_req_is_error(req, &tstate, &err)) { + if (err != 0) return err; + if (tstate == TEVENT_REQ_IN_PROGRESS) return EOK; + return EIO; + } - cbctx = talloc_zero(handle, struct sysdb_cb_ctx); - if (!cbctx) return ENOMEM; + return EOK; +} - cbctx->fn = fn; - cbctx->pvt = pvt; +/* =Standard-Sysdb-Operations-utility-functions=========================== */ - /* Add the member_dn as a member of the group */ - msg = ldb_msg_new(cbctx); - if(msg == NULL) return ENOMEM; +struct sysdb_op_state { + struct tevent_context *ev; + struct sysdb_handle *handle; - msg->dn = group_dn; - ret = ldb_msg_add_empty(msg, SYSDB_MEMBER, - LDB_FLAG_MOD_DELETE, NULL); - if (ret != LDB_SUCCESS) return ENOMEM; + bool ignore_not_found; - dn = ldb_dn_get_linearized(member_dn); - if (!dn) return EINVAL; + struct ldb_reply *ldbreply; +}; - ret = ldb_msg_add_fmt(msg, SYSDB_MEMBER, "%s", dn); - if (ret != LDB_SUCCESS) return EINVAL; +static void sysdb_op_default_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_op_state *state = tevent_req_data(req, + struct sysdb_op_state); + int ret; - ret = ldb_build_mod_req(&req, ctx->ldb, cbctx, msg, - NULL, cbctx, sysdb_op_callback, NULL); - if (ret != LDB_SUCCESS) { - DEBUG(1, ("Failed to build modify request: %s(%d)[%s]\n", - ldb_strerror(ret), ret, ldb_errstring(ctx->ldb))); - return sysdb_error_to_errno(ret); + ret = sldb_request_recv(subreq, state, &state->ldbreply); + talloc_zfree(subreq); + if (ret) { + if (state->ignore_not_found && ret == ENOENT) { + goto done; + } + tevent_req_error(req, ret); + return; } - ret = ldb_request(ctx->ldb, req); - if (ret != LDB_SUCCESS) return sysdb_error_to_errno(ret); + if (state->ldbreply->type != LDB_REPLY_DONE) { + tevent_req_error(req, EIO); + return; + } - return EOK; +done: + tevent_req_done(req); } -int sysdb_delete_entry(struct sysdb_handle *handle, - struct ldb_dn *dn, - sysdb_callback_t fn, void *pvt) +static int sysdb_op_default_recv(struct tevent_req *req) { - struct sysdb_ctx *ctx; - struct sysdb_cb_ctx *cbctx; - struct ldb_request *req; - int ret; + enum tevent_req_state tstate; + uint64_t err; - if (!sysdb_handle_check_running(handle)) { - DEBUG(2, ("Invalid request! Not running at this time.\n")); - return EINVAL; + if (tevent_req_is_error(req, &tstate, &err)) { + return err; } - ctx = sysdb_handle_get_ctx(handle); + return EOK; +} + + +/* =Remove-Entry-From-Sysdb=============================================== */ + +struct tevent_req *sysdb_delete_entry_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct ldb_dn *dn) +{ + struct tevent_req *req, *subreq; + struct sysdb_op_state *state; + struct ldb_request *ldbreq; + int ret; - cbctx = talloc_zero(handle, struct sysdb_cb_ctx); - if (!cbctx) return ENOMEM; + req = tevent_req_create(mem_ctx, &state, struct sysdb_op_state); + if (!req) return NULL; - cbctx->fn = fn; - cbctx->pvt = pvt; - cbctx->ignore_not_found = true; + state->ev = ev; + state->handle = handle; + state->ignore_not_found = true; + state->ldbreply = NULL; - ret = ldb_build_del_req(&req, ctx->ldb, cbctx, dn, NULL, - cbctx, sysdb_op_callback, NULL); + ret = ldb_build_del_req(&ldbreq, handle->ctx->ldb, state, dn, + NULL, NULL, NULL, NULL); if (ret != LDB_SUCCESS) { DEBUG(1, ("LDB Error: %s(%d)\nError Message: [%s]\n", - ldb_strerror(ret), ret, ldb_errstring(ctx->ldb))); - return sysdb_error_to_errno(ret); + ldb_strerror(ret), ret, ldb_errstring(handle->ctx->ldb))); + ERROR_OUT(ret, sysdb_error_to_errno(ret), fail); } - ret = ldb_request(ctx->ldb, req); - if (ret != LDB_SUCCESS) return sysdb_error_to_errno(ret); + subreq = sldb_request_send(state, ev, handle->ctx->ldb, ldbreq); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_op_default_done, req); - return EOK; + return req; + +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; } -struct delete_ctx { - struct sysdb_handle *handle; - struct sysdb_cb_ctx *cbctx; +int sysdb_delete_entry_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); +} - struct ldb_result *res; -}; -static int delete_callback(struct ldb_request *req, struct ldb_reply *rep) +/* =Search-Entry========================================================== */ + +static void sysdb_search_entry_done(struct tevent_req *subreq); + +struct tevent_req *sysdb_search_entry_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct ldb_dn *base_dn, + const char *filter, + const char **attrs) { - struct delete_ctx *del_ctx; - struct sysdb_cb_ctx *cbctx; - struct sysdb_ctx *ctx; - struct ldb_request *delreq; - struct ldb_result *res; - struct ldb_dn *dn; - int ret, err; + struct tevent_req *req, *subreq; + struct sysdb_op_state *state; + struct ldb_request *ldbreq; + int ret; + + req = tevent_req_create(mem_ctx, &state, struct sysdb_op_state); + if (!req) return NULL; - del_ctx = talloc_get_type(req->context, struct delete_ctx); - ctx = sysdb_handle_get_ctx(del_ctx->handle); - cbctx = del_ctx->cbctx; - res = del_ctx->res; + state->ev = ev; + state->handle = handle; + state->ignore_not_found = false; + state->ldbreply = NULL; + + ret = ldb_build_search_req(&ldbreq, handle->ctx->ldb, state, + base_dn, LDB_SCOPE_SUBTREE, + filter, attrs, NULL, NULL, NULL, NULL); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Failed to build search request: %s(%d)[%s]\n", + ldb_strerror(ret), ret, ldb_errstring(handle->ctx->ldb))); + ERROR_OUT(ret, sysdb_error_to_errno(ret), fail); + } - if (!rep) { - return sysdb_ret_error(cbctx, EIO, LDB_ERR_OPERATIONS_ERROR); + subreq = sldb_request_send(state, ev, handle->ctx->ldb, ldbreq); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); } - if (rep->error != LDB_SUCCESS) { - err = sysdb_error_to_errno(rep->error); - return sysdb_ret_error(cbctx, err, rep->error); + tevent_req_set_callback(subreq, sysdb_search_entry_done, req); + + return req; + +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} + +static void sysdb_search_entry_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_op_state *state = tevent_req_data(req, + struct sysdb_op_state); + struct ldb_reply *ldbreply; + int ret; + + ret = sldb_request_recv(subreq, state, &ldbreply); + if (ret) { + tevent_req_error(req, ret); + return; } - switch (rep->type) { + switch (ldbreply->type) { case LDB_REPLY_ENTRY: - if (res->msgs != NULL) { + if (state->ldbreply) { DEBUG(1, ("More than one reply for a base search ?! " "DB seems corrupted, aborting.")); - return sysdb_ret_error(cbctx, EFAULT, LDB_ERR_OPERATIONS_ERROR); - } - res->msgs = talloc_realloc(res, res->msgs, struct ldb_message *, 2); - if (!res->msgs) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); + tevent_req_error(req, EFAULT); + return; } - res->msgs[0] = talloc_steal(res->msgs, rep->message); - res->msgs[1] = NULL; - res->count = 1; + /* save the entry so that it can be retrieved by the caller */ + state->ldbreply = ldbreply; - break; + /* just return, wait for a LDB_REPLY_DONE entry */ + return; case LDB_REPLY_DONE: - - if (res->count == 0) { - DEBUG(7, ("Base search returned no results\n")); - return sysdb_ret_done(cbctx); + if (!state->ldbreply) { + talloc_zfree(ldbreply); + tevent_req_error(req, ENOENT); + return; } + talloc_zfree(ldbreply); + return tevent_req_done(req); - dn = ldb_dn_copy(del_ctx, res->msgs[0]->dn); - if (!dn) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } - - talloc_free(res); - del_ctx->res = res = NULL; + default: + /* unexpected stuff */ + talloc_zfree(ldbreply); + tevent_req_error(req, EIO); + return; + } +} - ret = ldb_build_del_req(&delreq, ctx->ldb, cbctx, dn, NULL, - cbctx, sysdb_op_callback, NULL); - if (ret == LDB_SUCCESS) { - ret = ldb_request(ctx->ldb, delreq); - } - if (ret != LDB_SUCCESS) { - err = sysdb_error_to_errno(ret); - return sysdb_ret_error(cbctx, err, ret); - } - break; +int sysdb_search_entry_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + struct ldb_message **msg) +{ + struct sysdb_op_state *state = tevent_req_data(req, + struct sysdb_op_state); + enum tevent_req_state tstate; + uint64_t err; - default: - return sysdb_ret_error(cbctx, EINVAL, LDB_ERR_OPERATIONS_ERROR); + if (tevent_req_is_error(req, &tstate, &err)) { + return err; } - talloc_free(rep); - return LDB_SUCCESS; + *msg = talloc_move(mem_ctx, &state->ldbreply->message); + + return EOK; } -int sysdb_delete_user_by_uid(struct sysdb_handle *handle, - struct sss_domain_info *domain, - uid_t uid, - sysdb_callback_t fn, void *pvt) + +/* =Search-User-by-[UID/NAME]============================================= */ + +struct sysdb_search_user_state { + struct tevent_context *ev; + struct sysdb_handle *handle; + + struct ldb_message *msg; +}; + +static void sysdb_search_user_done(struct tevent_req *subreq); + +struct tevent_req *sysdb_search_user_by_name_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name) { + struct tevent_req *req, *subreq; + struct sysdb_search_user_state *state; static const char *attrs[] = { SYSDB_NAME, SYSDB_UIDNUM, NULL }; - struct delete_ctx *del_ctx; - struct sysdb_ctx *ctx; struct ldb_dn *base_dn; - struct ldb_request *req; char *filter; int ret; - if (!sysdb_handle_check_running(handle)) { - DEBUG(2, ("Invalid request! Not running at this time.\n")); - return EINVAL; - } - - ctx = sysdb_handle_get_ctx(handle); - - del_ctx = talloc_zero(handle, struct delete_ctx); - if (!del_ctx) return ENOMEM; + req = tevent_req_create(mem_ctx, &state, struct sysdb_search_user_state); + if (!req) return NULL; - del_ctx->cbctx = talloc_zero(del_ctx, struct sysdb_cb_ctx); - if (!del_ctx->cbctx) return ENOMEM; + state->ev = ev; + state->handle = handle; + state->msg = NULL; - del_ctx->handle = handle; - del_ctx->cbctx->fn = fn; - del_ctx->cbctx->pvt = pvt; - del_ctx->cbctx->ignore_not_found = true; - - del_ctx->res = talloc_zero(del_ctx, struct ldb_result); - if (!del_ctx->res) return ENOMEM; - - base_dn = ldb_dn_new_fmt(del_ctx, ctx->ldb, + base_dn = ldb_dn_new_fmt(state, handle->ctx->ldb, SYSDB_TMPL_USER_BASE, domain->name); - if (!base_dn) return ENOMEM; + if (!base_dn) + ERROR_OUT(ret, ENOMEM, fail); - filter = talloc_asprintf(del_ctx, SYSDB_PWUID_FILTER, (unsigned long)uid); - if (!filter) return ENOMEM; + filter = talloc_asprintf(state, SYSDB_PWNAM_FILTER, name); + if (!filter) + ERROR_OUT(ret, ENOMEM, fail); - ret = ldb_build_search_req(&req, ctx->ldb, del_ctx, - base_dn, LDB_SCOPE_ONELEVEL, - filter, attrs, NULL, - del_ctx, delete_callback, NULL); - if (ret != LDB_SUCCESS) { - DEBUG(1, ("Failed to build search request: %s(%d)[%s]\n", - ldb_strerror(ret), ret, ldb_errstring(ctx->ldb))); - return sysdb_error_to_errno(ret); + subreq = sysdb_search_entry_send(state, ev, handle, + base_dn, filter, attrs); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); } + tevent_req_set_callback(subreq, sysdb_search_user_done, req); - ret = ldb_request(ctx->ldb, req); - if (ret != LDB_SUCCESS) return sysdb_error_to_errno(ret); + return req; - return EOK; +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; } -int sysdb_delete_group_by_gid(struct sysdb_handle *handle, - struct sss_domain_info *domain, - gid_t gid, - sysdb_callback_t fn, void *pvt) +struct tevent_req *sysdb_search_user_by_uid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + uid_t uid) { - static const char *attrs[] = { SYSDB_NAME, SYSDB_GIDNUM, NULL }; - struct delete_ctx *del_ctx; - struct sysdb_ctx *ctx; + struct tevent_req *req, *subreq; + struct sysdb_search_user_state *state; + static const char *attrs[] = { SYSDB_NAME, SYSDB_UIDNUM, NULL }; struct ldb_dn *base_dn; - struct ldb_request *req; char *filter; int ret; - if (!sysdb_handle_check_running(handle)) { - DEBUG(2, ("Invalid request! Not running at this time.\n")); - return EINVAL; - } + req = tevent_req_create(mem_ctx, &state, struct sysdb_search_user_state); + if (!req) return NULL; - ctx = sysdb_handle_get_ctx(handle); + state->ev = ev; + state->handle = handle; + state->msg = NULL; - del_ctx = talloc_zero(handle, struct delete_ctx); - if (!del_ctx) return ENOMEM; + base_dn = ldb_dn_new_fmt(state, handle->ctx->ldb, + SYSDB_TMPL_USER_BASE, domain->name); + if (!base_dn) + ERROR_OUT(ret, ENOMEM, fail); - del_ctx->cbctx = talloc_zero(del_ctx, struct sysdb_cb_ctx); - if (!del_ctx->cbctx) return ENOMEM; + filter = talloc_asprintf(state, SYSDB_PWUID_FILTER, (unsigned long)uid); + if (!filter) + ERROR_OUT(ret, ENOMEM, fail); - del_ctx->handle = handle; - del_ctx->cbctx->fn = fn; - del_ctx->cbctx->pvt = pvt; - del_ctx->cbctx->ignore_not_found = true; + subreq = sysdb_search_entry_send(state, ev, handle, + base_dn, filter, attrs); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_search_user_done, req); - del_ctx->res = talloc_zero(del_ctx, struct ldb_result); - if (!del_ctx->res) return ENOMEM; + return req; - base_dn = ldb_dn_new_fmt(del_ctx, ctx->ldb, - SYSDB_TMPL_GROUP_BASE, domain->name); - if (!base_dn) return ENOMEM; +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} - filter = talloc_asprintf(del_ctx, SYSDB_GRGID_FILTER, (unsigned long)gid); - if (!filter) return ENOMEM; +static void sysdb_search_user_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_search_user_state *state = tevent_req_data(req, + struct sysdb_search_user_state); + int ret; - ret = ldb_build_search_req(&req, ctx->ldb, del_ctx, - base_dn, LDB_SCOPE_ONELEVEL, - filter, attrs, NULL, - del_ctx, delete_callback, NULL); - if (ret != LDB_SUCCESS) { - DEBUG(1, ("Failed to build search request: %s(%d)[%s]\n", - ldb_strerror(ret), ret, ldb_errstring(ctx->ldb))); - return sysdb_error_to_errno(ret); + ret = sysdb_search_entry_recv(subreq, state, &state->msg); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; } - ret = ldb_request(ctx->ldb, req); - if (ret != LDB_SUCCESS) return sysdb_error_to_errno(ret); - - return EOK; + tevent_req_done(req); } -int sysdb_set_user_attr(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *name, - struct sysdb_attrs *attrs, - sysdb_callback_t fn, void *pvt) +int sysdb_search_user_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + struct ldb_message **msg) { - struct sysdb_ctx *ctx; - struct sysdb_cb_ctx *cbctx; - struct ldb_message *msg; - struct ldb_request *req; - int i, ret; + struct sysdb_search_user_state *state = tevent_req_data(req, + struct sysdb_search_user_state); + enum tevent_req_state tstate; + uint64_t err; - if (!sysdb_handle_check_running(handle)) { - DEBUG(2, ("Invalid request! Not running at this time.\n")); - return EINVAL; + if (tevent_req_is_error(req, &tstate, &err)) { + return err; } - if (attrs->num == 0) return EINVAL; + *msg = talloc_move(mem_ctx, &state->msg); + + return EOK; +} - ctx = sysdb_handle_get_ctx(handle); - cbctx = talloc_zero(handle, struct sysdb_cb_ctx); - if (!cbctx) return ENOMEM; +/* =Delete-User-by-UID==================================================== */ - cbctx->fn = fn; - cbctx->pvt = pvt; +static void sysdb_delete_user_by_uid_found(struct tevent_req *subreq); +static void sysdb_delete_user_by_uid_done(struct tevent_req *subreq); - msg = ldb_msg_new(cbctx); - if (!msg) return ENOMEM; +struct tevent_req *sysdb_delete_user_by_uid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + uid_t uid) +{ + struct tevent_req *req, *subreq; + struct sysdb_op_state *state; - msg->dn = sysdb_user_dn(ctx, msg, domain->name, name); - if (!msg->dn) return ENOMEM; + req = tevent_req_create(mem_ctx, &state, struct sysdb_op_state); + if (!req) return NULL; - msg->elements = talloc_array(msg, struct ldb_message_element, attrs->num); - if (!msg->elements) return ENOMEM; + state->ev = ev; + state->handle = handle; + state->ignore_not_found = true; + state->ldbreply = NULL; - for (i = 0; i < attrs->num; i++) { - msg->elements[i] = attrs->a[i]; - msg->elements[i].flags = LDB_FLAG_MOD_REPLACE; + subreq = sysdb_search_user_by_uid_send(state, ev, handle, domain, uid); + if (!subreq) { + talloc_zfree(req); + return NULL; } + tevent_req_set_callback(subreq, sysdb_delete_user_by_uid_found, req); - msg->num_elements = attrs->num; + return req; +} - ret = ldb_build_mod_req(&req, ctx->ldb, cbctx, msg, NULL, - cbctx, sysdb_op_callback, NULL); - if (ret == LDB_SUCCESS) { - ret = ldb_request(ctx->ldb, req); +static void sysdb_delete_user_by_uid_found(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_op_state *state = tevent_req_data(req, + struct sysdb_op_state); + struct ldb_message *msg; + int ret; + + ret = sysdb_search_user_recv(subreq, state, &msg); + talloc_zfree(subreq); + if (ret) { + if (state->ignore_not_found && ret == ENOENT) { + return tevent_req_done(req); + } + tevent_req_error(req, ret); + return; } - if (ret != LDB_SUCCESS) { - return sysdb_error_to_errno(ret); + + subreq = sysdb_delete_entry_send(state, state->ev, state->handle, msg->dn); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; } + tevent_req_set_callback(subreq, sysdb_delete_user_by_uid_done, req); +} - return EOK; +static void sysdb_delete_user_by_uid_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + int ret; + + ret = sysdb_delete_entry_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + tevent_req_done(req); } -struct next_id { - uint32_t id; -}; +int sysdb_delete_user_by_uid_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); +} -struct next_id_ctx { - struct sysdb_handle *handle; - struct sss_domain_info *domain; - struct sysdb_cb_ctx *cbctx; - struct ldb_dn *base_dn; - struct ldb_result *res; - uint32_t tmp_id; +/* =Search-Group-by-[GID/NAME]============================================ */ - enum next_step { NEXTID_SEARCH=0, NEXTID_VERIFY, NEXTID_STORE } step; +struct sysdb_search_group_state { + struct tevent_context *ev; + struct sysdb_handle *handle; - struct next_id *result; + struct ldb_message *msg; }; -static int nextid_callback(struct ldb_request *req, struct ldb_reply *rep); +static void sysdb_search_group_done(struct tevent_req *subreq); -static int sysdb_get_next_available_id(struct sysdb_handle *handle, - struct sss_domain_info *domain, - struct next_id *result, - sysdb_callback_t fn, void *pvt) +struct tevent_req *sysdb_search_group_by_name_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name) { - static const char *attrs[] = { SYSDB_NEXTID, NULL }; - struct sysdb_ctx *ctx; - struct next_id_ctx *idctx; - struct ldb_request *req; + struct tevent_req *req, *subreq; + struct sysdb_search_group_state *state; + static const char *attrs[] = { SYSDB_NAME, SYSDB_GIDNUM, NULL }; + struct ldb_dn *base_dn; + char *filter; int ret; - if (!sysdb_handle_check_running(handle)) { - DEBUG(2, ("Invalid request! Not running at this time.\n")); - return EINVAL; - } - - ctx = sysdb_handle_get_ctx(handle); - - idctx = talloc_zero(handle, struct next_id_ctx); - if (!idctx) return ENOMEM; + req = tevent_req_create(mem_ctx, &state, struct sysdb_search_group_state); + if (!req) return NULL; - idctx->handle = handle; - idctx->domain = domain; - idctx->result = result; + state->ev = ev; + state->handle = handle; + state->msg = NULL; - idctx->cbctx = talloc_zero(handle, struct sysdb_cb_ctx); - if (!idctx->cbctx) return ENOMEM; - - idctx->cbctx->fn = fn; - idctx->cbctx->pvt = pvt; - - idctx->base_dn = sysdb_domain_dn(ctx, idctx, domain->name); - if (!idctx->base_dn) return ENOMEM; + base_dn = ldb_dn_new_fmt(state, handle->ctx->ldb, + SYSDB_TMPL_GROUP_BASE, domain->name); + if (!base_dn) + ERROR_OUT(ret, ENOMEM, fail); - idctx->res = talloc_zero(idctx, struct ldb_result); - if (!idctx->res) return ENOMEM; + filter = talloc_asprintf(state, SYSDB_GRNAM_FILTER, name); + if (!filter) + ERROR_OUT(ret, ENOMEM, fail); - ret = ldb_build_search_req(&req, ctx->ldb, idctx, - idctx->base_dn, LDB_SCOPE_BASE, - SYSDB_NEXTID_FILTER, attrs, NULL, - idctx, nextid_callback, NULL); - if (ret != LDB_SUCCESS) { - DEBUG(1, ("Failed to build search request: %s(%d)[%s]\n", - ldb_strerror(ret), ret, ldb_errstring(ctx->ldb))); - return sysdb_error_to_errno(ret); + subreq = sysdb_search_entry_send(state, ev, handle, + base_dn, filter, attrs); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); } + tevent_req_set_callback(subreq, sysdb_search_group_done, req); - ret = ldb_request(ctx->ldb, req); - if (ret != LDB_SUCCESS) return sysdb_error_to_errno(ret); + return req; - return EOK; +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; } -static int nextid_callback(struct ldb_request *req, struct ldb_reply *rep) +struct tevent_req *sysdb_search_group_by_gid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + gid_t gid) { - static const char *attrs[] = { SYSDB_UIDNUM, SYSDB_GIDNUM, NULL }; - struct next_id_ctx *idctx; - struct sysdb_cb_ctx *cbctx; - struct sysdb_ctx *ctx; - struct ldb_request *nreq; - struct ldb_message *msg; - struct ldb_result *res; + struct tevent_req *req, *subreq; + struct sysdb_search_group_state *state; + static const char *attrs[] = { SYSDB_NAME, SYSDB_GIDNUM, NULL }; + struct ldb_dn *base_dn; char *filter; - int ret, err; + int ret; - idctx = talloc_get_type(req->context, struct next_id_ctx); - ctx = sysdb_handle_get_ctx(idctx->handle); - cbctx = idctx->cbctx; - res = idctx->res; + req = tevent_req_create(mem_ctx, &state, struct sysdb_search_group_state); + if (!req) return NULL; - if (!rep) { - return sysdb_ret_error(cbctx, EIO, LDB_ERR_OPERATIONS_ERROR); - } - if (rep->error != LDB_SUCCESS) { - err = sysdb_error_to_errno(rep->error); - return sysdb_ret_error(cbctx, err, rep->error); - } + state->ev = ev; + state->handle = handle; + state->msg = NULL; - switch (rep->type) { - case LDB_REPLY_ENTRY: + base_dn = ldb_dn_new_fmt(state, handle->ctx->ldb, + SYSDB_TMPL_GROUP_BASE, domain->name); + if (!base_dn) + ERROR_OUT(ret, ENOMEM, fail); - if (idctx->step == NEXTID_VERIFY) { - res->count++; - break; - } + filter = talloc_asprintf(state, SYSDB_GRGID_FILTER, (unsigned long)gid); + if (!filter) + ERROR_OUT(ret, ENOMEM, fail); - /* NEXTID_SEARCH */ - if (res->msgs != NULL) { - DEBUG(1, ("More than one reply for a base search ?! " - "DB seems corrupted, aborting.")); - return sysdb_ret_error(cbctx, EFAULT, LDB_ERR_OPERATIONS_ERROR); - } + subreq = sysdb_search_entry_send(state, ev, handle, + base_dn, filter, attrs); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_search_group_done, req); - res->msgs = talloc_realloc(res, res->msgs, struct ldb_message *, 2); - if (!res->msgs) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } + return req; - res->msgs[0] = talloc_steal(res->msgs, rep->message); - res->msgs[1] = NULL; - res->count = 1; +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} - break; +static void sysdb_search_group_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_search_group_state *state = tevent_req_data(req, + struct sysdb_search_group_state); + int ret; - case LDB_REPLY_DONE: + ret = sysdb_search_entry_recv(subreq, state, &state->msg); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } - switch (idctx->step) { - case NEXTID_SEARCH: - if (res->count != 0) { - idctx->tmp_id = get_attr_as_uint32(res->msgs[0], SYSDB_NEXTID); - if (idctx->tmp_id == (uint32_t)(-1)) { - DEBUG(1, ("Invalid Next ID in domain %s\n", - idctx->domain->name)); - return sysdb_ret_error(cbctx, ERANGE, LDB_ERR_OPERATIONS_ERROR); - } - } else { - DEBUG(4, ("Base search returned no results, adding min id!\n")); - } + tevent_req_done(req); +} - if (idctx->tmp_id < idctx->domain->id_min) { - DEBUG(2, ("Initializing domain next id to id min %u\n", - idctx->domain->id_min)); - idctx->tmp_id = idctx->domain->id_min; - } - if ((idctx->domain->id_max != 0) && - (idctx->tmp_id > idctx->domain->id_max)) { - DEBUG(0, ("Failed to allocate new id, out of range (%u/%u)\n", - idctx->tmp_id, idctx->domain->id_max)); - return sysdb_ret_error(cbctx, ERANGE, LDB_ERR_OPERATIONS_ERROR); - } +int sysdb_search_group_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + struct ldb_message **msg) +{ + struct sysdb_search_group_state *state = tevent_req_data(req, + struct sysdb_search_group_state); + enum tevent_req_state tstate; + uint64_t err; - talloc_free(res->msgs); - res->msgs = NULL; - res->count = 0; + if (tevent_req_is_error(req, &tstate, &err)) { + return err; + } - idctx->step = NEXTID_VERIFY; - break; + *msg = talloc_move(mem_ctx, &state->msg); - case NEXTID_VERIFY: - if (res->count) { - /* actually something's using the id, try next */ - idctx->tmp_id++; - } else { - /* ok store new next_id */ - idctx->result->id = idctx->tmp_id; - idctx->tmp_id++; - idctx->step = NEXTID_STORE; - } - break; + return EOK; +} - default: - DEBUG(1, ("Invalid step, aborting.\n")); - return sysdb_ret_error(cbctx, EFAULT, LDB_ERR_OPERATIONS_ERROR); - } - switch (idctx->step) { - case NEXTID_VERIFY: - filter = talloc_asprintf(idctx, "(|(%s=%u)(%s=%u))", - SYSDB_UIDNUM, idctx->tmp_id, - SYSDB_GIDNUM, idctx->tmp_id); - if (!filter) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } - ret = ldb_build_search_req(&nreq, ctx->ldb, idctx, - idctx->base_dn, LDB_SCOPE_SUBTREE, - filter, attrs, NULL, - idctx, nextid_callback, NULL); - break; - - case NEXTID_STORE: - msg = ldb_msg_new(idctx); - if (!msg) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } +/* =Delete-Group-by-GID=================================================== */ - msg->dn = idctx->base_dn; +static void sysdb_delete_group_by_gid_found(struct tevent_req *subreq); +static void sysdb_delete_group_by_gid_done(struct tevent_req *subreq); - ret = add_ulong(msg, LDB_FLAG_MOD_REPLACE, - SYSDB_NEXTID, idctx->tmp_id); - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } +struct tevent_req *sysdb_delete_group_by_gid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + gid_t gid) +{ + struct tevent_req *req, *subreq; + struct sysdb_op_state *state; - ret = ldb_build_mod_req(&nreq, ctx->ldb, idctx, msg, NULL, - cbctx, sysdb_op_callback, NULL); - break; + req = tevent_req_create(mem_ctx, &state, struct sysdb_op_state); + if (!req) return NULL; - default: - DEBUG(1, ("Invalid step, aborting.\n")); - return sysdb_ret_error(cbctx, EFAULT, LDB_ERR_OPERATIONS_ERROR); - } + state->ev = ev; + state->handle = handle; + state->ignore_not_found = true; + state->ldbreply = NULL; - if (ret != LDB_SUCCESS) { - DEBUG(1, ("Failed to build search request: %s(%d)[%s]\n", - ldb_strerror(ret), ret, ldb_errstring(ctx->ldb))); - err = sysdb_error_to_errno(ret); - return sysdb_ret_error(cbctx, err, ret); - } + subreq = sysdb_search_group_by_gid_send(state, ev, handle, domain, gid); + if (!subreq) { + talloc_zfree(req); + return NULL; + } + tevent_req_set_callback(subreq, sysdb_delete_group_by_gid_found, req); - ret = ldb_request(ctx->ldb, nreq); - if (ret != LDB_SUCCESS) { - err = sysdb_error_to_errno(ret); - return sysdb_ret_error(cbctx, err, ret); - } + return req; +} - break; +static void sysdb_delete_group_by_gid_found(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_op_state *state = tevent_req_data(req, + struct sysdb_op_state); + struct ldb_message *msg; + int ret; - default: - return sysdb_ret_error(cbctx, EINVAL, LDB_ERR_OPERATIONS_ERROR); + ret = sysdb_search_group_recv(subreq, state, &msg); + talloc_zfree(subreq); + if (ret) { + if (state->ignore_not_found && ret == ENOENT) { + return tevent_req_done(req); + } + tevent_req_error(req, ret); + return; } - talloc_free(rep); - return LDB_SUCCESS; + subreq = sysdb_delete_entry_send(state, state->ev, state->handle, msg->dn); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_delete_group_by_gid_done, req); } -static int check_name_callback(struct ldb_request *req, struct ldb_reply *rep); - -int sysdb_check_name_unique(struct sysdb_handle *handle, - struct sss_domain_info *domain, - TALLOC_CTX *mem_ctx, const char *name, - sysdb_callback_t fn, void *pvt) +static void sysdb_delete_group_by_gid_done(struct tevent_req *subreq) { - static const char *attrs[] = { SYSDB_NAME, NULL }; - struct sysdb_cb_ctx *cbctx; - struct sysdb_ctx *ctx; - struct ldb_dn *base_dn; - struct ldb_request *req; - char *filter; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); int ret; - if (!sysdb_handle_check_running(handle)) { - DEBUG(2, ("Invalid request! Not running at this time.\n")); - return EINVAL; + ret = sysdb_delete_entry_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; } - ctx = sysdb_handle_get_ctx(handle); - - cbctx = talloc_zero(mem_ctx, struct sysdb_cb_ctx); - if (!cbctx) return ENOMEM; + tevent_req_done(req); +} - cbctx->fn = fn; - cbctx->pvt = pvt; +int sysdb_delete_group_by_gid_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); +} - base_dn = sysdb_domain_dn(ctx, cbctx, domain->name); - if (!base_dn) return ENOMEM; - filter = talloc_asprintf(cbctx, SYSDB_CHECK_FILTER, name); - if (!filter) return ENOMEM; +/* =Replace-Attributes-On-Entry=========================================== */ - ret = ldb_build_search_req(&req, ctx->ldb, mem_ctx, - base_dn, LDB_SCOPE_SUBTREE, - filter, attrs, NULL, - cbctx, check_name_callback, NULL); +struct tevent_req *sysdb_set_entry_attr_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct ldb_dn *entry_dn, + struct sysdb_attrs *attrs, + int mod_op) +{ + struct tevent_req *req, *subreq; + struct sysdb_op_state *state; + struct ldb_request *ldbreq; + struct ldb_message *msg; + int i, ret; + + req = tevent_req_create(mem_ctx, &state, struct sysdb_op_state); + if (!req) return NULL; + + state->ev = ev; + state->handle = handle; + state->ignore_not_found = false; + state->ldbreply = NULL; + + if (!entry_dn) { + ERROR_OUT(ret, EINVAL, fail); + } + + if (attrs->num == 0) { + ERROR_OUT(ret, EINVAL, fail); + } + + msg = ldb_msg_new(state); + if (!msg) { + ERROR_OUT(ret, ENOMEM, fail); + } + + msg->dn = entry_dn; + + msg->elements = talloc_array(msg, struct ldb_message_element, attrs->num); + if (!msg->elements) { + ERROR_OUT(ret, ENOMEM, fail); + } + + for (i = 0; i < attrs->num; i++) { + msg->elements[i] = attrs->a[i]; + msg->elements[i].flags = mod_op; + } + + msg->num_elements = attrs->num; + + ret = ldb_build_mod_req(&ldbreq, handle->ctx->ldb, state, msg, + NULL, NULL, NULL, NULL); if (ret != LDB_SUCCESS) { - DEBUG(1, ("Failed to build search request: %s(%d)[%s]\n", - ldb_strerror(ret), ret, ldb_errstring(ctx->ldb))); - return sysdb_error_to_errno(ret); + DEBUG(1, ("Failed to build modify request: %s(%d)[%s]\n", + ldb_strerror(ret), ret, ldb_errstring(handle->ctx->ldb))); + ERROR_OUT(ret, sysdb_error_to_errno(ret), fail); } - ret = ldb_request(ctx->ldb, req); - if (ret != LDB_SUCCESS) return sysdb_error_to_errno(ret); + subreq = sldb_request_send(state, ev, handle->ctx->ldb, ldbreq); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_op_default_done, req); - return EOK; + return req; + +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; } -static int check_name_callback(struct ldb_request *req, struct ldb_reply *rep) +int sysdb_set_entry_attr_recv(struct tevent_req *req) { - struct sysdb_cb_ctx *cbctx; - int err; + return sysdb_op_default_recv(req); +} + + +/* =Replace-Attributes-On-User============================================ */ + +static void sysdb_set_user_attr_done(struct tevent_req *subreq); + +struct tevent_req *sysdb_set_user_attr_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, + struct sysdb_attrs *attrs, + int mod_op) +{ + struct tevent_req *req, *subreq; + struct sysdb_op_state *state; + struct ldb_dn *dn; + int ret; + + req = tevent_req_create(mem_ctx, &state, struct sysdb_op_state); + if (!req) return NULL; + + state->ev = ev; + state->handle = handle; + state->ignore_not_found = false; + state->ldbreply = NULL; + + dn = sysdb_user_dn(handle->ctx, state, domain->name, name); + if (!dn) { + ERROR_OUT(ret, ENOMEM, fail); + } + + subreq = sysdb_set_entry_attr_send(state, ev, handle, dn, attrs, mod_op); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_set_user_attr_done, req); + + return req; + +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} + +static void sysdb_set_user_attr_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + int ret; + + ret = sysdb_set_entry_attr_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + tevent_req_done(req); +} + +int sysdb_set_user_attr_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); +} + + +/* =Replace-Attributes-On-Group=========================================== */ + +static void sysdb_set_group_attr_done(struct tevent_req *subreq); + +struct tevent_req *sysdb_set_group_attr_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, + struct sysdb_attrs *attrs, + int mod_op) +{ + struct tevent_req *req, *subreq; + struct sysdb_op_state *state; + struct ldb_dn *dn; + int ret; + + req = tevent_req_create(mem_ctx, &state, struct sysdb_op_state); + if (!req) return NULL; + + state->ev = ev; + state->handle = handle; + state->ignore_not_found = false; + state->ldbreply = NULL; + + dn = sysdb_group_dn(handle->ctx, state, domain->name, name); + if (!dn) { + ERROR_OUT(ret, ENOMEM, fail); + } + + subreq = sysdb_set_entry_attr_send(state, ev, handle, dn, attrs, mod_op); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_set_group_attr_done, req); + + return req; + +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} + +static void sysdb_set_group_attr_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + int ret; + + ret = sysdb_set_entry_attr_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + tevent_req_done(req); +} + +int sysdb_set_group_attr_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); +} + + +/* =Get-New-ID============================================================ */ + +struct sysdb_get_new_id_state { + struct tevent_context *ev; + struct sysdb_handle *handle; + struct sss_domain_info *domain; + + struct ldb_dn *base_dn; + struct ldb_message *base; + + struct ldb_message **v_msgs; + int v_count; + + uint32_t new_id; +}; + +static void sysdb_get_new_id_base(struct tevent_req *subreq); +static void sysdb_get_new_id_verify(struct tevent_req *subreq); +static void sysdb_get_new_id_done(struct tevent_req *subreq); + +struct tevent_req *sysdb_get_new_id_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain) +{ + struct tevent_req *req, *subreq; + struct sysdb_get_new_id_state *state; + static const char *attrs[] = { SYSDB_NEXTID, NULL }; + struct ldb_request *ldbreq; + int ret; + + req = tevent_req_create(mem_ctx, &state, struct sysdb_get_new_id_state); + if (!req) return NULL; + + state->ev = ev; + state->handle = handle; + state->domain = domain; + state->base = NULL; + state->v_msgs = NULL; + state->v_count = 0; + state->new_id = 0; + + state->base_dn = sysdb_domain_dn(handle->ctx, state, domain->name); + if (!state->base_dn) { + ERROR_OUT(ret, ENOMEM, fail); + } - cbctx = talloc_get_type(req->context, struct sysdb_cb_ctx); + ret = ldb_build_search_req(&ldbreq, handle->ctx->ldb, state, + state->base_dn, LDB_SCOPE_BASE, + SYSDB_NEXTID_FILTER, attrs, + NULL, NULL, NULL, NULL); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Failed to build search request: %s(%d)[%s]\n", + ldb_strerror(ret), ret, ldb_errstring(handle->ctx->ldb))); + ERROR_OUT(ret, sysdb_error_to_errno(ret), fail); + } - if (!rep) { - return sysdb_ret_error(cbctx, EIO, LDB_ERR_OPERATIONS_ERROR); + subreq = sldb_request_send(state, ev, handle->ctx->ldb, ldbreq); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); } - if (rep->error != LDB_SUCCESS) { - err = sysdb_error_to_errno(rep->error); - return sysdb_ret_error(cbctx, err, rep->error); + tevent_req_set_callback(subreq, sysdb_get_new_id_base, req); + + return req; + +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} + +static void sysdb_get_new_id_base(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_get_new_id_state *state = tevent_req_data(req, + struct sysdb_get_new_id_state); + static const char *attrs[] = { SYSDB_UIDNUM, SYSDB_GIDNUM, NULL }; + struct ldb_reply *ldbreply; + struct ldb_request *ldbreq; + char *filter; + int ret; + + ret = sldb_request_recv(subreq, state, &ldbreply); + if (ret) { + talloc_zfree(subreq); + tevent_req_error(req, ret); + return; } - switch (rep->type) { + switch (ldbreply->type) { case LDB_REPLY_ENTRY: + if (state->base) { + DEBUG(1, ("More than one reply for a base search ?! " + "DB seems corrupted, aborting.")); + tevent_req_error(req, EFAULT); + return; + } - /* one found, that means name is not available */ - /* return EEXIST */ - return sysdb_ret_error(cbctx, EEXIST, LDB_ERR_ENTRY_ALREADY_EXISTS); + state->base = talloc_move(state, &ldbreply->message); + if (!state->base) { + tevent_req_error(req, ENOMEM); + return; + } + + /* just return, wait for a LDB_REPLY_DONE entry */ + talloc_zfree(ldbreply); + return; case LDB_REPLY_DONE: + break; + + default: + /* unexpected stuff */ + tevent_req_error(req, EIO); + talloc_zfree(ldbreply); + return; + } + + talloc_zfree(subreq); + + if (state->base) { + state->new_id = get_attr_as_uint32(state->base, SYSDB_NEXTID); + if (state->new_id == (uint32_t)(-1)) { + DEBUG(1, ("Invalid Next ID in domain %s\n", state->domain->name)); + tevent_req_error(req, ERANGE); + return; + } + + if (state->new_id < state->domain->id_min) { + state->new_id = state->domain->id_min; + } + + if ((state->domain->id_max != 0) && + (state->new_id > state->domain->id_max)) { + DEBUG(0, ("Failed to allocate new id, out of range (%u/%u)\n", + state->new_id, state->domain->id_max)); + tevent_req_error(req, ERANGE); + return; + } + + } else { + /* looks like the domain is not initialized yet, use min_id */ + state->new_id = state->domain->id_min; + } + + /* verify the id is actually really free. + * search all entries with id >= new_id and < max_id */ + filter = talloc_asprintf(state, + "(|(&(%s>=%u)(%s<=%u))(&(%s>=%u)(%s<=%u)))", + SYSDB_UIDNUM, state->new_id, + SYSDB_UIDNUM, state->domain->id_max, + SYSDB_GIDNUM, state->new_id, + SYSDB_GIDNUM, state->domain->id_max); + if (!filter) { + tevent_req_error(req, ENOMEM); + return; + } - return sysdb_ret_done(cbctx); + ret = ldb_build_search_req(&ldbreq, state->handle->ctx->ldb, state, + state->base_dn, LDB_SCOPE_SUBTREE, + filter, attrs, + NULL, NULL, NULL, NULL); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Failed to build search request: %s(%d)[%s]\n", + ldb_strerror(ret), ret, + ldb_errstring(state->handle->ctx->ldb))); + tevent_req_error(req, sysdb_error_to_errno(ret)); + return; + } + + subreq = sldb_request_send(state, state->ev, + state->handle->ctx->ldb, ldbreq); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_get_new_id_verify, req); + + return; +} + +static void sysdb_get_new_id_verify(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_get_new_id_state *state = tevent_req_data(req, + struct sysdb_get_new_id_state); + struct ldb_reply *ldbreply; + struct ldb_request *ldbreq; + struct ldb_message *msg; + int ret, i; + + ret = sldb_request_recv(subreq, state, &ldbreply); + if (ret) { + talloc_zfree(subreq); + tevent_req_error(req, ret); + return; + } + + switch (ldbreply->type) { + case LDB_REPLY_ENTRY: + state->v_msgs = talloc_realloc(state, state->v_msgs, + struct ldb_message *, + state->v_count + 2); + if (!state->v_msgs) { + tevent_req_error(req, ENOMEM); + return; + } + + state->v_msgs[state->v_count] = talloc_move(state, &ldbreply->message); + if (!state->v_msgs[state->v_count]) { + tevent_req_error(req, ENOMEM); + return; + } + state->v_count++; + + /* just return, wait for a LDB_REPLY_DONE entry */ + talloc_zfree(ldbreply); + return; + + case LDB_REPLY_DONE: + break; default: - return sysdb_ret_error(cbctx, EINVAL, LDB_ERR_OPERATIONS_ERROR); + /* unexpected stuff */ + tevent_req_error(req, EIO); + talloc_zfree(ldbreply); + return; + } + + talloc_zfree(subreq); + + /* if anything was found, find the maximum and increment past it */ + if (state->v_count) { + uint32_t id; + + for (i = 0; i < state->v_count; i++) { + id = get_attr_as_uint32(state->v_msgs[i], SYSDB_UIDNUM); + if (id != (uint32_t)(-1)) { + if (id > state->new_id) state->new_id = id; + } + id = get_attr_as_uint32(state->v_msgs[i], SYSDB_GIDNUM); + if (id != (uint32_t)(-1)) { + if (id > state->new_id) state->new_id = id; + } + } + + state->new_id++; + + /* check again we are not falling out of range */ + if ((state->domain->id_max != 0) && + (state->new_id > state->domain->id_max)) { + DEBUG(0, ("Failed to allocate new id, out of range (%u/%u)\n", + state->new_id, state->domain->id_max)); + tevent_req_error(req, ERANGE); + return; + } + + talloc_zfree(state->v_msgs); + state->v_count = 0; + } + + /* finally store the new next id */ + msg = ldb_msg_new(state); + if (!msg) { + tevent_req_error(req, ENOMEM); + return; + } + msg->dn = state->base->dn; + + ret = add_ulong(msg, LDB_FLAG_MOD_REPLACE, + SYSDB_NEXTID, state->new_id + 1); + if (ret) { + tevent_req_error(req, ret); + return; + } + + ret = ldb_build_mod_req(&ldbreq, state->handle->ctx->ldb, state, msg, + NULL, NULL, NULL, NULL); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Failed to build modify request: %s(%d)[%s]\n", + ldb_strerror(ret), ret, + ldb_errstring(state->handle->ctx->ldb))); + tevent_req_error(req, ret); + return; + } + + subreq = sldb_request_send(state, state->ev, + state->handle->ctx->ldb, ldbreq); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_get_new_id_done, req); +} + +static void sysdb_get_new_id_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_get_new_id_state *state = tevent_req_data(req, + struct sysdb_get_new_id_state); + struct ldb_reply *ldbreply; + int ret; + + ret = sldb_request_recv(subreq, state, &ldbreply); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + if (ldbreply->type != LDB_REPLY_DONE) { + tevent_req_error(req, EIO); + return; + } + + tevent_req_done(req); +} + +int sysdb_get_new_id_recv(struct tevent_req *req, uint32_t *id) +{ + struct sysdb_get_new_id_state *state = tevent_req_data(req, + struct sysdb_get_new_id_state); + enum tevent_req_state tstate; + uint64_t err; + + if (tevent_req_is_error(req, &tstate, &err)) { + return err; + } + + *id = state->new_id; + + return EOK; +} + + +/* =Add-Basic-User-NO-CHECKS============================================== */ + +struct tevent_req *sysdb_add_basic_user_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, + uid_t uid, gid_t gid, + const char *gecos, + const char *homedir, + const char *shell) +{ + struct tevent_req *req, *subreq; + struct sysdb_op_state *state; + struct ldb_request *ldbreq; + struct ldb_message *msg; + int ret; + + req = tevent_req_create(mem_ctx, &state, struct sysdb_op_state); + if (!req) return NULL; + + state->ev = ev; + state->handle = handle; + state->ignore_not_found = false; + state->ldbreply = NULL; + + msg = ldb_msg_new(state); + if (!msg) { + ERROR_OUT(ret, ENOMEM, fail); + } + + /* user dn */ + msg->dn = sysdb_user_dn(handle->ctx, msg, domain->name, name); + if (!msg->dn) { + ERROR_OUT(ret, ENOMEM, fail); + } + + ret = add_string(msg, LDB_FLAG_MOD_ADD, "objectClass", SYSDB_USER_CLASS); + if (ret) goto fail; + + ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_NAME, name); + if (ret) goto fail; + + ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_UIDNUM, (unsigned long)uid); + if (ret) goto fail; + + ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_GIDNUM, (unsigned long)gid); + if (ret) goto fail; + + /* We set gecos to be the same as fullname on user creation, + * But we will not enforce coherency after that, it's up to + * admins to decide if they want to keep it in sync if they change + * one of the 2 */ + if (gecos && *gecos) { + ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_FULLNAME, gecos); + if (ret) goto fail; + ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_GECOS, gecos); + if (ret) goto fail; + } + + if (homedir && *homedir) { + ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_HOMEDIR, homedir); + if (ret) goto fail; } - return LDB_SUCCESS; + if (shell && *shell) { + ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_SHELL, shell); + if (ret) goto fail; + } + + /* creation time */ + ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_CREATE_TIME, + (unsigned long)time(NULL)); + if (ret) goto fail; + + + ret = ldb_build_add_req(&ldbreq, handle->ctx->ldb, state, msg, + NULL, NULL, NULL, NULL); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Failed to build modify request: %s(%d)[%s]\n", + ldb_strerror(ret), ret, ldb_errstring(handle->ctx->ldb))); + ERROR_OUT(ret, sysdb_error_to_errno(ret), fail); + } + + subreq = sldb_request_send(state, ev, handle->ctx->ldb, ldbreq); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_op_default_done, req); + + return req; + +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; } +int sysdb_add_basic_user_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); +} -struct user_add_ctx { + +/* =Add-User-Function===================================================== */ + +struct sysdb_add_user_state { + struct tevent_context *ev; struct sysdb_handle *handle; - struct sysdb_cb_ctx *cbctx; struct sss_domain_info *domain; const char *name; uid_t uid; gid_t gid; - const char *fullname; + const char *gecos; const char *homedir; const char *shell; - - struct next_id id; + struct sysdb_attrs *attrs; }; -static void user_check_callback(void *pvt, int error, struct ldb_result *res); -static int user_add_id(struct user_add_ctx *user_ctx); -static void user_add_id_callback(void *pvt, int error, struct ldb_result *res); -static int user_add_call(struct user_add_ctx *user_ctx); +static void sysdb_add_user_group_check(struct tevent_req *subreq); +static void sysdb_add_user_uid_check(struct tevent_req *subreq); +static void sysdb_add_user_basic_done(struct tevent_req *subreq); +static void sysdb_add_user_get_id_done(struct tevent_req *subreq); +static void sysdb_add_user_set_id_done(struct tevent_req *subreq); +static void sysdb_add_user_set_attrs_done(struct tevent_req *subreq); -int sysdb_add_user(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *name, - uid_t uid, gid_t gid, const char *fullname, - const char *homedir, const char *shell, - sysdb_callback_t fn, void *pvt) +struct tevent_req *sysdb_add_user_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, + uid_t uid, gid_t gid, + const char *gecos, + const char *homedir, + const char *shell, + struct sysdb_attrs *attrs) { - struct user_add_ctx *user_ctx; + struct tevent_req *req, *subreq; + struct sysdb_add_user_state *state; + int ret; - if (!sysdb_handle_check_running(handle)) { - DEBUG(2, ("Invalid request! Not running at this time.\n")); - return EINVAL; + req = tevent_req_create(mem_ctx, &state, struct sysdb_add_user_state); + if (!req) return NULL; + + state->ev = ev; + state->handle = handle; + state->domain = domain; + state->name = name; + state->uid = uid; + state->gid = gid; + state->gecos = gecos; + state->homedir = homedir; + state->shell = shell; + state->attrs = attrs; + + if (domain->mpg) { + if (gid != 0) { + DEBUG(0, ("Cannot add user with arbitrary GID in MPG domain!\n")); + ERROR_OUT(ret, EINVAL, fail); + } + state->gid = state->uid; } if (domain->id_max != 0 && uid != 0 && (uid < domain->id_min || uid > domain->id_max)) { DEBUG(2, ("Supplied uid [%d] is not in the allowed range [%d-%d].\n", uid, domain->id_min, domain->id_max)); - return EINVAL; + ERROR_OUT(ret, EINVAL, fail); } if (domain->id_max != 0 && gid != 0 && (gid < domain->id_min || gid > domain->id_max)) { DEBUG(2, ("Supplied gid [%d] is not in the allowed range [%d-%d].\n", gid, domain->id_min, domain->id_max)); - return EINVAL; + ERROR_OUT(ret, EINVAL, fail); } + if (domain->mpg) { + /* In MPG domains you can't have groups with the same name as users, + * search if a group with the same name exists. + * Don't worry about users, if we try to add a user with the same + * name the operation will fail */ + + subreq = sysdb_search_group_by_name_send(state, ev, handle, + domain, name); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_add_user_group_check, req); + return req; + } - user_ctx = talloc(handle, struct user_add_ctx); - if (!user_ctx) return ENOMEM; + /* check no other user with the same uid exist */ + if (state->uid != 0) { + subreq = sysdb_search_user_by_uid_send(state, ev, handle, domain, uid); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_add_user_uid_check, req); + return req; + } - user_ctx->cbctx = talloc_zero(user_ctx, struct sysdb_cb_ctx); - if (!user_ctx->cbctx) return ENOMEM; + /* try to add the user */ + subreq = sysdb_add_basic_user_send(state, ev, handle, + domain, name, uid, gid, + gecos, homedir, shell); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_add_user_basic_done, req); + return req; - user_ctx->handle = handle; - user_ctx->domain = domain; - user_ctx->cbctx->fn = fn; - user_ctx->cbctx->pvt = pvt; - user_ctx->name = name; - user_ctx->uid = uid; - user_ctx->gid = gid; - user_ctx->fullname = fullname; - user_ctx->homedir = homedir; - user_ctx->shell = shell; +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} - if (domain->mpg) { - /* if the domain is mpg we need to check we do not have there are no - * name conflicts */ +static void sysdb_add_user_group_check(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_add_user_state *state = tevent_req_data(req, + struct sysdb_add_user_state); + struct ldb_message *msg; + int ret; - return sysdb_check_name_unique(handle, domain, user_ctx, name, - user_check_callback, user_ctx); + /* We can succeed only if we get an ENOENT error, which means no groups + * with the same name exist. + * If any other error is returned fail as well. */ + ret = sysdb_search_group_recv(subreq, state, &msg); + talloc_zfree(subreq); + if (ret != ENOENT) { + if (ret == EOK) ret = EEXIST; + tevent_req_error(req, ret); + return; + } + + /* check no other user with the same uid exist */ + if (state->uid != 0) { + subreq = sysdb_search_user_by_uid_send(state, + state->ev, state->handle, + state->domain, state->uid); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_add_user_uid_check, req); + return; } - return user_add_id(user_ctx); + /* try to add the user */ + subreq = sysdb_add_basic_user_send(state, state->ev, state->handle, + state->domain, state->name, + state->uid, state->gid, + state->gecos, + state->homedir, + state->shell); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_add_user_basic_done, req); } -static void user_check_callback(void *pvt, int error, struct ldb_result *res) +static void sysdb_add_user_uid_check(struct tevent_req *subreq) { - struct user_add_ctx *user_ctx; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_add_user_state *state = tevent_req_data(req, + struct sysdb_add_user_state); + struct ldb_message *msg; int ret; - user_ctx = talloc_get_type(pvt, struct user_add_ctx); - if (error != EOK) { - sysdb_ret_error(user_ctx->cbctx, error, LDB_ERR_OPERATIONS_ERROR); + /* We can succeed only if we get an ENOENT error, which means no user + * with the same uid exist. + * If any other error is returned fail as well. */ + ret = sysdb_search_user_recv(subreq, state, &msg); + talloc_zfree(subreq); + if (ret != ENOENT) { + if (ret == EOK) ret = EEXIST; + tevent_req_error(req, ret); return; } - ret = user_add_id(user_ctx); - if (ret != EOK) { - sysdb_ret_error(user_ctx->cbctx, ret, LDB_ERR_OPERATIONS_ERROR); + /* try to add the user */ + subreq = sysdb_add_basic_user_send(state, state->ev, state->handle, + state->domain, state->name, + state->uid, state->gid, + state->gecos, + state->homedir, + state->shell); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; } + tevent_req_set_callback(subreq, sysdb_add_user_basic_done, req); } -static int user_add_id(struct user_add_ctx *user_ctx) +static void sysdb_add_user_basic_done(struct tevent_req *subreq) { - if (user_ctx->uid != 0 && user_ctx->gid == 0) { - if(user_ctx->domain->mpg) { - user_ctx->gid = user_ctx->uid; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_add_user_state *state = tevent_req_data(req, + struct sysdb_add_user_state); + int ret; + + ret = sysdb_add_basic_user_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + if (state->uid == 0) { + subreq = sysdb_get_new_id_send(state, + state->ev, state->handle, + state->domain); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; } + tevent_req_set_callback(subreq, sysdb_add_user_get_id_done, req); + return; } - if (user_ctx->uid == 0 || user_ctx->gid == 0) { - /* Must generate uid/gid pair */ - return sysdb_get_next_available_id(user_ctx->handle, - user_ctx->domain, - &(user_ctx->id), - user_add_id_callback, user_ctx); + if (state->attrs) { + subreq = sysdb_set_user_attr_send(state, state->ev, state->handle, + state->domain, state->name, + state->attrs, SYSDB_MOD_ADD); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_add_user_set_attrs_done, req); + return; } - return user_add_call(user_ctx); + tevent_req_done(req); } -static void user_add_id_callback(void *pvt, int error, struct ldb_result *res) +static void sysdb_add_user_get_id_done(struct tevent_req *subreq) { - struct user_add_ctx *user_ctx; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_add_user_state *state = tevent_req_data(req, + struct sysdb_add_user_state); + struct sysdb_attrs *id_attrs; + uint32_t id; int ret; - user_ctx = talloc_get_type(pvt, struct user_add_ctx); - if (error != EOK) { - sysdb_ret_error(user_ctx->cbctx, error, LDB_ERR_OPERATIONS_ERROR); + ret = sysdb_get_new_id_recv(subreq, &id); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); return; } - /* ok id has been allocated, fill in uid and gid fields if not - * already set */ - if (user_ctx->uid == 0) { - user_ctx->uid = user_ctx->id.id; + if (state->uid == 0) { + id_attrs = sysdb_new_attrs(state); + if (!id_attrs) { + tevent_req_error(req, ENOMEM); + return; + } + ret = sysdb_attrs_add_uint32(id_attrs, SYSDB_UIDNUM, id); + if (ret) { + tevent_req_error(req, ret); + return; + } + if (state->domain->mpg) { + ret = sysdb_attrs_add_uint32(id_attrs, SYSDB_GIDNUM, id); + if (ret) { + tevent_req_error(req, ret); + return; + } + } + + subreq = sysdb_set_user_attr_send(state, state->ev, state->handle, + state->domain, state->name, + id_attrs, SYSDB_MOD_REP); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_add_user_set_id_done, req); + return; + } + + if (state->attrs) { + subreq = sysdb_set_user_attr_send(state, state->ev, + state->handle, state->domain, + state->name, state->attrs, + SYSDB_MOD_REP); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_add_user_set_attrs_done, req); + return; } - if (user_ctx->gid == 0) { - user_ctx->gid = user_ctx->id.id; + + tevent_req_done(req); +} + +static void sysdb_add_user_set_id_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_add_user_state *state = tevent_req_data(req, + struct sysdb_add_user_state); + int ret; + + ret = sysdb_set_user_attr_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; } - ret = user_add_call(user_ctx); - if (ret != EOK) { - sysdb_ret_error(user_ctx->cbctx, ret, LDB_ERR_OPERATIONS_ERROR); + if (state->attrs) { + subreq = sysdb_set_user_attr_send(state, state->ev, + state->handle, state->domain, + state->name, state->attrs, + SYSDB_MOD_REP); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_add_user_set_attrs_done, req); + return; } + + tevent_req_done(req); } -static int user_add_call(struct user_add_ctx *user_ctx) +static void sysdb_add_user_set_attrs_done(struct tevent_req *subreq) { - struct sysdb_ctx *ctx; - struct ldb_message *msg; - struct ldb_request *req; - int flags = LDB_FLAG_MOD_ADD; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); int ret; - ctx = sysdb_handle_get_ctx(user_ctx->handle); + ret = sysdb_set_user_attr_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + tevent_req_done(req); +} - msg = ldb_msg_new(user_ctx); - if (!msg) return ENOMEM; +int sysdb_add_user_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); +} - msg->dn = sysdb_user_dn(ctx, msg, user_ctx->domain->name, user_ctx->name); - if (!msg->dn) return ENOMEM; - ret = add_string(msg, flags, "objectClass", SYSDB_USER_CLASS); - if (ret != LDB_SUCCESS) return ENOMEM; +/* =Add-Basic-Group-NO-CHECKS============================================= */ - ret = add_string(msg, flags, SYSDB_NAME, user_ctx->name); - if (ret != LDB_SUCCESS) return ENOMEM; +struct tevent_req *sysdb_add_basic_group_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, gid_t gid) +{ + struct tevent_req *req, *subreq; + struct sysdb_op_state *state; + struct ldb_request *ldbreq; + struct ldb_message *msg; + int ret; - if (user_ctx->uid) { - ret = add_ulong(msg, flags, SYSDB_UIDNUM, - (unsigned long)(user_ctx->uid)); - if (ret != LDB_SUCCESS) return ENOMEM; - } else { - DEBUG(0, ("Cached users can't have UID == 0\n")); - return EINVAL; - } + req = tevent_req_create(mem_ctx, &state, struct sysdb_op_state); + if (!req) return NULL; - if (user_ctx->gid) { - ret = add_ulong(msg, flags, SYSDB_GIDNUM, - (unsigned long)(user_ctx->gid)); - if (ret != LDB_SUCCESS) return ENOMEM; - } else { - DEBUG(0, ("Cached users can't have GID == 0\n")); - return EINVAL; - } + state->ev = ev; + state->handle = handle; + state->ignore_not_found = false; + state->ldbreply = NULL; - /* We set gecos to be the same as fullname on user creation, - * But we will not enforce coherency after that, it's up to - * admins to decide if they want to keep it in sync if they change - * one of the 2 */ - if (user_ctx->fullname && *user_ctx->fullname) { - ret = add_string(msg, flags, SYSDB_FULLNAME, user_ctx->fullname); - if (ret != LDB_SUCCESS) return ENOMEM; - ret = add_string(msg, flags, SYSDB_GECOS, user_ctx->fullname); - if (ret != LDB_SUCCESS) return ENOMEM; + msg = ldb_msg_new(state); + if (!msg) { + ERROR_OUT(ret, ENOMEM, fail); } - if (user_ctx->homedir && *user_ctx->homedir) { - ret = add_string(msg, flags, SYSDB_HOMEDIR, user_ctx->homedir); - if (ret != LDB_SUCCESS) return ENOMEM; + /* user dn */ + msg->dn = sysdb_group_dn(handle->ctx, msg, domain->name, name); + if (!msg->dn) { + ERROR_OUT(ret, ENOMEM, fail); } - if (user_ctx->shell && *user_ctx->shell) { - ret = add_string(msg, flags, SYSDB_SHELL, user_ctx->shell); - if (ret != LDB_SUCCESS) return ENOMEM; - } + ret = add_string(msg, LDB_FLAG_MOD_ADD, "objectClass", SYSDB_GROUP_CLASS); + if (ret) goto fail; + + ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_NAME, name); + if (ret) goto fail; + + ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_GIDNUM, (unsigned long)gid); + if (ret) goto fail; /* creation time */ - ret = add_ulong(msg, flags, SYSDB_CREATE_TIME, (unsigned long)time(NULL)); - if (ret != LDB_SUCCESS) return ENOMEM; + ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_CREATE_TIME, + (unsigned long)time(NULL)); + if (ret) goto fail; - ret = ldb_build_add_req(&req, ctx->ldb, user_ctx, msg, NULL, - user_ctx->cbctx, sysdb_op_callback, NULL); - if (ret == LDB_SUCCESS) { - ret = ldb_request(ctx->ldb, req); - } + + ret = ldb_build_add_req(&ldbreq, handle->ctx->ldb, state, msg, + NULL, NULL, NULL, NULL); if (ret != LDB_SUCCESS) { - return sysdb_error_to_errno(ret); + DEBUG(1, ("Failed to build modify request: %s(%d)[%s]\n", + ldb_strerror(ret), ret, ldb_errstring(handle->ctx->ldb))); + ERROR_OUT(ret, sysdb_error_to_errno(ret), fail); } - return EOK; + subreq = sldb_request_send(state, ev, handle->ctx->ldb, ldbreq); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_op_default_done, req); + + return req; + +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} + +int sysdb_add_basic_group_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); } -struct group_add_ctx { + +/* =Add-Group-Function==================================================== */ + +struct sysdb_add_group_state { + struct tevent_context *ev; struct sysdb_handle *handle; - struct sysdb_cb_ctx *cbctx; struct sss_domain_info *domain; const char *name; gid_t gid; - - struct next_id id; + struct sysdb_attrs *attrs; }; -static void group_check_callback(void *pvt, int error, struct ldb_result *res); -static int group_add_id(struct group_add_ctx *group_ctx); -static void group_add_id_callback(void *pvt, int error, struct ldb_result *res); -static int group_add_call(struct group_add_ctx *group_ctx); - -int sysdb_add_group(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *name, gid_t gid, - sysdb_callback_t fn, void *pvt) +static void sysdb_add_group_user_check(struct tevent_req *subreq); +static void sysdb_add_group_gid_check(struct tevent_req *subreq); +static void sysdb_add_group_basic_done(struct tevent_req *subreq); +static void sysdb_add_group_get_id_done(struct tevent_req *subreq); +static void sysdb_add_group_set_id_done(struct tevent_req *subreq); +static void sysdb_add_group_set_attrs_done(struct tevent_req *subreq); + +struct tevent_req *sysdb_add_group_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, gid_t gid, + struct sysdb_attrs *attrs) { - struct group_add_ctx *group_ctx; + struct tevent_req *req, *subreq; + struct sysdb_add_group_state *state; + int ret; - if (!sysdb_handle_check_running(handle)) { - DEBUG(2, ("Invalid request! Not running at this time.\n")); - return EINVAL; - } + req = tevent_req_create(mem_ctx, &state, struct sysdb_add_group_state); + if (!req) return NULL; + + state->ev = ev; + state->handle = handle; + state->domain = domain; + state->name = name; + state->gid = gid; + state->attrs = attrs; if (domain->id_max != 0 && gid != 0 && (gid < domain->id_min || gid > domain->id_max)) { DEBUG(2, ("Supplied gid [%d] is not in the allowed range [%d-%d].\n", gid, domain->id_min, domain->id_max)); - return EINVAL; + ERROR_OUT(ret, EINVAL, fail); } - group_ctx = talloc(handle, struct group_add_ctx); - if (!group_ctx) return ENOMEM; + if (domain->mpg) { + /* In MPG domains you can't have groups with the same name as users, + * search if a group with the same name exists. + * Don't worry about users, if we try to add a user with the same + * name the operation will fail */ + + subreq = sysdb_search_user_by_name_send(state, ev, handle, + domain, name); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_add_group_user_check, req); + return req; + } - group_ctx->cbctx = talloc_zero(group_ctx, struct sysdb_cb_ctx); - if (!group_ctx->cbctx) return ENOMEM; + /* check no other groups with the same gid exist */ + if (state->gid != 0) { + subreq = sysdb_search_group_by_gid_send(state, ev, handle, + domain, gid); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_add_group_gid_check, req); + return req; + } - group_ctx->handle = handle; - group_ctx->domain = domain; - group_ctx->cbctx->fn = fn; - group_ctx->cbctx->pvt = pvt; - group_ctx->name = name; - group_ctx->gid = gid; + /* try to add the group */ + subreq = sysdb_add_basic_group_send(state, ev, handle, + domain, name, gid); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_add_group_basic_done, req); + return req; - if (domain->mpg) { - /* if the domain is mpg we need to check we do not have there are no - * name conflicts */ +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} - return sysdb_check_name_unique(handle, domain, group_ctx, name, - group_check_callback, group_ctx); +static void sysdb_add_group_user_check(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_add_group_state *state = tevent_req_data(req, + struct sysdb_add_group_state); + struct ldb_message *msg; + int ret; + + /* We can succeed only if we get an ENOENT error, which means no users + * with the same name exist. + * If any other error is returned fail as well. */ + ret = sysdb_search_user_recv(subreq, state, &msg); + talloc_zfree(subreq); + if (ret != ENOENT) { + if (ret == EOK) ret = EEXIST; + tevent_req_error(req, ret); + return; } - return group_add_id(group_ctx); + /* check no other group with the same gid exist */ + if (state->gid != 0) { + subreq = sysdb_search_group_by_gid_send(state, + state->ev, state->handle, + state->domain, state->gid); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_add_group_gid_check, req); + return; + } + + /* try to add the group */ + subreq = sysdb_add_basic_group_send(state, state->ev, + state->handle, state->domain, + state->name, state->gid); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_add_group_basic_done, req); } -static void group_check_callback(void *pvt, int error, struct ldb_result *res) +static void sysdb_add_group_gid_check(struct tevent_req *subreq) { - struct group_add_ctx *group_ctx; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_add_group_state *state = tevent_req_data(req, + struct sysdb_add_group_state); + struct ldb_message *msg; int ret; - group_ctx = talloc_get_type(pvt, struct group_add_ctx); - if (error != EOK) { - sysdb_ret_error(group_ctx->cbctx, error, LDB_ERR_OPERATIONS_ERROR); + /* We can succeed only if we get an ENOENT error, which means no group + * with the same gid exist. + * If any other error is returned fail as well. */ + ret = sysdb_search_group_recv(subreq, state, &msg); + talloc_zfree(subreq); + if (ret != ENOENT) { + if (ret == EOK) ret = EEXIST; + tevent_req_error(req, ret); return; } - ret = group_add_id(group_ctx); - if (ret != EOK) { - sysdb_ret_error(group_ctx->cbctx, ret, LDB_ERR_OPERATIONS_ERROR); + /* try to add the group */ + subreq = sysdb_add_basic_group_send(state, state->ev, + state->handle, state->domain, + state->name, state->gid); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; } + tevent_req_set_callback(subreq, sysdb_add_group_basic_done, req); } -static int group_add_id(struct group_add_ctx *group_ctx) +static void sysdb_add_group_basic_done(struct tevent_req *subreq) { - if (group_ctx->gid == 0) { - /* Must generate uid/gid pair */ - return sysdb_get_next_available_id(group_ctx->handle, - group_ctx->domain, - &(group_ctx->id), - group_add_id_callback, group_ctx); + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_add_group_state *state = tevent_req_data(req, + struct sysdb_add_group_state); + int ret; + + ret = sysdb_add_basic_group_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + if (state->gid == 0) { + subreq = sysdb_get_new_id_send(state, + state->ev, state->handle, + state->domain); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_add_group_get_id_done, req); + return; } - return group_add_call(group_ctx); + if (state->attrs) { + subreq = sysdb_set_group_attr_send(state, state->ev, + state->handle, state->domain, + state->name, state->attrs, + SYSDB_MOD_ADD); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_add_group_set_attrs_done, req); + return; + } + + tevent_req_done(req); } -static void group_add_id_callback(void *pvt, int error, struct ldb_result *res) +static void sysdb_add_group_get_id_done(struct tevent_req *subreq) { - struct group_add_ctx *group_ctx; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_add_group_state *state = tevent_req_data(req, + struct sysdb_add_group_state); + struct sysdb_attrs *id_attrs; + uint32_t id; int ret; - group_ctx = talloc_get_type(pvt, struct group_add_ctx); - if (error != EOK) { - sysdb_ret_error(group_ctx->cbctx, error, LDB_ERR_OPERATIONS_ERROR); + ret = sysdb_get_new_id_recv(subreq, &id); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + if (state->gid == 0) { + id_attrs = sysdb_new_attrs(state); + if (!id_attrs) { + tevent_req_error(req, ENOMEM); + return; + } + ret = sysdb_attrs_add_uint32(id_attrs, SYSDB_GIDNUM, id); + if (ret) { + tevent_req_error(req, ret); + return; + } + + subreq = sysdb_set_group_attr_send(state, state->ev, state->handle, + state->domain, state->name, + id_attrs, SYSDB_MOD_REP); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_add_group_set_id_done, req); + return; + } + + if (state->attrs) { + subreq = sysdb_set_group_attr_send(state, state->ev, + state->handle, state->domain, + state->name, state->attrs, + SYSDB_MOD_ADD); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_add_group_set_attrs_done, req); + return; + } + + tevent_req_done(req); +} + +static void sysdb_add_group_set_id_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_add_group_state *state = tevent_req_data(req, + struct sysdb_add_group_state); + int ret; + + ret = sysdb_set_group_attr_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + if (state->attrs) { + subreq = sysdb_set_group_attr_send(state, state->ev, + state->handle, state->domain, + state->name, state->attrs, + SYSDB_MOD_ADD); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_add_group_set_attrs_done, req); + return; + } + + tevent_req_done(req); +} + +static void sysdb_add_group_set_attrs_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + int ret; + + ret = sysdb_set_group_attr_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); return; } - /* ok id has been allocated, fill in uid and gid fields */ - group_ctx->gid = group_ctx->id.id; - - ret = group_add_call(group_ctx); - if (ret != EOK) { - sysdb_ret_error(group_ctx->cbctx, ret, LDB_ERR_OPERATIONS_ERROR); - } + tevent_req_done(req); } -static int group_add_call(struct group_add_ctx *group_ctx) +int sysdb_add_group_recv(struct tevent_req *req) { - struct sysdb_ctx *ctx; - struct ldb_message *msg; - struct ldb_request *req; - int flags = LDB_FLAG_MOD_ADD; - int ret; + return sysdb_op_default_recv(req); +} - ctx = sysdb_handle_get_ctx(group_ctx->handle); - msg = ldb_msg_new(group_ctx); - if (!msg) return ENOMEM; +/* =Add-Or-Remove-Group-Memeber=========================================== */ - msg->dn = sysdb_group_dn(ctx, msg, group_ctx->domain->name, group_ctx->name); - if (!msg->dn) return ENOMEM; +/* mod_op must be either SYSDB_MOD_ADD or SYSDB_MOD_DEL */ +struct tevent_req *sysdb_mod_group_member_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct ldb_dn *member_dn, + struct ldb_dn *group_dn, + int mod_op) +{ + struct tevent_req *req, *subreq; + struct sysdb_op_state *state; + struct ldb_request *ldbreq; + struct ldb_message *msg; + const char *dn; + int ret; - ret = add_string(msg, flags, "objectClass", SYSDB_GROUP_CLASS); - if (ret != LDB_SUCCESS) return ENOMEM; + req = tevent_req_create(mem_ctx, &state, struct sysdb_op_state); + if (!req) return NULL; - ret = add_string(msg, flags, SYSDB_NAME, group_ctx->name); - if (ret != LDB_SUCCESS) return ENOMEM; + state->ev = ev; + state->handle = handle; + state->ignore_not_found = false; + state->ldbreply = NULL; - if (group_ctx->gid) { - ret = add_ulong(msg, flags, SYSDB_GIDNUM, - (unsigned long)(group_ctx->gid)); - if (ret != LDB_SUCCESS) return ENOMEM; - } else { - DEBUG(0, ("Cached groups can't have GID == 0\n")); - return EINVAL; + msg = ldb_msg_new(state); + if (!msg) { + ERROR_OUT(ret, ENOMEM, fail); } - /* creation time */ - ret = add_ulong(msg, flags, SYSDB_CREATE_TIME, (unsigned long)time(NULL)); - if (ret != LDB_SUCCESS) return ENOMEM; - - ret = ldb_build_add_req(&req, ctx->ldb, group_ctx, msg, NULL, - group_ctx->cbctx, sysdb_op_callback, NULL); - if (ret == LDB_SUCCESS) { - ret = ldb_request(ctx->ldb, req); - } + msg->dn = group_dn; + ret = ldb_msg_add_empty(msg, SYSDB_MEMBER, mod_op, NULL); if (ret != LDB_SUCCESS) { - return sysdb_error_to_errno(ret); + ERROR_OUT(ret, ENOMEM, fail); } - return EOK; -} - -/* This function is not safe, but is included for completeness - * It is much better to allow SSSD to internally manage the - * group GID values. sysdb_set_group_gid() will perform no - * validation that the new GID is unused. The only check it - * will perform is whether the requested GID is in the range - * of IDs allocated for the domain. - */ -int sysdb_set_group_gid(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *name, gid_t gid, - sysdb_callback_t fn, void *pvt) -{ - struct group_add_ctx *group_ctx; - struct sysdb_ctx *sysdb; - struct ldb_message *msg; - struct ldb_request *req; - int flags = LDB_FLAG_MOD_REPLACE; - int ret; - - if (!sysdb_handle_check_running(handle)) { - DEBUG(2, ("Invalid request! Not running at this time.\n")); - return EINVAL; + dn = ldb_dn_get_linearized(member_dn); + if (!dn) { + ERROR_OUT(ret, EINVAL, fail); } - /* Validate that the target GID is within the domain range */ - if((gid < domain->id_min) || - (domain->id_max && (gid > domain->id_max))) { - DEBUG(2, ("Invalid request. Domain ID out of range")); - return EDOM; + ret = ldb_msg_add_fmt(msg, SYSDB_MEMBER, "%s", dn); + if (ret != LDB_SUCCESS) { + ERROR_OUT(ret, EINVAL, fail); } - group_ctx = talloc(handle, struct group_add_ctx); - if (!group_ctx) return ENOMEM; - - group_ctx->cbctx = talloc_zero(group_ctx, struct sysdb_cb_ctx); - if (!group_ctx->cbctx) return ENOMEM; - - group_ctx->handle = handle; - group_ctx->domain = domain; - group_ctx->cbctx->fn = fn; - group_ctx->cbctx->pvt = pvt; - group_ctx->name = name; - group_ctx->gid = gid; + ret = ldb_build_mod_req(&ldbreq, handle->ctx->ldb, state, msg, + NULL, NULL, NULL, NULL); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Failed to build modify request: %s(%d)[%s]\n", + ldb_strerror(ret), ret, ldb_errstring(handle->ctx->ldb))); + ERROR_OUT(ret, sysdb_error_to_errno(ret), fail); + } - sysdb = sysdb_handle_get_ctx(group_ctx->handle); + subreq = sldb_request_send(state, ev, handle->ctx->ldb, ldbreq); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_op_default_done, req); - msg = ldb_msg_new(group_ctx); - if (!msg) return ENOMEM; + return req; - msg->dn = sysdb_group_dn(sysdb, msg, - group_ctx->domain->name, - group_ctx->name); - if (!msg->dn) return ENOMEM; +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} - ret = add_ulong(msg, flags, SYSDB_GIDNUM, - (unsigned long)(group_ctx->gid)); +int sysdb_mod_group_member_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); +} - ret = ldb_build_mod_req(&req, sysdb->ldb, group_ctx, msg, NULL, - group_ctx->cbctx, sysdb_op_callback, NULL); - if (ret == LDB_SUCCESS) { - ret = ldb_request(sysdb->ldb, req); - } - if (ret != LDB_SUCCESS) { - return sysdb_error_to_errno(ret); - } - return EOK; -} +/* =Store-Users-(Native/Legacy)-(replaces-existing-data)================== */ -/* "sysdb_legacy_" functions - * the set of functions named sysdb_legacy_* are used by modules - * that only have access to strictly posix like databases where - * user and groups names are retrieved as strings, groups can't - * be nested and can't reference foreign sources */ +/* if one of the basic attributes is empty ("") as opposed to NULL, + * this will just remove it */ -struct legacy_user_ctx { +struct sysdb_store_user_state { + struct tevent_context *ev; struct sysdb_handle *handle; - struct sysdb_cb_ctx *cbctx; struct sss_domain_info *domain; - struct ldb_dn *dn; - const char *name; - const char *pwd; uid_t uid; gid_t gid; const char *gecos; const char *homedir; const char *shell; - - struct ldb_result *res; + struct sysdb_attrs *attrs; }; -static int legacy_user_callback(struct ldb_request *req, - struct ldb_reply *rep); - -int sysdb_legacy_store_user(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *name, const char *pwd, - uid_t uid, gid_t gid, const char *gecos, - const char *homedir, const char *shell, - sysdb_callback_t fn, void *pvt) +static void sysdb_store_user_check(struct tevent_req *subreq); +static void sysdb_store_user_add_done(struct tevent_req *subreq); +static void sysdb_store_user_attr_done(struct tevent_req *subreq); + +struct tevent_req *sysdb_store_user_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, + const char *pwd, + uid_t uid, gid_t gid, + const char *gecos, + const char *homedir, + const char *shell) { - static const char *attrs[] = { SYSDB_NAME, NULL }; - struct legacy_user_ctx *user_ctx; - struct sysdb_ctx *ctx; - struct ldb_request *req; + struct tevent_req *req, *subreq; + struct sysdb_store_user_state *state; int ret; - if (!sysdb_handle_check_running(handle)) { - DEBUG(2, ("Invalid request! Not running at this time.\n")); - return EINVAL; - } - - ctx = sysdb_handle_get_ctx(handle); - - user_ctx = talloc(handle, struct legacy_user_ctx); - if (!user_ctx) return ENOMEM; - - user_ctx->cbctx = talloc_zero(user_ctx, struct sysdb_cb_ctx); - if (!user_ctx->cbctx) return ENOMEM; + req = tevent_req_create(mem_ctx, &state, struct sysdb_store_user_state); + if (!req) return NULL; - user_ctx->dn = sysdb_user_dn(ctx, user_ctx, domain->name, name); - if (!user_ctx->dn) return ENOMEM; + state->ev = ev; + state->handle = handle; + state->domain = domain; + state->name = name; + state->uid = uid; + state->gid = gid; + state->gecos = gecos; + state->homedir = homedir; + state->shell = shell; + state->attrs = NULL; - user_ctx->handle = handle; - user_ctx->cbctx->fn = fn; - user_ctx->cbctx->pvt = pvt; - user_ctx->domain = domain; - user_ctx->name = name; - user_ctx->pwd = pwd; - user_ctx->uid = uid; - user_ctx->gid = gid; - user_ctx->gecos = gecos; - user_ctx->homedir = homedir; - user_ctx->shell = shell; - - user_ctx->res = talloc_zero(user_ctx, struct ldb_result); - if (!user_ctx->res) return ENOMEM; + if (pwd && (domain->legacy_passwords || !*pwd)) { + ret = sysdb_attrs_add_string(state->attrs, SYSDB_PWD, pwd); + if (ret) goto fail; + } - ret = ldb_build_search_req(&req, ctx->ldb, user_ctx, - user_ctx->dn, LDB_SCOPE_BASE, - SYSDB_PWENT_FILTER, attrs, NULL, - user_ctx, legacy_user_callback, NULL); - if (ret != LDB_SUCCESS) { - DEBUG(1, ("Failed to build search request: %s(%d)[%s]\n", - ldb_strerror(ret), ret, ldb_errstring(ctx->ldb))); - return sysdb_error_to_errno(ret); + subreq = sysdb_search_user_by_name_send(state, ev, handle, domain, name); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); } + tevent_req_set_callback(subreq, sysdb_store_user_check, req); - ret = ldb_request(ctx->ldb, req); - if (ret != LDB_SUCCESS) return sysdb_error_to_errno(ret); + return req; - return EOK; +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; } -static int legacy_user_callback(struct ldb_request *req, - struct ldb_reply *rep) +static void sysdb_store_user_check(struct tevent_req *subreq) { - struct legacy_user_ctx *user_ctx; - struct sysdb_cb_ctx *cbctx; - struct sysdb_ctx *ctx; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_store_user_state *state = tevent_req_data(req, + struct sysdb_store_user_state); struct ldb_message *msg; - struct ldb_request *ureq; - struct ldb_result *res; - int flags; - int ret, err; - - user_ctx = talloc_get_type(req->context, struct legacy_user_ctx); - ctx = sysdb_handle_get_ctx(user_ctx->handle); - cbctx = user_ctx->cbctx; - res = user_ctx->res; + int ret; - if (!rep) { - return sysdb_ret_error(cbctx, EIO, LDB_ERR_OPERATIONS_ERROR); - } - if (rep->error != LDB_SUCCESS) { - err = sysdb_error_to_errno(rep->error); - return sysdb_ret_error(cbctx, err, rep->error); + ret = sysdb_search_user_recv(subreq, state, &msg); + talloc_zfree(subreq); + if (ret && ret != ENOENT) { + tevent_req_error(req, ret); + return; } - switch (rep->type) { - case LDB_REPLY_ENTRY: - res->msgs = talloc_realloc(res, res->msgs, - struct ldb_message *, - res->count + 2); - if (!res->msgs) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); + if (ret == ENOENT) { + /* users doesn't exist, turn into adding a user */ + subreq = sysdb_add_user_send(state, state->ev, state->handle, + state->domain, state->name, + state->uid, state->gid, + state->gecos, state->homedir, + state->shell, state->attrs); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; } + tevent_req_set_callback(subreq, sysdb_store_user_add_done, req); + return; + } - res->msgs[res->count + 1] = NULL; - - res->msgs[res->count] = talloc_steal(res->msgs, rep->message); - res->count++; - - break; - - case LDB_REPLY_DONE: - - msg = ldb_msg_new(cbctx); - if (!msg) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); + /* the user exists, let's just replace attributes when set */ + if (!state->attrs) { + state->attrs = sysdb_new_attrs(state); + if (!state->attrs) { + tevent_req_error(req, ENOMEM); + return; } - msg->dn = user_ctx->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)); - - return sysdb_ret_error(cbctx, EFAULT, LDB_ERR_OPERATIONS_ERROR); - } - - talloc_free(res); - user_ctx->res = res = NULL; - - if (flags == LDB_FLAG_MOD_ADD) { - ret = add_string(msg, flags, "objectClass", SYSDB_USER_CLASS); - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } + } - ret = add_string(msg, flags, SYSDB_NAME, user_ctx->name); - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } + if (state->uid) { + ret = sysdb_attrs_add_uint32(state->attrs, SYSDB_UIDNUM, state->uid); + if (ret) { + tevent_req_error(req, ret); + return; } + } - if (user_ctx->domain->legacy_passwords && - user_ctx->pwd && *user_ctx->pwd) { - ret = add_string(msg, flags, SYSDB_PWD, user_ctx->pwd); - } else { - ret = ldb_msg_add_empty(msg, SYSDB_PWD, - LDB_FLAG_MOD_DELETE, NULL); - } - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); + if (state->gid) { + ret = sysdb_attrs_add_uint32(state->attrs, SYSDB_GIDNUM, state->gid); + if (ret) { + tevent_req_error(req, ret); + return; } + } - if (user_ctx->uid) { - ret = add_ulong(msg, flags, SYSDB_UIDNUM, - (unsigned long)(user_ctx->uid)); - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } - } else { - DEBUG(0, ("Cached users can't have UID == 0\n")); - return sysdb_ret_error(cbctx, EINVAL, LDB_ERR_OPERATIONS_ERROR); + if (state->uid && !state->gid && state->domain->mpg) { + ret = sysdb_attrs_add_uint32(state->attrs, SYSDB_GIDNUM, state->uid); + if (ret) { + tevent_req_error(req, ret); + return; } + } - if (user_ctx->gid) { - ret = add_ulong(msg, flags, SYSDB_GIDNUM, - (unsigned long)(user_ctx->gid)); - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } - } else { - DEBUG(0, ("Cached users can't have GID == 0\n")); - return sysdb_ret_error(cbctx, EINVAL, LDB_ERR_OPERATIONS_ERROR); + if (state->gecos) { + ret = sysdb_attrs_add_string(state->attrs, SYSDB_GECOS, state->gecos); + if (ret) { + tevent_req_error(req, ret); + return; } + } - if (user_ctx->gecos && *user_ctx->gecos) { - ret = add_string(msg, flags, SYSDB_GECOS, user_ctx->gecos); - } else { - ret = ldb_msg_add_empty(msg, SYSDB_GECOS, - LDB_FLAG_MOD_DELETE, NULL); - } - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); + if (state->homedir) { + ret = sysdb_attrs_add_string(state->attrs, + SYSDB_HOMEDIR, state->homedir); + if (ret) { + tevent_req_error(req, ret); + return; } + } - if (user_ctx->homedir && *user_ctx->homedir) { - ret = add_string(msg, flags, SYSDB_HOMEDIR, user_ctx->homedir); - } else { - ret = ldb_msg_add_empty(msg, SYSDB_HOMEDIR, - LDB_FLAG_MOD_DELETE, NULL); - } - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); + if (state->shell) { + ret = sysdb_attrs_add_string(state->attrs, SYSDB_SHELL, state->shell); + if (ret) { + tevent_req_error(req, ret); + return; } + } - if (user_ctx->shell && *user_ctx->shell) { - ret = add_string(msg, flags, SYSDB_SHELL, user_ctx->shell); - } else { - ret = ldb_msg_add_empty(msg, SYSDB_SHELL, - LDB_FLAG_MOD_DELETE, NULL); - } - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } + ret = sysdb_attrs_add_time_t(state->attrs, SYSDB_LAST_UPDATE, time(NULL)); + if (ret) { + tevent_req_error(req, ret); + return; + } - /* modification time */ - ret = add_ulong(msg, flags, SYSDB_LAST_UPDATE, - (unsigned long)time(NULL)); - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } + subreq = sysdb_set_user_attr_send(state, state->ev, + state->handle, state->domain, + state->name, state->attrs, + SYSDB_MOD_REP); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_store_user_attr_done, req); +} - if (flags == LDB_FLAG_MOD_ADD) { - ret = ldb_build_add_req(&ureq, ctx->ldb, cbctx, msg, NULL, - cbctx, sysdb_op_callback, NULL); - } else { - ret = ldb_build_mod_req(&ureq, ctx->ldb, cbctx, msg, NULL, - cbctx, sysdb_op_callback, NULL); - } - if (ret == LDB_SUCCESS) { - ret = ldb_request(ctx->ldb, ureq); - } - if (ret != LDB_SUCCESS) { - err = sysdb_error_to_errno(ret); - return sysdb_ret_error(cbctx, err, ret); - } - break; +static void sysdb_store_user_add_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + int ret; - default: - return sysdb_ret_error(cbctx, EINVAL, LDB_ERR_OPERATIONS_ERROR); + ret = sysdb_add_user_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + tevent_req_done(req); +} + +static void sysdb_store_user_attr_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + int ret; + + ret = sysdb_set_user_attr_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; } - talloc_free(rep); - return LDB_SUCCESS; + tevent_req_done(req); +} + +int sysdb_store_user_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); } +/* =Store-Group-(Native/Legacy)-(replaces-existing-data)================== */ /* this function does not check that all user members are actually present */ -struct legacy_group_ctx { +struct sysdb_store_group_state { + struct tevent_context *ev; struct sysdb_handle *handle; - struct sysdb_cb_ctx *cbctx; struct sss_domain_info *domain; - struct ldb_dn *dn; - const char *name; gid_t gid; const char **members; - struct ldb_result *res; + struct sysdb_attrs *attrs; }; -static int legacy_group_callback(struct ldb_request *req, - struct ldb_reply *rep); - -int sysdb_legacy_store_group(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *name, gid_t gid, - const char **members, - sysdb_callback_t fn, void *pvt) +static void sysdb_store_group_check(struct tevent_req *subreq); +static void sysdb_store_group_add_done(struct tevent_req *subreq); +static void sysdb_store_group_attr_done(struct tevent_req *subreq); + +struct tevent_req *sysdb_store_group_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, + gid_t gid, + const char **members) { - static const char *attrs[] = { SYSDB_NAME, NULL }; - struct legacy_group_ctx *group_ctx; - struct sysdb_ctx *ctx; - struct ldb_request *req; - int ret; + struct tevent_req *req, *subreq; + struct sysdb_store_group_state *state; + int ret, i; + + req = tevent_req_create(mem_ctx, &state, struct sysdb_store_group_state); + if (!req) return NULL; + + state->ev = ev; + state->handle = handle; + state->domain = domain; + state->name = name; + state->gid = gid; + state->members = members; + state->attrs = NULL; + + if (state->members) { + state->attrs = sysdb_new_attrs(state); + if (!state->attrs) { + ERROR_OUT(ret, ENOMEM, fail); + } + + for (i = 0; state->members[i]; i++) { + if (domain->legacy) { +/* + const char *member; + + member = talloc_asprintf(state, SYSDB_TMPL_USER, + domain->name, state->members[i]); + if (!member) { + ERROR_OUT(ret, ENOMEM, fail); + } +*/ + ret = sysdb_attrs_add_string(state->attrs, SYSDB_LEGACY_MEMBER, + state->members[i]); + if (ret) goto fail; + } else { + ret = sysdb_attrs_add_string(state->attrs, SYSDB_MEMBER, + state->members[i]); + if (ret) goto fail; + } + } + + state->members = NULL; + } - if (!sysdb_handle_check_running(handle)) { - DEBUG(2, ("Invalid request! Not running at this time.\n")); - return EINVAL; + subreq = sysdb_search_group_by_name_send(state, ev, handle, domain, name); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); } + tevent_req_set_callback(subreq, sysdb_store_group_check, req); - ctx = sysdb_handle_get_ctx(handle); + return req; - group_ctx = talloc(handle, struct legacy_group_ctx); - if (!group_ctx) return ENOMEM; +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} - group_ctx->cbctx = talloc_zero(group_ctx, struct sysdb_cb_ctx); - if (!group_ctx->cbctx) return ENOMEM; +static void sysdb_store_group_check(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_store_group_state *state = tevent_req_data(req, + struct sysdb_store_group_state); + struct ldb_message *msg; + int ret; - group_ctx->dn = sysdb_group_dn(ctx, group_ctx, domain->name, name); - if (!group_ctx->dn) return ENOMEM; + ret = sysdb_search_group_recv(subreq, state, &msg); + talloc_zfree(subreq); + if (ret && ret != ENOENT) { + tevent_req_error(req, ret); + return; + } - group_ctx->handle = handle; - group_ctx->cbctx->fn = fn; - group_ctx->cbctx->pvt = pvt; - group_ctx->domain = domain; - group_ctx->name = name; - group_ctx->gid = gid; - group_ctx->members = members; + if (ret == ENOENT) { + /* groups doesn't exist, turn into adding a group */ + subreq = sysdb_add_group_send(state, state->ev, state->handle, + state->domain, state->name, + state->gid, state->attrs); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_store_group_add_done, req); + return; + } - group_ctx->res = talloc_zero(group_ctx, struct ldb_result); - if (!group_ctx->res) return ENOMEM; + /* the group exists, let's just replace attributes when set */ + if (!state->attrs) { + state->attrs = sysdb_new_attrs(state); + if (!state->attrs) { + tevent_req_error(req, ENOMEM); + return; + } + } - ret = ldb_build_search_req(&req, ctx->ldb, group_ctx, - group_ctx->dn, LDB_SCOPE_BASE, - SYSDB_GRENT_FILTER, attrs, NULL, - group_ctx, legacy_group_callback, NULL); - if (ret != LDB_SUCCESS) { - DEBUG(1, ("Failed to build search request: %s(%d)[%s]\n", - ldb_strerror(ret), ret, ldb_errstring(ctx->ldb))); - return sysdb_error_to_errno(ret); + if (state->gid) { + ret = sysdb_attrs_add_uint32(state->attrs, SYSDB_GIDNUM, state->gid); + if (ret) { + tevent_req_error(req, ret); + return; + } } - ret = ldb_request(ctx->ldb, req); - if (ret != LDB_SUCCESS) return sysdb_error_to_errno(ret); + /* FIXME: handle non legacy groups */ - return EOK; + ret = sysdb_attrs_add_time_t(state->attrs, SYSDB_LAST_UPDATE, time(NULL)); + if (ret) { + tevent_req_error(req, ret); + return; + } + + subreq = sysdb_set_group_attr_send(state, state->ev, + state->handle, state->domain, + state->name, state->attrs, + SYSDB_MOD_REP); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_store_group_attr_done, req); } -static int legacy_group_callback(struct ldb_request *req, - struct ldb_reply *rep) +static void sysdb_store_group_add_done(struct tevent_req *subreq) { - struct legacy_group_ctx *group_ctx; - struct sysdb_cb_ctx *cbctx; - struct sysdb_ctx *ctx; - struct ldb_message *msg; - struct ldb_request *greq; - struct ldb_result *res; - int flags; - int i, ret, err; - - group_ctx = talloc_get_type(req->context, struct legacy_group_ctx); - ctx = sysdb_handle_get_ctx(group_ctx->handle); - cbctx = group_ctx->cbctx; - res = group_ctx->res; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + int ret; - if (!rep) { - return sysdb_ret_error(cbctx, EIO, LDB_ERR_OPERATIONS_ERROR); + ret = sysdb_add_group_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; } - if (rep->error != LDB_SUCCESS) { - err = sysdb_error_to_errno(rep->error); - return sysdb_ret_error(cbctx, err, rep->error); + + tevent_req_done(req); +} + +static void sysdb_store_group_attr_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + int ret; + + ret = sysdb_set_group_attr_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; } - switch (rep->type) { - case LDB_REPLY_ENTRY: - res->msgs = talloc_realloc(res, res->msgs, - struct ldb_message *, - res->count + 2); - if (!res->msgs) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } + tevent_req_done(req); +} - res->msgs[res->count + 1] = NULL; +int sysdb_store_group_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); +} - res->msgs[res->count] = talloc_steal(res->msgs, rep->message); - res->count++; - break; +/* =Add-User-to-Group(Native/Legacy)====================================== */ - case LDB_REPLY_DONE: +static void sysdb_add_group_member_done(struct tevent_req *subreq); +static void sysdb_add_group_member_l_done(struct tevent_req *subreq); - msg = ldb_msg_new(cbctx); - if (!msg) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } - msg->dn = group_ctx->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)); - - return sysdb_ret_error(cbctx, EFAULT, LDB_ERR_OPERATIONS_ERROR); - } +struct tevent_req *sysdb_add_group_member_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *group, + const char *user) +{ + struct tevent_req *req, *subreq; + struct sysdb_op_state *state; + struct ldb_dn *group_dn, *user_dn; + struct sysdb_attrs *attrs; + int ret; - talloc_free(res); - group_ctx->res = res = NULL; + req = tevent_req_create(mem_ctx, &state, struct sysdb_op_state); + if (!req) return NULL; - if (flags == LDB_FLAG_MOD_ADD) { - ret = add_string(msg, flags, "objectClass", SYSDB_GROUP_CLASS); - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } + state->ev = ev; + state->handle = handle; + state->ignore_not_found = false; + state->ldbreply = NULL; - ret = add_string(msg, flags, SYSDB_NAME, group_ctx->name); - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } + if (domain->legacy) { + attrs = sysdb_new_attrs(state); + if (!attrs) { + ERROR_OUT(ret, ENOMEM, fail); } - if (group_ctx->gid) { - ret = add_ulong(msg, flags, SYSDB_GIDNUM, - (unsigned long)(group_ctx->gid)); - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } - } else { - DEBUG(0, ("Cached groups can't have GID == 0\n")); - return sysdb_ret_error(cbctx, EINVAL, LDB_ERR_OPERATIONS_ERROR); - } + ret = sysdb_attrs_add_string(attrs, SYSDB_LEGACY_MEMBER, user); + if (ret) goto fail; - /* members */ - if (group_ctx->members && group_ctx->members[0]) { - ret = ldb_msg_add_empty(msg, SYSDB_LEGACY_MEMBER, flags, NULL); - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } - for (i = 0; group_ctx->members[i]; i++) { - ret = ldb_msg_add_string(msg, SYSDB_LEGACY_MEMBER, - group_ctx->members[i]); - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } - } + subreq = sysdb_set_group_attr_send(state, ev, handle, + domain, group, attrs, + SYSDB_MOD_ADD); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); } + tevent_req_set_callback(subreq, sysdb_add_group_member_l_done, req); - /* modification time */ - ret = add_ulong(msg, flags, SYSDB_LAST_UPDATE, - (unsigned long)time(NULL)); - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); + } else { + group_dn = sysdb_group_dn(handle->ctx, state, domain->name, group); + if (!group_dn) { + ERROR_OUT(ret, ENOMEM, fail); } - if (flags == LDB_FLAG_MOD_ADD) { - ret = ldb_build_add_req(&greq, ctx->ldb, cbctx, msg, NULL, - cbctx, sysdb_op_callback, NULL); - } else { - ret = ldb_build_mod_req(&greq, ctx->ldb, cbctx, msg, NULL, - cbctx, sysdb_op_callback, NULL); - } - if (ret == LDB_SUCCESS) { - ret = ldb_request(ctx->ldb, greq); + user_dn = sysdb_user_dn(handle->ctx, state, domain->name, user); + if (!user_dn) { + ERROR_OUT(ret, ENOMEM, fail); } - if (ret != LDB_SUCCESS) { - err = sysdb_error_to_errno(ret); - return sysdb_ret_error(cbctx, err, ret); + + subreq = sysdb_mod_group_member_send(state, ev, handle, + user_dn, group_dn, + SYSDB_MOD_ADD); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); } - break; + tevent_req_set_callback(subreq, sysdb_add_group_member_done, req); + } - default: - return sysdb_ret_error(cbctx, EINVAL, LDB_ERR_OPERATIONS_ERROR); + return req; + +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} + +static void sysdb_add_group_member_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + int ret; + + ret = sysdb_mod_group_member_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; } - talloc_free(rep); - return LDB_SUCCESS; + tevent_req_done(req); } -int sysdb_legacy_add_group_member(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *group, - const char *member, - sysdb_callback_t fn, void *pvt) +static void sysdb_add_group_member_l_done(struct tevent_req *subreq) { - struct sysdb_ctx *ctx; - struct sysdb_cb_ctx *cbctx; - struct ldb_request *req; - struct ldb_message *msg; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); int ret; - if (!sysdb_handle_check_running(handle)) { - DEBUG(2, ("Invalid request! Not running at this time.\n")); - return EINVAL; + ret = sysdb_set_group_attr_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; } - ctx = sysdb_handle_get_ctx(handle); + tevent_req_done(req); +} + +int sysdb_add_group_member_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); +} - cbctx = talloc_zero(handle, struct sysdb_cb_ctx); - if (!cbctx) return ENOMEM; - cbctx->fn = fn; - cbctx->pvt = pvt; +/* =Remove-member-from-Group(Native/Legacy)=============================== */ - /* Add the member_dn as a member of the group */ - msg = ldb_msg_new(cbctx); - if(msg == NULL) return ENOMEM; +static void sysdb_remove_group_member_done(struct tevent_req *subreq); +static void sysdb_remove_group_member_l_done(struct tevent_req *subreq); - msg->dn = sysdb_group_dn(ctx, cbctx, domain->name, group); - if (!msg->dn) return ENOMEM; +struct tevent_req *sysdb_remove_group_member_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *group, + const char *user) +{ + struct tevent_req *req, *subreq; + struct sysdb_op_state *state; + struct ldb_dn *group_dn, *user_dn; + struct sysdb_attrs *attrs; + int ret; - ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_LEGACY_MEMBER, member); - if (ret != LDB_SUCCESS) return ENOMEM; + req = tevent_req_create(mem_ctx, &state, struct sysdb_op_state); + if (!req) return NULL; - ret = ldb_build_mod_req(&req, ctx->ldb, cbctx, msg, - NULL, cbctx, sysdb_op_callback, NULL); - if (ret != LDB_SUCCESS) { - DEBUG(1, ("Failed to build modify request: %s(%d)[%s]\n", - ldb_strerror(ret), ret, ldb_errstring(ctx->ldb))); - return sysdb_error_to_errno(ret); + state->ev = ev; + state->handle = handle; + state->ignore_not_found = false; + state->ldbreply = NULL; + + if (domain->legacy) { + attrs = sysdb_new_attrs(state); + if (!attrs) { + ERROR_OUT(ret, ENOMEM, fail); + } + + ret = sysdb_attrs_add_string(attrs, SYSDB_LEGACY_MEMBER, user); + if (ret) goto fail; + + subreq = sysdb_set_group_attr_send(state, ev, handle, + domain, group, attrs, + SYSDB_MOD_DEL); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_remove_group_member_l_done, req); + + } else { + group_dn = sysdb_group_dn(handle->ctx, state, domain->name, group); + if (!group_dn) { + ERROR_OUT(ret, ENOMEM, fail); + } + + user_dn = sysdb_user_dn(handle->ctx, state, domain->name, user); + if (!user_dn) { + ERROR_OUT(ret, ENOMEM, fail); + } + + subreq = sysdb_mod_group_member_send(state, ev, handle, + user_dn, group_dn, + SYSDB_MOD_DEL); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_remove_group_member_done, req); } - ret = ldb_request(ctx->ldb, req); - if (ret != LDB_SUCCESS) return sysdb_error_to_errno(ret); + return req; - return EOK; +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; } -int sysdb_legacy_remove_group_member(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *group, - const char *member, - sysdb_callback_t fn, void *pvt) +static void sysdb_remove_group_member_done(struct tevent_req *subreq) { - struct sysdb_ctx *ctx; - struct sysdb_cb_ctx *cbctx; - struct ldb_request *req; - struct ldb_message *msg; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); int ret; - if (!sysdb_handle_check_running(handle)) { - DEBUG(2, ("Invalid request! Not running at this time.\n")); - return EINVAL; + ret = sysdb_mod_group_member_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; } - ctx = sysdb_handle_get_ctx(handle); - - cbctx = talloc_zero(handle, struct sysdb_cb_ctx); - if (!cbctx) return ENOMEM; + tevent_req_done(req); +} - cbctx->fn = fn; - cbctx->pvt = pvt; +static void sysdb_remove_group_member_l_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + int ret; - /* Add the member_dn as a member of the group */ - msg = ldb_msg_new(cbctx); - if(msg == NULL) return ENOMEM; + ret = sysdb_set_group_attr_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } - msg->dn = sysdb_group_dn(ctx, cbctx, domain->name, group); - if (!msg->dn) return ENOMEM; + tevent_req_done(req); +} - ret = add_string(msg, LDB_FLAG_MOD_DELETE, SYSDB_LEGACY_MEMBER, member); - if (ret != LDB_SUCCESS) return ENOMEM; +int sysdb_remove_group_member_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); +} - ret = ldb_build_mod_req(&req, ctx->ldb, cbctx, msg, - NULL, cbctx, sysdb_op_callback, NULL); - if (ret != LDB_SUCCESS) { - DEBUG(1, ("Failed to build modify request: %s(%d)[%s]\n", - ldb_strerror(ret), ret, ldb_errstring(ctx->ldb))); - return sysdb_error_to_errno(ret); - } - ret = ldb_request(ctx->ldb, req); - if (ret != LDB_SUCCESS) return sysdb_error_to_errno(ret); +/* ======================================================================= */ - return EOK; -} +static void sysdb_set_cached_password_done(struct tevent_req *subreq); -int sysdb_set_cached_password(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *user, - const char *password, - sysdb_callback_t fn, void *pvt) +struct tevent_req *sysdb_set_cached_password_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *user, + const char *password) { - struct sysdb_ctx *ctx; + struct tevent_req *req, *subreq; + struct sysdb_op_state *state; struct sysdb_attrs *attrs; char *hash = NULL; char *salt; int ret; - ctx = sysdb_handle_get_ctx(handle); - if (!ctx) return EFAULT; + req = tevent_req_create(mem_ctx, &state, struct sysdb_op_state); + if (!req) return NULL; + + state->ev = ev; + state->handle = handle; + state->ignore_not_found = false; + state->ldbreply = NULL; - ret = s3crypt_gen_salt(handle, &salt); + ret = s3crypt_gen_salt(state, &salt); if (ret) { DEBUG(4, ("Failed to generate random salt.\n")); - return ret; + goto fail; } - ret = s3crypt_sha512(handle, password, salt, &hash); + ret = s3crypt_sha512(state, password, salt, &hash); if (ret) { DEBUG(4, ("Failed to create password hash.\n")); - return ret; + goto fail; } - attrs = sysdb_new_attrs(handle); + attrs = sysdb_new_attrs(state); if (!attrs) { - return ENOMEM; + ERROR_OUT(ret, ENOMEM, fail); } ret = sysdb_attrs_add_string(attrs, SYSDB_CACHEDPWD, hash); - if (ret) return ret; + if (ret) goto fail; /* FIXME: should we use a different attribute for chache passwords ?? */ ret = sysdb_attrs_add_long(attrs, "lastCachedPasswordChange", (long)time(NULL)); - if (ret) return ret; + if (ret) goto fail; - ret = sysdb_set_user_attr(handle, domain, user, attrs, fn, pvt); - if (ret) return ret; + subreq = sysdb_set_user_attr_send(state, ev, handle, domain, + user, attrs, SYSDB_MOD_REP); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_set_cached_password_done, req); - return EOK; + return req; + +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} + +static void sysdb_set_cached_password_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + int ret; + + ret = sysdb_set_user_attr_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + tevent_req_done(req); } + +int sysdb_set_cached_password_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); +} + diff --git a/server/db/sysdb_private.h b/server/db/sysdb_private.h index 8c10d9519..d15ec370a 100644 --- a/server/db/sysdb_private.h +++ b/server/db/sysdb_private.h @@ -68,15 +68,36 @@ #include "db/sysdb.h" -struct sysdb_handle; +struct sysdb_handle { + struct sysdb_handle *prev; + struct sysdb_handle *next; + + struct sysdb_ctx *ctx; + struct tevent_req *subreq; + + bool transaction_active; +}; struct sysdb_ctx { struct tevent_context *ev; struct ldb_context *ldb; char *ldb_file; + struct sysdb_handle *queue; }; -bool sysdb_handle_check_running(struct sysdb_handle *handle); +/* An operation blocks the transaction queue as well, but does not + * start a transaction, normally useful only for search type calls. + * do *NOT* call within a transaction you'll deadlock sysdb. + * Also make sure to free the handle as soon as the operation is + * finished to avoid stalling or potentially deadlocking sysdb */ + +struct tevent_req *sysdb_operation_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_ctx *ctx); +int sysdb_operation_recv(struct tevent_req *req, TALLOC_CTX *memctx, + struct sysdb_handle **handle); + +void sysdb_operation_done(struct sysdb_handle *handle); #endif /* __INT_SYS_DB_H__ */ diff --git a/server/db/sysdb_req.c b/server/db/sysdb_req.c deleted file mode 100644 index a768fefb2..000000000 --- a/server/db/sysdb_req.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - 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_handle { - struct sysdb_handle *next, *prev; - struct sysdb_ctx *ctx; - sysdb_fn_t fn; - void *pvt; - int status; - bool transaction_active; -}; - -bool sysdb_handle_check_running(struct sysdb_handle *handle) -{ - if (handle->ctx->queue == handle) return true; - return false; -} - -struct sysdb_ctx *sysdb_handle_get_ctx(struct sysdb_handle *handle) -{ - return handle->ctx; -} - -static void sysdb_queue_run(struct tevent_context *ev, - struct tevent_timer *te, - struct timeval tv, void *ptr) -{ - struct sysdb_handle *handle = talloc_get_type(ptr, struct sysdb_handle); - - if (handle != handle->ctx->queue) abort(); - - handle->fn(handle, handle->pvt); -} - -static int sysdb_queue_schedule(struct sysdb_handle *handle) -{ - struct tevent_timer *te = NULL; - struct timeval tv; - - /* call it asap */ - tv.tv_sec = 0; - tv.tv_usec = 0; - - te = tevent_add_timer(handle->ctx->ev, handle, tv, sysdb_queue_run, handle); - if (te == NULL) { - return EIO; - } - - return EOK; -} - -static int sysdb_enqueue(struct sysdb_handle *handle) -{ - int ret = EOK; - - DLIST_ADD_END(handle->ctx->queue, handle, struct sysdb_handle *); - - if (handle->ctx->queue == handle) { - ret = sysdb_queue_schedule(handle); - } - - return ret; -} - -static void sysdb_transaction_end(struct sysdb_handle *handle); - -static int sysdb_handle_destructor(void *ptr) -{ - struct sysdb_handle *handle; - int ret; - - handle = talloc_get_type(ptr, struct sysdb_handle); - - if (handle->ctx->queue != handle) { - DLIST_REMOVE(handle->ctx->queue, handle); - return 0; - } - - /* handle is the currently running operation or - * scheduled to run operation */ - - if (handle->transaction_active) { - /* freeing before the transaction is complete */ - handle->status = ETIMEDOUT; - sysdb_transaction_end(handle); - } - - DLIST_REMOVE(handle->ctx->queue, handle); - - /* make sure we schedule the next in line if any */ - if (handle->ctx->queue) { - ret = sysdb_queue_schedule(handle->ctx->queue); - if (ret != EOK) abort(); - } - - return 0; -} - -static struct sysdb_handle *sysdb_new_req(TALLOC_CTX *memctx, - struct sysdb_ctx *ctx, - sysdb_fn_t fn, void *pvt) -{ - struct sysdb_handle *handle; - - handle = talloc_zero(memctx, struct sysdb_handle); - if (!handle) return NULL; - - handle->ctx = ctx; - handle->fn = fn; - handle->pvt = pvt; - - talloc_set_destructor((TALLOC_CTX *)handle, sysdb_handle_destructor); - - return handle; -} - -static void sysdb_transaction_int(struct sysdb_handle *ihandle, void *pvt) -{ - struct sysdb_handle *handle = talloc_get_type(pvt, struct sysdb_handle); - int ret; - - /* first of all swap this internal handle with the real one on the queue - * otherwise request_done() will later abort */ - DLIST_REMOVE(handle->ctx->queue, ihandle); - DLIST_ADD(handle->ctx->queue, handle); - - if (ihandle->status != EOK) { - handle->status = ihandle->status; - handle->fn(handle, handle->pvt); - return; - } - - ret = ldb_transaction_start(handle->ctx->ldb); - if (ret != LDB_SUCCESS) { - DEBUG(1, ("Failed to start ldb transaction! (%d)\n", ret)); - handle->status = sysdb_error_to_errno(ret); - } - handle->transaction_active = true; - - handle->fn(handle, handle->pvt); -} - -static void sysdb_transaction_end(struct sysdb_handle *handle) -{ - int ret; - - if (handle->status == EOK) { - ret = ldb_transaction_commit(handle->ctx->ldb); - if (ret != LDB_SUCCESS) { - DEBUG(1, ("Failed to commit ldb transaction! (%d)\n", ret)); - } - } else { - DEBUG(4, ("Canceling transaction (%d[%s])\n", - handle->status, strerror(handle->status))); - ret = ldb_transaction_cancel(handle->ctx->ldb); - if (ret != LDB_SUCCESS) { - DEBUG(1, ("Failed to cancel ldb transaction! (%d)\n", ret)); - /* FIXME: abort() ? */ - } - } - handle->transaction_active = false; -} - -int sysdb_transaction(TALLOC_CTX *memctx, struct sysdb_ctx *ctx, - sysdb_fn_t fn, void *pvt) -{ - struct sysdb_handle *handle, *ihandle; - - handle = sysdb_new_req(memctx, ctx, fn, pvt); - if (!handle) return ENOMEM; - - ihandle = sysdb_new_req(handle, ctx, sysdb_transaction_int, handle); - if (!ihandle) { - talloc_free(ihandle); - return ENOMEM; - } - - return sysdb_enqueue(ihandle); -} - -void sysdb_transaction_done(struct sysdb_handle *handle, int status) -{ - int ret; - - if (handle->ctx->queue != handle) abort(); - if (!handle->transaction_active) abort(); - - handle->status = status; - - sysdb_transaction_end(handle); - - DLIST_REMOVE(handle->ctx->queue, handle); - - if (handle->ctx->queue) { - ret = sysdb_queue_schedule(handle->ctx->queue); - if (ret != EOK) abort(); - } - - talloc_free(handle); -} - -int sysdb_operation(TALLOC_CTX *memctx, struct sysdb_ctx *ctx, - sysdb_fn_t fn, void *pvt) -{ - struct sysdb_handle *handle; - - handle = sysdb_new_req(memctx, ctx, fn, pvt); - if (!handle) return ENOMEM; - - return sysdb_enqueue(handle); -} - -void sysdb_operation_done(struct sysdb_handle *handle) -{ - int ret; - - if (handle->ctx->queue != handle) abort(); - - DLIST_REMOVE(handle->ctx->queue, handle); - - if (handle->ctx->queue) { - ret = sysdb_queue_schedule(handle->ctx->queue); - if (ret != EOK) abort(); - } - - talloc_free(handle); -} - diff --git a/server/db/sysdb_search.c b/server/db/sysdb_search.c index 7e0aed8f2..5ee9f8c0d 100644 --- a/server/db/sysdb_search.c +++ b/server/db/sysdb_search.c @@ -29,6 +29,7 @@ struct sysdb_search_ctx; typedef void (*gen_callback)(struct sysdb_search_ctx *); struct sysdb_search_ctx { + struct tevent_context *ev; struct sysdb_ctx *ctx; struct sysdb_handle *handle; @@ -46,6 +47,8 @@ struct sysdb_search_ctx { struct ldb_result *res; const char **attrs; + + int error; }; static struct sysdb_search_ctx *init_src_ctx(TALLOC_CTX *mem_ctx, @@ -61,6 +64,7 @@ static struct sysdb_search_ctx *init_src_ctx(TALLOC_CTX *mem_ctx, return NULL; } sctx->ctx = ctx; + sctx->ev = ctx->ev; sctx->callback = fn; sctx->ptr = ptr; sctx->res = talloc_zero(sctx, struct ldb_result); @@ -162,15 +166,19 @@ static int get_gen_callback(struct ldb_request *req, /* users */ -static void user_search(struct sysdb_handle *handle, void *ptr) +static void user_search(struct tevent_req *treq) { struct sysdb_search_ctx *sctx; struct ldb_request *req; struct ldb_dn *base_dn; int ret; - sctx = talloc_get_type(ptr, struct sysdb_search_ctx); - sctx->handle = handle; + sctx = tevent_req_callback_data(treq, struct sysdb_search_ctx); + + ret = sysdb_operation_recv(treq, sctx, &sctx->handle); + if (ret) { + return request_error(sctx, ret); + } base_dn = ldb_dn_new_fmt(sctx, sctx->ctx->ldb, SYSDB_TMPL_USER_BASE, sctx->domain->name); @@ -201,6 +209,7 @@ int sysdb_getpwnam(TALLOC_CTX *mem_ctx, { static const char *attrs[] = SYSDB_PW_ATTRS; struct sysdb_search_ctx *sctx; + struct tevent_req *req; if (!domain) { return EINVAL; @@ -219,7 +228,15 @@ int sysdb_getpwnam(TALLOC_CTX *mem_ctx, sctx->attrs = attrs; - return sysdb_operation(mem_ctx, ctx, user_search, sctx); + req = sysdb_operation_send(mem_ctx, ctx->ev, ctx); + if (!req) { + talloc_free(sctx); + return ENOMEM; + } + + tevent_req_set_callback(req, user_search, sctx); + + return EOK; } int sysdb_getpwuid(TALLOC_CTX *mem_ctx, @@ -231,6 +248,7 @@ int sysdb_getpwuid(TALLOC_CTX *mem_ctx, static const char *attrs[] = SYSDB_PW_ATTRS; struct sysdb_search_ctx *sctx; unsigned long int filter_uid = uid; + struct tevent_req *req; if (!domain) { return EINVAL; @@ -249,7 +267,15 @@ int sysdb_getpwuid(TALLOC_CTX *mem_ctx, sctx->attrs = attrs; - return sysdb_operation(mem_ctx, ctx, user_search, sctx); + req = sysdb_operation_send(mem_ctx, ctx->ev, ctx); + if (!req) { + talloc_free(sctx); + return ENOMEM; + } + + tevent_req_set_callback(req, user_search, sctx); + + return EOK; } int sysdb_enumpwent(TALLOC_CTX *mem_ctx, @@ -260,6 +286,7 @@ int sysdb_enumpwent(TALLOC_CTX *mem_ctx, { static const char *attrs[] = SYSDB_PW_ATTRS; struct sysdb_search_ctx *sctx; + struct tevent_req *req; if (!domain) { return EINVAL; @@ -277,7 +304,15 @@ int sysdb_enumpwent(TALLOC_CTX *mem_ctx, sctx->attrs = attrs; - return sysdb_operation(mem_ctx, ctx, user_search, sctx); + req = sysdb_operation_send(mem_ctx, ctx->ev, ctx); + if (!req) { + talloc_free(sctx); + return ENOMEM; + } + + tevent_req_set_callback(req, user_search, sctx); + + return EOK; } /* groups */ @@ -478,7 +513,7 @@ static int get_grp_callback(struct ldb_request *req, return LDB_SUCCESS; } -static void grp_search(struct sysdb_handle *handle, void *ptr) +static void grp_search(struct tevent_req *treq) { struct sysdb_search_ctx *sctx; static const char *attrs[] = SYSDB_GRSRC_ATTRS; @@ -486,8 +521,12 @@ static void grp_search(struct sysdb_handle *handle, void *ptr) struct ldb_dn *base_dn; int ret; - sctx = talloc_get_type(ptr, struct sysdb_search_ctx); - sctx->handle = handle; + sctx = tevent_req_callback_data(treq, struct sysdb_search_ctx); + + ret = sysdb_operation_recv(treq, sctx, &sctx->handle); + if (ret) { + return request_error(sctx, ret); + } if (sctx->domain->mpg) { base_dn = ldb_dn_new_fmt(sctx, sctx->ctx->ldb, @@ -522,6 +561,7 @@ int sysdb_getgrnam(TALLOC_CTX *mem_ctx, sysdb_callback_t fn, void *ptr) { struct sysdb_search_ctx *sctx; + struct tevent_req *req; if (!domain) { return EINVAL; @@ -542,7 +582,15 @@ int sysdb_getgrnam(TALLOC_CTX *mem_ctx, return ENOMEM; } - return sysdb_operation(mem_ctx, ctx, grp_search, sctx); + req = sysdb_operation_send(mem_ctx, ctx->ev, ctx); + if (!req) { + talloc_free(sctx); + return ENOMEM; + } + + tevent_req_set_callback(req, grp_search, sctx); + + return EOK; } int sysdb_getgrgid(TALLOC_CTX *mem_ctx, @@ -552,6 +600,7 @@ int sysdb_getgrgid(TALLOC_CTX *mem_ctx, sysdb_callback_t fn, void *ptr) { struct sysdb_search_ctx *sctx; + struct tevent_req *req; if (!domain) { return EINVAL; @@ -576,7 +625,15 @@ int sysdb_getgrgid(TALLOC_CTX *mem_ctx, return ENOMEM; } - return sysdb_operation(mem_ctx, ctx, grp_search, sctx); + req = sysdb_operation_send(mem_ctx, ctx->ev, ctx); + if (!req) { + talloc_free(sctx); + return ENOMEM; + } + + tevent_req_set_callback(req, grp_search, sctx); + + return EOK; } int sysdb_enumgrent(TALLOC_CTX *mem_ctx, @@ -585,6 +642,7 @@ int sysdb_enumgrent(TALLOC_CTX *mem_ctx, sysdb_callback_t fn, void *ptr) { struct sysdb_search_ctx *sctx; + struct tevent_req *req; if (!domain) { return EINVAL; @@ -601,7 +659,15 @@ int sysdb_enumgrent(TALLOC_CTX *mem_ctx, sctx->expression = SYSDB_GRENT_FILTER; } - return sysdb_operation(mem_ctx, ctx, grp_search, sctx); + req = sysdb_operation_send(mem_ctx, ctx->ev, ctx); + if (!req) { + talloc_free(sctx); + return ENOMEM; + } + + tevent_req_set_callback(req, grp_search, sctx); + + return EOK; } static void initgr_mem_legacy(struct sysdb_search_ctx *sctx) @@ -720,7 +786,7 @@ static void initgr_mem_search(struct sysdb_search_ctx *sctx) } } -static void initgr_search(struct sysdb_handle *handle, void *ptr) +static void initgr_search(struct tevent_req *treq) { struct sysdb_search_ctx *sctx; static const char *attrs[] = SYSDB_PW_ATTRS; @@ -728,8 +794,12 @@ static void initgr_search(struct sysdb_handle *handle, void *ptr) struct ldb_dn *base_dn; int ret; - sctx = talloc_get_type(ptr, struct sysdb_search_ctx); - sctx->handle = handle; + sctx = tevent_req_callback_data(treq, struct sysdb_search_ctx); + + ret = sysdb_operation_recv(treq, sctx, &sctx->handle); + if (ret) { + return request_error(sctx, ret); + } if (sctx->domain->legacy) { sctx->gen_aux_fn = initgr_mem_legacy; @@ -765,6 +835,7 @@ int sysdb_initgroups(TALLOC_CTX *mem_ctx, sysdb_callback_t fn, void *ptr) { struct sysdb_search_ctx *sctx; + struct tevent_req *req; if (!domain) { return EINVAL; @@ -781,7 +852,15 @@ int sysdb_initgroups(TALLOC_CTX *mem_ctx, return ENOMEM; } - return sysdb_operation(mem_ctx, ctx, initgr_search, sctx); + req = sysdb_operation_send(mem_ctx, ctx->ev, ctx); + if (!req) { + talloc_free(sctx); + return ENOMEM; + } + + tevent_req_set_callback(req, initgr_search, sctx); + + return EOK; } int sysdb_get_user_attr(TALLOC_CTX *mem_ctx, @@ -792,6 +871,7 @@ int sysdb_get_user_attr(TALLOC_CTX *mem_ctx, sysdb_callback_t fn, void *ptr) { struct sysdb_search_ctx *sctx; + struct tevent_req *req; if (!domain) { return EINVAL; @@ -810,5 +890,13 @@ int sysdb_get_user_attr(TALLOC_CTX *mem_ctx, sctx->attrs = attributes; - return sysdb_operation(mem_ctx, ctx, user_search, sctx); + req = sysdb_operation_send(mem_ctx, ctx->ev, ctx); + if (!req) { + talloc_free(sctx); + return ENOMEM; + } + + tevent_req_set_callback(req, user_search, sctx); + + return EOK; } diff --git a/server/ldb_modules/memberof.c b/server/ldb_modules/memberof.c index 8b61549a9..bf1760bb0 100644 --- a/server/ldb_modules/memberof.c +++ b/server/ldb_modules/memberof.c @@ -1487,6 +1487,7 @@ static int mbof_del_mod_callback(struct ldb_request *req, LDB_ERR_OPERATIONS_ERROR); case LDB_REPLY_REFERRAL: /* ignore */ + talloc_free(ares); break; case LDB_REPLY_DONE: @@ -1499,7 +1500,6 @@ static int mbof_del_mod_callback(struct ldb_request *req, } } - talloc_free(ares); return LDB_SUCCESS; } diff --git a/server/providers/ldap/ldap_auth.c b/server/providers/ldap/ldap_auth.c index 89e301aae..5d1a81f08 100644 --- a/server/providers/ldap/ldap_auth.c +++ b/server/providers/ldap/ldap_auth.c @@ -656,6 +656,7 @@ done: } struct sdap_pw_cache { + struct tevent_context *ev; struct sysdb_handle *handle; struct sdap_req *lr; }; @@ -665,30 +666,72 @@ static void sdap_reply(struct be_req *req, int ret, char *errstr) req->fn(req, ret, errstr); } -static void sdap_cache_pw_callback(void *pvt, int error, - struct ldb_result *ignore) + +static void sdap_cache_pw_done(struct tevent_req *req) { - struct sdap_pw_cache *data = talloc_get_type(pvt, struct sdap_pw_cache); - if (error != EOK) { + struct sdap_pw_cache *data = tevent_req_callback_data(req, + struct sdap_pw_cache); + int ret; + + ret = sysdb_transaction_commit_recv(req); + if (ret) { DEBUG(2, ("Failed to cache password (%d)[%s]!?\n", - error, strerror(error))); + ret, strerror(ret))); + } + + /* password caching failures are not fatal errors */ + sdap_reply(data->lr->req, data->lr->pd->pam_status, NULL); +} + +static void sdap_cache_pw_callback(struct tevent_req *subreq) +{ + struct sdap_pw_cache *data = tevent_req_callback_data(subreq, + struct sdap_pw_cache); + struct tevent_req *req; + int ret; + + ret = sysdb_set_cached_password_recv(subreq); + talloc_zfree(subreq); + if (ret != EOK) { + goto fail; + } + + req = sysdb_transaction_commit_send(data, data->ev, data->handle); + if (!req) { + ret = ENOMEM; + goto fail; } + tevent_req_set_callback(req, sdap_cache_pw_done, data); + + return; + +fail: + DEBUG(2, ("Failed to cache password (%d)[%s]!?\n", ret, strerror(ret))); - sysdb_transaction_done(data->handle, error); + /* free transaction */ + talloc_zfree(data->handle); /* password caching failures are not fatal errors */ sdap_reply(data->lr->req, data->lr->pd->pam_status, NULL); } -static void sdap_cache_pw_op(struct sysdb_handle *handle, void *pvt) +static void sdap_cache_pw_op(struct tevent_req *req) { - struct sdap_pw_cache *data = talloc_get_type(pvt, struct sdap_pw_cache); + struct sdap_pw_cache *data = tevent_req_callback_data(req, + struct sdap_pw_cache); + struct tevent_req *subreq; struct pam_data *pd; const char *username; char *password; int ret; - data->handle = handle; + ret = sysdb_transaction_recv(req, data, &data->handle); + if (ret) { + DEBUG(1, ("Failed to start transaction (%d)[%s]!?\n", + ret, strerror(ret))); + sdap_reply(data->lr->req, data->lr->pd->pam_status, NULL); + return; + } pd = data->lr->pd; username = pd->user; @@ -715,21 +758,20 @@ static void sdap_cache_pw_op(struct sysdb_handle *handle, void *pvt) return; } - ret = sysdb_set_cached_password(handle, - data->lr->req->be_ctx->domain, - username, - password, - sdap_cache_pw_callback, data); - if (ret != EOK) { + subreq = sysdb_set_cached_password_send(data, data->ev, data->handle, + data->lr->req->be_ctx->domain, + username, password); + if (!subreq) { /* password caching failures are not fatal errors */ sdap_reply(data->lr->req, data->lr->pd->pam_status, NULL); } + tevent_req_set_callback(subreq, sdap_cache_pw_callback, data); } static void sdap_cache_password(struct sdap_req *lr) { struct sdap_pw_cache *data; - int ret; + struct tevent_req *req; data = talloc_zero(lr, struct sdap_pw_cache); if (!data) { @@ -739,16 +781,18 @@ static void sdap_cache_password(struct sdap_req *lr) return; } data->lr = lr; + data->ev = lr->req->be_ctx->ev; - ret = sysdb_transaction(data, lr->req->be_ctx->sysdb, - sdap_cache_pw_op, data); - - if (ret != EOK) { + req = sysdb_transaction_send(data, data->ev, + lr->req->be_ctx->sysdb); + if (!req) { DEBUG(1, ("Failed to start transaction (%d)[%s]!?\n", - ret, strerror(ret))); + ENOMEM, strerror(ENOMEM))); /* password caching failures are not fatal errors */ sdap_reply(data->lr->req, lr->pd->pam_status, NULL); } + + tevent_req_set_callback(req, sdap_cache_pw_op, data); } static void sdap_shutdown(struct be_req *req) diff --git a/server/providers/proxy.c b/server/providers/proxy.c index 6870cef16..9bbfdbd6f 100644 --- a/server/providers/proxy.c +++ b/server/providers/proxy.c @@ -261,6 +261,10 @@ static void proxy_pam_handler(struct be_req *req) { } struct proxy_data { + struct tevent_context *ev; + /* FIXME: should not store it here */ + struct tevent_req *treq; + struct sysdb_handle *handle; struct proxy_ctx *ctx; struct be_req *req; @@ -278,44 +282,85 @@ struct proxy_data { struct ldb_dn *dn; sysdb_callback_t next_fn; + + const char *err; }; static void proxy_reply(struct be_req *req, int error, const char *errstr) { + if (error && !errstr) errstr = "Operation failed"; return req->fn(req, error, errstr); } -static void cache_pw_return(void *pvt, int error, struct ldb_result *ignore) +static void proxy_req_done(struct tevent_req *req) { - struct proxy_data *data = talloc_get_type(pvt, struct proxy_data); + struct proxy_data *data = tevent_req_callback_data(req, struct proxy_data); + int ret; - if (error != EOK) { + ret = sysdb_transaction_commit_recv(req); + if (ret) { DEBUG(2, ("Failed to cache password (%d)[%s]!?\n", - error, strerror(error))); + ret, strerror(ret))); } - sysdb_transaction_done(data->handle, error); + /* password caching failures are not fatal errors */ + proxy_reply(data->req, EOK, data->err); +} + +static void cache_pw_return(struct tevent_req *subreq) +{ + struct proxy_data *data = tevent_req_callback_data(subreq, + struct proxy_data); + struct tevent_req *req; + int ret; + + ret = sysdb_set_cached_password_recv(subreq); + talloc_zfree(subreq); + if (ret != EOK) { + goto fail; + } + + req = sysdb_transaction_commit_send(data, data->ev, data->handle); + if (!req) { + ret = ENOMEM; + goto fail; + } + tevent_req_set_callback(req, proxy_req_done, data); + + return; + +fail: + DEBUG(2, ("Failed to cache password (%d)[%s]!?\n", ret, strerror(ret))); + + /* free transaction */ + talloc_zfree(data->handle); /* password caching failures are not fatal errors */ - return proxy_reply(data->req, EOK, NULL); + proxy_reply(data->req, EOK, NULL); } -static void cache_pw_op(struct sysdb_handle *handle, void *pvt) +static void cache_pw_op(struct tevent_req *req) { - struct proxy_data *data = talloc_get_type(pvt, struct proxy_data); + struct proxy_data *data = tevent_req_callback_data(req, + struct proxy_data); + struct tevent_req *subreq; int ret; - data->handle = handle; + ret = sysdb_transaction_recv(req, data, &data->handle); + if (ret) { + /* password caching failures are not fatal errors */ + return proxy_reply(data->req, EOK, NULL); + } - ret = sysdb_set_cached_password(handle, - data->req->be_ctx->domain, - data->pwd->pw_name, - data->pwd->pw_passwd, - cache_pw_return, data); - if (ret != EOK) { + subreq = sysdb_set_cached_password_send(data, data->ev, data->handle, + data->req->be_ctx->domain, + data->pwd->pw_name, + data->pwd->pw_passwd); + if (!subreq) { /* password caching failures are not fatal errors */ proxy_reply(data->req, EOK, NULL); } + tevent_req_set_callback(subreq, cache_pw_return, data); } static void cache_password(struct be_req *req, @@ -324,7 +369,7 @@ static void cache_password(struct be_req *req, { struct proxy_data *data; struct proxy_ctx *ctx; - int ret; + struct tevent_req *treq; ctx = talloc_get_type(req->be_ctx->pvt_id_data, struct proxy_ctx); @@ -348,82 +393,165 @@ static void cache_password(struct be_req *req, talloc_set_destructor((TALLOC_CTX *)data->pwd->pw_passwd, password_destructor); - ret = sysdb_transaction(data, req->be_ctx->sysdb, cache_pw_op, data); + data->ev = req->be_ctx->ev; - if (ret != EOK) { - DEBUG(1, ("Failed to start transaction (%d)[%s]!?\n", - ret, strerror(ret))); + treq = sysdb_transaction_send(data, data->ev, req->be_ctx->sysdb); + if (!treq) { /* password caching failures are not fatal errors */ return proxy_reply(req, EOK, NULL); } + + tevent_req_set_callback(treq, cache_pw_op, data); } static void proxy_return(void *pvt, int error, struct ldb_result *ignore) { struct proxy_data *data = talloc_get_type(pvt, struct proxy_data); - const char *err = "Success"; + struct tevent_req *req; + int ret; - if (error != EOK) err = "Operation failed"; + if (error != EOK) { + data->err = "Operation failed"; + ret = error; + goto fail; + } + + req = sysdb_transaction_commit_send(data, data->ev, data->handle); + if (!req) { + data->err = "Operation failed"; + ret = ENOMEM; + goto fail; + } - sysdb_transaction_done(data->handle, error); - return proxy_reply(data->req, error, err); + tevent_req_set_callback(req, proxy_req_done, data); + + return; + +fail: + /* free transaction */ + talloc_zfree(data->handle); + + /* password caching failures are not fatal errors */ + proxy_reply(data->req, EOK, NULL); } -static void del_db_entry(struct sysdb_handle *handle, void *pvt) +static void del_db_entry_done(struct tevent_req *subreq); +static void del_db_entry(struct tevent_req *req) { - struct proxy_data *data = talloc_get_type(pvt, struct proxy_data); - struct sysdb_ctx *ctx; + struct proxy_data *data = tevent_req_callback_data(req, + struct proxy_data); + struct tevent_req *subreq; int ret; - data->handle = handle; - ctx = sysdb_handle_get_ctx(handle); + ret = sysdb_transaction_recv(req, data, &data->handle); + if (ret) { + return proxy_reply(data->req, ret, NULL); + } - ret = sysdb_delete_entry(handle, data->dn, data->next_fn, data); - if (ret != EOK) { - proxy_return(data, ret, NULL); + subreq = sysdb_delete_entry_send(data, data->ev, data->handle, data->dn); + if (!subreq) { + proxy_return(data, ENOMEM, NULL); } + tevent_req_set_callback(subreq, del_db_entry_done, data); } -static void del_pw_uid(struct sysdb_handle *handle, void *pvt) +static void del_db_entry_done(struct tevent_req *subreq) { - struct proxy_data *data = talloc_get_type(pvt, struct proxy_data); - struct sysdb_ctx *ctx; + struct proxy_data *data = tevent_req_callback_data(subreq, + struct proxy_data); int ret; - data->handle = handle; - ctx = sysdb_handle_get_ctx(handle); + ret = sysdb_delete_entry_recv(subreq); + talloc_zfree(subreq); + if (ret) { + return proxy_return(data, ret, NULL); + } - ret = sysdb_delete_user_by_uid(handle, - data->req->be_ctx->domain, - data->pwd->pw_uid, - data->next_fn, data); - if (ret != EOK) { - proxy_return(data, ret, NULL); + data->next_fn(data, EOK, NULL); +} + +static void del_pw_uid_done(struct tevent_req *subreq); +static void del_pw_uid(struct tevent_req *req) +{ + struct proxy_data *data = tevent_req_callback_data(req, + struct proxy_data); + struct tevent_req *subreq; + int ret; + + ret = sysdb_transaction_recv(req, data, &data->handle); + if (ret) { + return proxy_reply(data->req, ret, NULL); } + + subreq = sysdb_delete_user_by_uid_send(data, data->ev, data->handle, + data->req->be_ctx->domain, + data->pwd->pw_uid); + if (!subreq) { + proxy_return(data, ENOMEM, NULL); + } + tevent_req_set_callback(subreq, del_pw_uid_done, data); } -static void set_pw_name(struct sysdb_handle *handle, void *pvt) +static void del_pw_uid_done(struct tevent_req *subreq) { - struct proxy_data *data = talloc_get_type(pvt, struct proxy_data); - struct sysdb_ctx *ctx; + struct proxy_data *data = tevent_req_callback_data(subreq, + struct proxy_data); int ret; - data->handle = handle; - ctx = sysdb_handle_get_ctx(handle); + ret = sysdb_delete_user_by_uid_recv(subreq); + talloc_zfree(subreq); + if (ret) { + return proxy_return(data, ret, NULL); + } - ret = sysdb_legacy_store_user(handle, data->req->be_ctx->domain, - data->pwd->pw_name, data->pwd->pw_passwd, - data->pwd->pw_uid, data->pwd->pw_gid, - data->pwd->pw_gecos, data->pwd->pw_dir, - data->pwd->pw_shell, - data->next_fn, data); - if (ret != EOK) { + data->next_fn(data, EOK, NULL); +} + +static void set_pw_name_done(struct tevent_req *subreq); + +static void set_pw_name(struct tevent_req *req) +{ + struct proxy_data *data = tevent_req_callback_data(req, + struct proxy_data); + struct tevent_req *subreq; + int ret; + + ret = sysdb_transaction_recv(req, data, &data->handle); + if (ret) { + return proxy_reply(data->req, ret, NULL); + } + + subreq = sysdb_store_user_send(data, data->ev, data->handle, + data->req->be_ctx->domain, + data->pwd->pw_name, data->pwd->pw_passwd, + data->pwd->pw_uid, data->pwd->pw_gid, + data->pwd->pw_gecos, data->pwd->pw_dir, + data->pwd->pw_shell); + if (!subreq) { proxy_return(data, ret, NULL); + return; } + tevent_req_set_callback(subreq, set_pw_name_done, data); } +static void set_pw_name_done(struct tevent_req *subreq) +{ + struct proxy_data *data = tevent_req_callback_data(subreq, + struct proxy_data); + int ret; + + ret = sysdb_store_user_recv(subreq); + if (ret) { + return proxy_reply(data->req, ret, NULL); + } + + data->next_fn(data, EOK, NULL); +} + + static void get_pw_name(struct be_req *req, char *name) { + struct tevent_req *treq = NULL; struct proxy_ctx *ctx; enum nss_status status; struct proxy_data *data; @@ -436,6 +564,7 @@ static void get_pw_name(struct be_req *req, char *name) return proxy_reply(req, ENOMEM, "Out of memory"); data->req = req; data->ctx = ctx; + data->ev = req->be_ctx->ev; data->next_fn = proxy_return; data->pwd = talloc(data, struct passwd); if (!data->pwd) @@ -456,18 +585,29 @@ static void get_pw_name(struct be_req *req, char *name) if (!data->dn) return proxy_reply(req, ENOMEM, "Out of memory"); - ret = sysdb_transaction(data, req->be_ctx->sysdb, del_db_entry, data); + treq = sysdb_transaction_send(data, data->ev, req->be_ctx->sysdb); + if (!treq) { + return proxy_reply(req, ENOMEM, NULL); + } + + tevent_req_set_callback(treq, del_db_entry, data); break; case NSS_STATUS_SUCCESS: + treq = sysdb_transaction_send(data, data->ev, req->be_ctx->sysdb); + if (!treq) { + return proxy_reply(req, ENOMEM, NULL); + } + /* FIXME: verify user does not have uid=0 or gid=0 as these are invalid * values */ if (data->pwd->pw_uid == 0 || data->pwd->pw_gid == 0) { - ret = sysdb_transaction(data, req->be_ctx->sysdb, del_db_entry, data); + + tevent_req_set_callback(treq, del_db_entry, data); break; } - ret = sysdb_transaction(data, req->be_ctx->sysdb, set_pw_name, data); + tevent_req_set_callback(treq, set_pw_name, data); break; case NSS_STATUS_UNAVAIL: @@ -480,16 +620,11 @@ static void get_pw_name(struct be_req *req, char *name) DEBUG(2, ("proxy -> getpwnam_r failed for '%s' <%d>\n", name, status)); return proxy_reply(req, EOK, "Operation failed"); } - - if (ret != EOK) { - DEBUG(1, ("Failed to start transaction (%d)[%s]!?\n", - ret, strerror(ret))); - return proxy_reply(req, ret, "Operation failed"); - } } static void get_pw_uid(struct be_req *req, uid_t uid) { + struct tevent_req *treq = NULL; struct proxy_ctx *ctx; enum nss_status status; struct proxy_data *data; @@ -502,6 +637,7 @@ static void get_pw_uid(struct be_req *req, uid_t uid) return proxy_reply(req, ENOMEM, "Out of memory"); data->req = req; data->ctx = ctx; + data->ev = req->be_ctx->ev; data->next_fn = proxy_return; data->pwd = talloc(data, struct passwd); if (!data->pwd) @@ -518,21 +654,32 @@ static void get_pw_uid(struct be_req *req, uid_t uid) switch (status) { case NSS_STATUS_NOTFOUND: data->pwd->pw_uid = uid; - ret = sysdb_transaction(data, req->be_ctx->sysdb, del_pw_uid, data); + + treq = sysdb_transaction_send(data, data->ev, req->be_ctx->sysdb); + if (!treq) { + return proxy_reply(req, ENOMEM, NULL); + } + + tevent_req_set_callback(treq, del_pw_uid, data); break; case NSS_STATUS_SUCCESS: + treq = sysdb_transaction_send(data, data->ev, req->be_ctx->sysdb); + if (!treq) { + return proxy_reply(req, ENOMEM, NULL); + } + /* FIXME: verify user does not have gid=0 as these are invalid values */ if (data->pwd->pw_gid == 0) { data->dn = sysdb_user_dn(req->be_ctx->sysdb, data, req->be_ctx->domain->name, data->pwd->pw_name); - ret = sysdb_transaction(data, req->be_ctx->sysdb, - del_db_entry, data); + + tevent_req_set_callback(treq, del_db_entry, data); break; } - ret = sysdb_transaction(data, req->be_ctx->sysdb, set_pw_name, data); + tevent_req_set_callback(treq, set_pw_name, data); break; case NSS_STATUS_UNAVAIL: @@ -546,37 +693,26 @@ static void get_pw_uid(struct be_req *req, uid_t uid) (unsigned long)uid, ret, strerror(ret))); return proxy_reply(req, ret, "Operation failed"); } - - if (ret != EOK) { - DEBUG(1, ("Failed to start transaction (%d)[%s]!?\n", - ret, strerror(ret))); - return proxy_reply(req, ret, "Operation failed"); - } } #define MAX_BUF_SIZE 1024*1024 /* max 1MiB */ -static void get_pw_entry(struct sysdb_handle *handle, void *pvt); - -static void get_next_pw_entry(void *pvt, int error, struct ldb_result *ignore) +static void get_pw_entry_store_done(struct tevent_req *subreq); +static void get_pw_entry(struct tevent_req *req) { - struct proxy_data *data = talloc_get_type(pvt, struct proxy_data); - - if (error != EOK) proxy_return(data, error, NULL); - - get_pw_entry(data->handle, data); -} - -static void get_pw_entry(struct sysdb_handle *handle, void *pvt) -{ - struct proxy_data *data = talloc_get_type(pvt, struct proxy_data); + struct proxy_data *data = tevent_req_callback_data(req, + struct proxy_data); enum nss_status status; - struct sysdb_ctx *ctx; + struct tevent_req *subreq; char *newb; int ret; - data->handle = handle; - ctx = sysdb_handle_get_ctx(handle); + data->treq = req; + + ret = sysdb_transaction_recv(req, data, &data->handle); + if (ret) { + return proxy_reply(data->req, ret, NULL); + } retry: status = data->ctx->ops.getpwent_r(data->pwd, @@ -611,20 +747,20 @@ retry: goto retry; /* skip */ } - ret = sysdb_legacy_store_user(handle, data->req->be_ctx->domain, - data->pwd->pw_name, - data->pwd->pw_passwd, - data->pwd->pw_uid, - data->pwd->pw_gid, - data->pwd->pw_gecos, - data->pwd->pw_dir, - data->pwd->pw_shell, - get_next_pw_entry, data); - if (ret != EOK) { - DEBUG(1, ("Failed to update LDB Cache for '%s' (%d)[%s] !?\n", - data->pwd->pw_name, ret, strerror(ret))); - proxy_return(data, ret, NULL); + subreq = sysdb_store_user_send(data, data->ev, data->handle, + data->req->be_ctx->domain, + data->pwd->pw_name, + data->pwd->pw_passwd, + data->pwd->pw_uid, + data->pwd->pw_gid, + data->pwd->pw_gecos, + data->pwd->pw_dir, + data->pwd->pw_shell); + if (!subreq) { + proxy_return(data, ENOMEM, NULL); + return; } + tevent_req_set_callback(subreq, get_pw_entry_store_done, data); break; case NSS_STATUS_UNAVAIL: @@ -640,12 +776,30 @@ retry: } } +static void get_pw_entry_store_done(struct tevent_req *subreq) +{ + struct proxy_data *data = tevent_req_callback_data(subreq, + struct proxy_data); + int ret; + + ret = sysdb_store_user_recv(subreq); + talloc_zfree(subreq); + if (ret) { + DEBUG(1, ("Failed to update LDB Cache for '%s' (%d)[%s] !?\n", + data->pwd->pw_name, ret, strerror(ret))); + proxy_return(data, ret, NULL); + return; + } + + get_pw_entry(data->treq); +} + static void enum_users(struct be_req *req) { + struct tevent_req *treq = NULL; struct proxy_ctx *ctx; enum nss_status status; struct proxy_data *data; - int ret; ctx = talloc_get_type(req->be_ctx->pvt_id_data, struct proxy_ctx); @@ -654,6 +808,7 @@ static void enum_users(struct be_req *req) return proxy_reply(req, ENOMEM, "Out of memory"); data->req = req; data->ctx = ctx; + data->ev = req->be_ctx->ev; data->next_fn = proxy_return; data->pwd = talloc(data, struct passwd); if (!data->pwd) @@ -668,53 +823,96 @@ static void enum_users(struct be_req *req) if (status != NSS_STATUS_SUCCESS) return proxy_reply(req, EIO, "Operation failed"); - ret = sysdb_transaction(data, req->be_ctx->sysdb, get_pw_entry, data); - if (ret != EOK) { - DEBUG(1, ("Failed to start transaction (%d)[%s]!?\n", - ret, strerror(ret))); - return proxy_reply(req, ret, "Operation failed"); + treq = sysdb_transaction_send(data, data->ev, req->be_ctx->sysdb); + if (!treq) { + return proxy_reply(req, ENOMEM, "Operation failed"); } + + tevent_req_set_callback(treq, get_pw_entry, data); } -static void del_gr_gid(struct sysdb_handle *handle, void *pvt) +static void del_gr_gid_done(struct tevent_req *subreq); +static void del_gr_gid(struct tevent_req *req) { - struct proxy_data *data = talloc_get_type(pvt, struct proxy_data); - struct sysdb_ctx *ctx; + struct proxy_data *data = tevent_req_callback_data(req, + struct proxy_data); + struct tevent_req *subreq; + int ret; + + ret = sysdb_transaction_recv(req, data, &data->handle); + if (ret) { + return proxy_reply(data->req, ret, NULL); + } + + subreq = sysdb_delete_group_by_gid_send(data, data->ev, data->handle, + data->req->be_ctx->domain, + data->grp->gr_gid); + if (!subreq) { + proxy_return(data, ENOMEM, NULL); + } + tevent_req_set_callback(subreq, del_gr_gid_done, data); +} + +static void del_gr_gid_done(struct tevent_req *subreq) +{ + struct proxy_data *data = tevent_req_callback_data(subreq, + struct proxy_data); + int ret; + + ret = sysdb_delete_group_by_gid_recv(subreq); + talloc_zfree(subreq); + if (ret) { + return proxy_return(data, ret, NULL); + } + + data->next_fn(data, EOK, NULL); +} + +static void set_gr_name_done(struct tevent_req *subreq); + +static void set_gr_name(struct tevent_req *req) +{ + struct proxy_data *data = tevent_req_callback_data(req, + struct proxy_data); + struct tevent_req *subreq; int ret; - data->handle = handle; - ctx = sysdb_handle_get_ctx(handle); + ret = sysdb_transaction_recv(req, data, &data->handle); + if (ret) { + return proxy_reply(data->req, ret, NULL); + } - ret = sysdb_delete_group_by_gid(handle, + subreq = sysdb_store_group_send(data, data->ev, data->handle, data->req->be_ctx->domain, + data->grp->gr_name, data->grp->gr_gid, - data->next_fn, data); - if (ret != EOK) { + (const char **)data->grp->gr_mem); + if (!subreq) { proxy_return(data, ret, NULL); + return; } + tevent_req_set_callback(subreq, set_gr_name_done, data); } -static void set_gr_name(struct sysdb_handle *handle, void *pvt) +static void set_gr_name_done(struct tevent_req *subreq) { - struct proxy_data *data = talloc_get_type(pvt, struct proxy_data); - struct sysdb_ctx *ctx; + struct proxy_data *data = tevent_req_callback_data(subreq, + struct proxy_data); int ret; - data->handle = handle; - ctx = sysdb_handle_get_ctx(handle); - - ret = sysdb_legacy_store_group(handle, data->req->be_ctx->domain, - data->grp->gr_name, - data->grp->gr_gid, - (const char **)data->grp->gr_mem, - data->next_fn, data); - if (ret != EOK) { + ret = sysdb_store_group_recv(subreq); + talloc_zfree(subreq); + if (ret) { proxy_return(data, ret, NULL); + return; } + + data->next_fn(data, EOK, NULL); } static void get_gr_name(struct be_req *req, char *name) { + struct tevent_req *treq = NULL; struct proxy_ctx *ctx; enum nss_status status; struct proxy_data *data; @@ -727,6 +925,7 @@ static void get_gr_name(struct be_req *req, char *name) return proxy_reply(req, ENOMEM, "Out of memory"); data->req = req; data->ctx = ctx; + data->ev = req->be_ctx->ev; data->next_fn = proxy_return; data->grp = talloc(data, struct group); if (!data->grp) @@ -747,17 +946,28 @@ static void get_gr_name(struct be_req *req, char *name) if (!data->dn) return proxy_reply(req, ENOMEM, "Out of memory"); - ret = sysdb_transaction(data, req->be_ctx->sysdb, del_db_entry, data); + treq = sysdb_transaction_send(data, data->ev, req->be_ctx->sysdb); + if (!treq) { + return proxy_reply(req, ENOMEM, NULL); + } + + tevent_req_set_callback(treq, del_db_entry, data); break; case NSS_STATUS_SUCCESS: + treq = sysdb_transaction_send(data, data->ev, req->be_ctx->sysdb); + if (!treq) { + return proxy_reply(req, ENOMEM, NULL); + } + /* FIXME: verify group does not have gid=0 as this is invalid */ if (data->grp->gr_gid == 0) { - ret = sysdb_transaction(data, req->be_ctx->sysdb, del_db_entry, data); + + tevent_req_set_callback(treq, del_db_entry, data); break; } - ret = sysdb_transaction(data, req->be_ctx->sysdb, set_gr_name, data); + tevent_req_set_callback(treq, set_gr_name, data); break; case NSS_STATUS_UNAVAIL: @@ -771,16 +981,11 @@ static void get_gr_name(struct be_req *req, char *name) name, ret, strerror(ret))); return proxy_reply(req, ret, "Operation failed"); } - - if (ret != EOK) { - DEBUG(1, ("Failed to start transaction (%d)[%s]!?\n", - ret, strerror(ret))); - return proxy_reply(req, ret, "Operation failed"); - } } static void get_gr_gid(struct be_req *req, gid_t gid) { + struct tevent_req *treq = NULL; struct proxy_ctx *ctx; enum nss_status status; struct proxy_data *data; @@ -793,6 +998,7 @@ static void get_gr_gid(struct be_req *req, gid_t gid) return proxy_reply(req, ENOMEM, "Out of memory"); data->req = req; data->ctx = ctx; + data->ev = req->be_ctx->ev; data->next_fn = proxy_return; data->grp = talloc(data, struct group); if (!data->grp) @@ -809,21 +1015,32 @@ static void get_gr_gid(struct be_req *req, gid_t gid) switch (status) { case NSS_STATUS_NOTFOUND: data->grp->gr_gid = gid; - ret = sysdb_transaction(data, req->be_ctx->sysdb, del_gr_gid, data); + + treq = sysdb_transaction_send(data, data->ev, req->be_ctx->sysdb); + if (!treq) { + return proxy_reply(req, ENOMEM, NULL); + } + + tevent_req_set_callback(treq, del_gr_gid, data); break; case NSS_STATUS_SUCCESS: + treq = sysdb_transaction_send(data, data->ev, req->be_ctx->sysdb); + if (!treq) { + return proxy_reply(req, ENOMEM, NULL); + } + /* FIXME: verify group does not have gid=0 as this is invalid */ if (data->grp->gr_gid == 0) { data->dn = sysdb_group_dn(req->be_ctx->sysdb, data, req->be_ctx->domain->name, data->grp->gr_name); - ret = sysdb_transaction(data, req->be_ctx->sysdb, - del_db_entry, data); + + tevent_req_set_callback(treq, del_db_entry, data); break; } - ret = sysdb_transaction(data, req->be_ctx->sysdb, set_gr_name, data); + tevent_req_set_callback(treq, set_gr_name, data); break; case NSS_STATUS_UNAVAIL: @@ -837,35 +1054,25 @@ static void get_gr_gid(struct be_req *req, gid_t gid) (unsigned long)gid, ret, strerror(ret))); return proxy_reply(req, ret, "Operation failed"); } - - if (ret != EOK) { - DEBUG(1, ("Failed to start transaction (%d)[%s]!?\n", - ret, strerror(ret))); - return proxy_reply(req, ret, "Operation failed"); - } } -static void get_gr_entry(struct sysdb_handle *handle, void *pvt); +static void get_gr_entry_store_done(struct tevent_req *subreq); -static void get_next_gr_entry(void *pvt, int error, struct ldb_result *ignore) +static void get_gr_entry(struct tevent_req *req) { - struct proxy_data *data = talloc_get_type(pvt, struct proxy_data); - - if (error != EOK) proxy_return(data, error, NULL); - - get_gr_entry(data->handle, data); -} - -static void get_gr_entry(struct sysdb_handle *handle, void *pvt) -{ - struct proxy_data *data = talloc_get_type(pvt, struct proxy_data); + struct proxy_data *data = tevent_req_callback_data(req, + struct proxy_data); enum nss_status status; - struct sysdb_ctx *ctx; + struct tevent_req *subreq; char *newb; int ret; - data->handle = handle; - ctx = sysdb_handle_get_ctx(handle); + data->treq = req; + + ret = sysdb_transaction_recv(req, data, &data->handle); + if (ret) { + return proxy_reply(data->req, ret, NULL); + } retry: status = data->ctx->ops.getgrent_r(data->grp, @@ -898,16 +1105,15 @@ retry: if (data->grp->gr_gid == 0) { goto retry; } - ret = sysdb_legacy_store_group(handle, data->req->be_ctx->domain, - data->grp->gr_name, - data->grp->gr_gid, - (const char **)data->grp->gr_mem, - get_next_gr_entry, data); - if (ret != EOK) { - DEBUG(1, ("Failed to update LDB Cache for '%s' (%d)[%s] !?\n", - data->grp->gr_name, ret, strerror(ret))); - proxy_return(data, ret, NULL); + subreq = sysdb_store_group_send(data, data->ev, data->handle, + data->req->be_ctx->domain, + data->grp->gr_name, + data->grp->gr_gid, + (const char **)data->grp->gr_mem); + if (!subreq) { + proxy_return(data, ENOMEM, NULL); } + tevent_req_set_callback(subreq, get_gr_entry_store_done, data); break; case NSS_STATUS_UNAVAIL: @@ -923,12 +1129,30 @@ retry: } } +static void get_gr_entry_store_done(struct tevent_req *subreq) +{ + struct proxy_data *data = tevent_req_callback_data(subreq, + struct proxy_data); + int ret; + + ret = sysdb_store_group_recv(subreq); + talloc_zfree(subreq); + if (ret) { + DEBUG(1, ("Failed to update LDB Cache for '%s' (%d)[%s] !?\n", + data->grp->gr_name, ret, strerror(ret))); + proxy_return(data, ret, NULL); + return; + } + + get_gr_entry(data->treq); +} + static void enum_groups(struct be_req *req) { + struct tevent_req *treq = NULL; struct proxy_ctx *ctx; enum nss_status status; struct proxy_data *data; - int ret; ctx = talloc_get_type(req->be_ctx->pvt_id_data, struct proxy_ctx); @@ -937,6 +1161,7 @@ static void enum_groups(struct be_req *req) return proxy_reply(req, ENOMEM, "Out of memory"); data->req = req; data->ctx = ctx; + data->ev = req->be_ctx->ev; data->next_fn = proxy_return; data->grp = talloc(data, struct group); if (!data->grp) @@ -951,39 +1176,23 @@ static void enum_groups(struct be_req *req) if (status != NSS_STATUS_SUCCESS) return proxy_reply(req, EIO, "Operation failed"); - ret = sysdb_transaction(data, req->be_ctx->sysdb, get_gr_entry, data); - if (ret != EOK) { - DEBUG(1, ("Failed to start transaction (%d)[%s]!?\n", - ret, strerror(ret))); - return proxy_reply(req, ret, "Operation failed"); + treq = sysdb_transaction_send(data, data->ev, req->be_ctx->sysdb); + if (!treq) { + return proxy_reply(req, ENOMEM, "Operation failed"); } -} - -static void get_gid_entry(struct sysdb_handle *handle, void *pvt); - -static void get_next_gid_entry(void *pvt, int error, struct ldb_result *ignore) -{ - struct proxy_data *data = talloc_get_type(pvt, struct proxy_data); - if (error != EOK) proxy_return(data, error, NULL); - - get_gid_entry(data->handle, data); + tevent_req_set_callback(treq, get_gr_entry, data); } -static void get_gid_entry(struct sysdb_handle *handle, void *pvt) +static void get_gid_entry_store_done(struct tevent_req *subreq); +static void get_gid_entry_del_done(struct tevent_req *subreq); +static void get_gid_entry(struct proxy_data *data) { - struct proxy_data *data = talloc_get_type(pvt, struct proxy_data); + struct tevent_req *subreq; enum nss_status status; - struct sysdb_ctx *ctx; char *newb; int ret; - ctx = sysdb_handle_get_ctx(handle); - - /* all done */ - if (data->cur == data->num) - return data->next_fn(data, EOK, NULL); - retry: status = data->ctx->ops.getgrgid_r(data->groups[data->cur], data->grp, data->buffer, data->buflen, &ret); @@ -1005,31 +1214,29 @@ retry: goto retry; case NSS_STATUS_NOTFOUND: - data->cur++; DEBUG(4, ("gid [%lu] not found, removing group\n", (unsigned long)(data->groups[data->cur]))); - ret = sysdb_delete_group_by_gid(handle, data->req->be_ctx->domain, - data->groups[data->cur-1], - get_next_gid_entry, data); - if (ret != EOK) { - DEBUG(1, ("Failed to update LDB Cache for '%s' (%d)[%s] !?\n", - data->grp->gr_name, ret, strerror(ret))); - proxy_return(data, ret, NULL); + subreq = sysdb_delete_group_by_gid_send(data, data->ev, + data->handle, + data->req->be_ctx->domain, + data->groups[data->cur]); + if (!subreq) { + proxy_return(data, ENOMEM, NULL); } + tevent_req_set_callback(subreq, get_gid_entry_del_done, data); break; case NSS_STATUS_SUCCESS: data->cur++; - ret = sysdb_legacy_store_group(handle, data->req->be_ctx->domain, - data->grp->gr_name, - data->grp->gr_gid, - (const char **)data->grp->gr_mem, - get_next_gid_entry, data); - if (ret != EOK) { - DEBUG(1, ("Failed to update LDB Cache for '%s' (%d)[%s] !?\n", - data->grp->gr_name, ret, strerror(ret))); - proxy_return(data, ret, NULL); + subreq = sysdb_store_group_send(data, data->ev, data->handle, + data->req->be_ctx->domain, + data->grp->gr_name, + data->grp->gr_gid, + (const char **)data->grp->gr_mem); + if (!subreq) { + proxy_return(data, ENOMEM, NULL); } + tevent_req_set_callback(subreq, get_gid_entry_store_done, data); break; default: @@ -1039,6 +1246,56 @@ retry: } } +static void get_gid_entry_del_done(struct tevent_req *subreq) +{ + struct proxy_data *data = tevent_req_callback_data(subreq, + struct proxy_data); + int ret; + + ret = sysdb_delete_group_by_gid_recv(subreq); + talloc_zfree(subreq); + if (ret) { + DEBUG(1, ("Failed to update LDB Cache for '%s' (%d)[%s] !?\n", + data->grp->gr_name, ret, strerror(ret))); + return proxy_return(data, ret, NULL); + } + + data->cur++; + + /* all done */ + if (data->cur == data->num) { + return data->next_fn(data, EOK, NULL); + } + + /* next item */ + get_gid_entry(data); +} + +static void get_gid_entry_store_done(struct tevent_req *subreq) +{ + struct proxy_data *data = tevent_req_callback_data(subreq, + struct proxy_data); + int ret; + + ret = sysdb_store_group_recv(subreq); + talloc_zfree(subreq); + if (ret) { + DEBUG(1, ("Failed to update LDB Cache for '%s' (%d)[%s] !?\n", + data->grp->gr_name, ret, strerror(ret))); + return proxy_return(data, ret, NULL); + } + + data->cur++; + + /* all done */ + if (data->cur == data->num) { + return data->next_fn(data, EOK, NULL); + } + + /* next item */ + get_gid_entry(data); +} + static void get_user_groups(void *pvt, int error, struct ldb_result *ignore) { struct proxy_data *data = talloc_get_type(pvt, struct proxy_data); @@ -1092,7 +1349,7 @@ retry: data->num = start; DEBUG(4, ("User [%s] appears to be member of %lu groups\n", name, data->num)); - get_gid_entry(data->handle, data); + get_gid_entry(data); break; default: @@ -1104,6 +1361,7 @@ retry: static void get_initgr_user(struct be_req *req, char *name) { + struct tevent_req *treq = NULL; struct proxy_ctx *ctx; enum nss_status status; struct proxy_data *data; @@ -1116,6 +1374,7 @@ static void get_initgr_user(struct be_req *req, char *name) return proxy_reply(req, ENOMEM, "Out of memory"); data->req = req; data->ctx = ctx; + data->ev = req->be_ctx->ev; data->next_fn = proxy_return; data->pwd = talloc(data, struct passwd); if (!data->pwd) @@ -1139,28 +1398,40 @@ static void get_initgr_user(struct be_req *req, char *name) if (!data->dn) return proxy_reply(req, ENOMEM, "Out of memory"); - ret = sysdb_transaction(data, req->be_ctx->sysdb, del_db_entry, data); + treq = sysdb_transaction_send(data, data->ev, req->be_ctx->sysdb); + if (!treq) { + return proxy_reply(req, ENOMEM, NULL); + } + + tevent_req_set_callback(treq, del_db_entry, data); break; case NSS_STATUS_SUCCESS: + treq = sysdb_transaction_send(data, data->ev, req->be_ctx->sysdb); + if (!treq) { + return proxy_reply(req, ENOMEM, NULL); + } + /* FIXME: verify user does not have uid=0 or gid=0 as these are invalid * values */ if (data->pwd->pw_uid == 0 || data->pwd->pw_gid == 0) { - ret = sysdb_transaction(data, req->be_ctx->sysdb, del_db_entry, data); + + tevent_req_set_callback(treq, del_db_entry, data); break; } if (ctx->ops.initgroups_dyn) { data->next_fn = get_user_groups; - ret = sysdb_transaction(data, req->be_ctx->sysdb, set_pw_name, data); + + tevent_req_set_callback(treq, set_pw_name, data); } else { status = ctx->ops.setgrent(); if (status != NSS_STATUS_SUCCESS) return proxy_reply(req, EIO, "Operation failed"); - ret = sysdb_transaction(data, req->be_ctx->sysdb, get_gr_entry, data); - break; + tevent_req_set_callback(treq, get_gr_entry, data); } + break; case NSS_STATUS_UNAVAIL: /* "remote" backend unavailable. Enter offline mode */ @@ -1173,12 +1444,6 @@ static void get_initgr_user(struct be_req *req, char *name) name, ret, strerror(ret))); return proxy_reply(req, ret, "Operation failed"); } - - if (ret != EOK) { - DEBUG(1, ("Failed to start transaction (%d)[%s]!?\n", - ret, strerror(ret))); - return proxy_reply(req, ret, "Operation failed"); - } } /* TODO: actually do check something */ diff --git a/server/responder/pam/pam_LOCAL_domain.c b/server/responder/pam/pam_LOCAL_domain.c index 15116a5e2..5c1fea993 100644 --- a/server/responder/pam/pam_LOCAL_domain.c +++ b/server/responder/pam/pam_LOCAL_domain.c @@ -47,6 +47,7 @@ struct LOCAL_request { + struct tevent_context *ev; struct sysdb_ctx *dbctx; struct sysdb_attrs *mod_attrs; struct sysdb_handle *handle; @@ -86,51 +87,89 @@ static void prepare_reply(struct LOCAL_request *lreq) lreq->preq->callback(lreq->preq); } -static void set_user_attr_callback(void *pvt, int ldb_status, struct ldb_result *res) +static void set_user_attr_done(struct tevent_req *req) { struct LOCAL_request *lreq; + int ret; - DEBUG(4, ("entering set_user_attr_callback, status [%d][%s]\n", - ldb_status, ldb_strerror(ldb_status))); - - lreq = talloc_get_type(pvt, struct LOCAL_request); - - sysdb_transaction_done(lreq->handle, sysdb_error_to_errno(ldb_status)); + lreq = tevent_req_callback_data(req, struct LOCAL_request); - NEQ_CHECK_OR_JUMP(ldb_status, LDB_SUCCESS, ("set_user_attr failed.\n"), - lreq->error, sysdb_error_to_errno(ldb_status), done); + ret = sysdb_transaction_commit_recv(req); + if (ret) { + DEBUG(2, ("set_user_attr failed.\n")); + lreq->error =ret; + } -done: prepare_reply(lreq); } -static void set_user_attr_req(struct sysdb_handle *handle, void *pvt) +static void set_user_attr_req_done(struct tevent_req *subreq); +static void set_user_attr_req(struct tevent_req *req) { + struct LOCAL_request *lreq = tevent_req_callback_data(req, + struct LOCAL_request); + struct tevent_req *subreq; int ret; - struct LOCAL_request *lreq; DEBUG(4, ("entering set_user_attr_req\n")); - lreq = talloc_get_type(pvt, struct LOCAL_request); + ret = sysdb_transaction_recv(req, lreq, &lreq->handle); + if (ret) { + lreq->error = ret; + return prepare_reply(lreq); + } - lreq->handle = handle; + subreq = sysdb_set_user_attr_send(lreq, lreq->ev, lreq->handle, + lreq->preq->domain, + lreq->preq->pd->user, + lreq->mod_attrs, SYSDB_MOD_REP); + if (!subreq) { + /* cancel transaction */ + talloc_zfree(lreq->handle); + lreq->error = ret; + return prepare_reply(lreq); + } + tevent_req_set_callback(subreq, set_user_attr_req_done, lreq); +} - ret = sysdb_set_user_attr(handle, lreq->preq->domain, - lreq->preq->pd->user, lreq->mod_attrs, - set_user_attr_callback, lreq); - if (ret != EOK) - sysdb_transaction_done(lreq->handle, ret); +static void set_user_attr_req_done(struct tevent_req *subreq) +{ + struct LOCAL_request *lreq = tevent_req_callback_data(subreq, + struct LOCAL_request); + struct tevent_req *req; + int ret; - NEQ_CHECK_OR_JUMP(ret, EOK, ("sysdb_set_user_attr failed.\n"), - lreq->error, ret, done); + ret = sysdb_set_user_attr_recv(subreq); + talloc_zfree(subreq); + + DEBUG(4, ("set_user_attr_callback, status [%d][%s]\n", ret, strerror(ret))); + + if (ret) { + lreq->error = ret; + goto fail; + } + + req = sysdb_transaction_commit_send(lreq, lreq->ev, lreq->handle); + if (!req) { + lreq->error = ENOMEM; + goto fail; + } + tevent_req_set_callback(req, set_user_attr_done, lreq); return; -done: + +fail: + DEBUG(2, ("set_user_attr failed.\n")); + + /* cancel transaction */ + talloc_zfree(lreq->handle); + prepare_reply(lreq); } static void do_successful_login(struct LOCAL_request *lreq) { + struct tevent_req *req; int ret; lreq->mod_attrs = sysdb_new_attrs(lreq); @@ -146,9 +185,12 @@ static void do_successful_login(struct LOCAL_request *lreq) NEQ_CHECK_OR_JUMP(ret, EOK, ("sysdb_attrs_add_long failed.\n"), lreq->error, ret, done); - ret = sysdb_transaction(lreq, lreq->dbctx, set_user_attr_req, lreq); - NEQ_CHECK_OR_JUMP(ret, EOK, ("sysdb_transaction failed.\n"), - lreq->error, ret, done); + req = sysdb_transaction_send(lreq, lreq->ev, lreq->dbctx); + if (!req) { + lreq->error = ENOMEM; + goto done; + } + tevent_req_set_callback(req, set_user_attr_req, lreq); return; @@ -159,6 +201,7 @@ done: static void do_failed_login(struct LOCAL_request *lreq) { + struct tevent_req *req; int ret; int failedLoginAttempts; struct pam_data *pd; @@ -187,9 +230,13 @@ static void do_failed_login(struct LOCAL_request *lreq) NEQ_CHECK_OR_JUMP(ret, EOK, ("sysdb_attrs_add_long failed.\n"), lreq->error, ret, done); - ret = sysdb_transaction(lreq, lreq->dbctx, set_user_attr_req, lreq); - NEQ_CHECK_OR_JUMP(ret, EOK, ("sysdb_transaction failed.\n"), - lreq->error, ret, done); + req = sysdb_transaction_send(lreq, lreq->ev, lreq->dbctx); + if (!req) { + lreq->error = ENOMEM; + goto done; + } + tevent_req_set_callback(req, set_user_attr_req, lreq); + return; done: @@ -217,6 +264,7 @@ static void do_pam_acct_mgmt(struct LOCAL_request *lreq) static void do_pam_chauthtok(struct LOCAL_request *lreq) { + struct tevent_req *req; int ret; char *newauthtok; char *salt; @@ -261,9 +309,13 @@ static void do_pam_chauthtok(struct LOCAL_request *lreq) NEQ_CHECK_OR_JUMP(ret, EOK, ("sysdb_attrs_add_long failed.\n"), lreq->error, ret, done); - ret = sysdb_transaction(lreq, lreq->dbctx, set_user_attr_req, lreq); - NEQ_CHECK_OR_JUMP(ret, EOK, ("sysdb_transaction failed.\n"), - lreq->error, ret, done); + req = sysdb_transaction_send(lreq, lreq->ev, lreq->dbctx); + if (!req) { + lreq->error = ENOMEM; + goto done; + } + tevent_req_set_callback(req, set_user_attr_req, lreq); + return; done: @@ -408,6 +460,7 @@ int LOCAL_pam_handler(struct pam_auth_req *preq) } lreq->dbctx = preq->cctx->rctx->sysdb; + lreq->ev = preq->cctx->ev; lreq->preq = preq; preq->pd->pam_status = PAM_SUCCESS; diff --git a/server/tests/sysdb-tests.c b/server/tests/sysdb-tests.c index bc8949620..ef7145cdd 100644 --- a/server/tests/sysdb-tests.c +++ b/server/tests/sysdb-tests.c @@ -26,7 +26,7 @@ #include #include "util/util.h" #include "confdb/confdb_setup.h" -#include "db/sysdb.h" +#include "db/sysdb_private.h" struct sysdb_test_ctx { struct sysdb_ctx *sysdb; @@ -84,6 +84,23 @@ static int setup_sysdb_tests(struct sysdb_test_ctx **ctx) return ret; } + val[0] = "foo"; + ret = confdb_add_param(test_ctx->confdb, true, "config/domains/LOCAL", "provider", val); + if (ret != EOK) { + fail("Could not initialize domains placeholder"); + talloc_free(test_ctx); + return ret; + } +/* + val[0] = "TRUE"; + ret = confdb_add_param(test_ctx->confdb, true, "config/domains/LOCAL", "legacy", val); + if (ret != EOK) { + fail("Could not initialize LOCAL domain"); + talloc_free(test_ctx); + return ret; + } +*/ +/* val[0] = "TRUE"; ret = confdb_add_param(test_ctx->confdb, true, "config/domains/LOCAL", "magicPrivateGroups", val); if (ret != EOK) { @@ -91,7 +108,7 @@ static int setup_sysdb_tests(struct sysdb_test_ctx **ctx) talloc_free(test_ctx); return ret; } - +*/ val[0] = "3"; ret = confdb_add_param(test_ctx->confdb, true, "config/domains/LOCAL", "enumerate", val); if (ret != EOK) { @@ -121,6 +138,7 @@ static int setup_sysdb_tests(struct sysdb_test_ctx **ctx) } struct test_data { + struct tevent_context *ev; struct sysdb_handle *handle; struct sss_domain_info *domain; struct sysdb_test_ctx *ctx; @@ -130,8 +148,6 @@ struct test_data { uid_t uid; gid_t gid; - sysdb_callback_t next_fn; - bool finished; int error; @@ -166,191 +182,319 @@ static int test_loop(struct test_data *data) return data->error; } -static void test_return(void *pvt, int error, struct ldb_result *ignore) +static void test_req_done(struct tevent_req *req) { - struct test_data *data = talloc_get_type(pvt, struct test_data); - const char *err = "Success"; + struct test_data *data = tevent_req_callback_data(req, struct test_data); + + data->error = sysdb_transaction_commit_recv(req); + data->finished = true; +} + +static void test_return(struct test_data *data, int error) +{ + struct tevent_req *req; - if (error != EOK) err = "Operation failed"; + if (error != EOK) { + goto fail; + } - sysdb_transaction_done(data->handle, error); + req = sysdb_transaction_commit_send(data, data->ev, data->handle); + if (!req) { + error = ENOMEM; + goto fail; + } + tevent_req_set_callback(req, test_req_done, data); + + return; + +fail: + /* free transaction */ + talloc_zfree(data->handle); data->error = error; data->finished = true; } -static void test_add_user(struct sysdb_handle *handle, void *pvt) +static void test_add_user_done(struct tevent_req *subreq); + +static void test_add_user(struct tevent_req *subreq) { - struct test_data *data = talloc_get_type(pvt, struct test_data); - struct sysdb_ctx *ctx; + struct test_data *data = tevent_req_callback_data(subreq, + struct test_data); char *homedir; char *gecos; int ret; + ret = sysdb_transaction_recv(subreq, data, &data->handle); + talloc_zfree(subreq); + if (ret != EOK) { + return test_return(data, ret); + } + homedir = talloc_asprintf(data, "/home/testuser%d", data->uid); gecos = talloc_asprintf(data, "Test User %d", data->uid); - data->handle = handle; - ctx = sysdb_handle_get_ctx(handle); + subreq = sysdb_add_user_send(data, data->ev, data->handle, + data->domain, data->username, + data->uid, data->gid, + gecos, homedir, "/bin/bash", + NULL); + if (!subreq) { + return test_return(data, ENOMEM); + } + tevent_req_set_callback(subreq, test_add_user_done, data); +} + +static void test_add_user_done(struct tevent_req *subreq) +{ + struct test_data *data = tevent_req_callback_data(subreq, struct test_data); + int ret; + + ret = sysdb_add_user_recv(subreq); + talloc_zfree(subreq); - ret = sysdb_add_user(handle, data->domain, - data->username, data->uid, data->gid, - gecos, homedir, "/bin/bash", - data->next_fn, data); - if (ret != EOK) test_return(data, ret, NULL); + return test_return(data, ret); } -static void test_add_legacy_user(struct sysdb_handle *handle, void *pvt) +static void test_store_user_done(struct tevent_req *subreq); + +static void test_store_user(struct tevent_req *req) { - struct test_data *data = talloc_get_type(pvt, struct test_data); - struct sysdb_ctx *ctx; + struct test_data *data = tevent_req_callback_data(req, struct test_data); + struct tevent_req *subreq; char *homedir; char *gecos; int ret; + ret = sysdb_transaction_recv(req, data, &data->handle); + if (ret != EOK) { + return test_return(data, ret); + } + homedir = talloc_asprintf(data, "/home/testuser%d", data->uid); gecos = talloc_asprintf(data, "Test User %d", data->uid); - data->handle = handle; - ctx = sysdb_handle_get_ctx(handle); + subreq = sysdb_store_user_send(data, data->ev, data->handle, + data->domain, data->username, "x", + data->uid, data->gid, + gecos, homedir, "/bin/bash"); + if (!subreq) { + test_return(data, ENOMEM); + return; + } + tevent_req_set_callback(subreq, test_store_user_done, data); +} - ret = sysdb_legacy_store_user(handle, data->domain, data->username, "x", - data->uid, data->gid, gecos, homedir, - "/bin/bash", data->next_fn, data); - if (ret != EOK) test_return(data, ret, NULL); +static void test_store_user_done(struct tevent_req *subreq) +{ + struct test_data *data = tevent_req_callback_data(subreq, struct test_data); + int ret; + + ret = sysdb_store_user_recv(subreq); + talloc_zfree(subreq); + + return test_return(data, ret); } -static void test_remove_user(struct sysdb_handle *handle, void *pvt) +static void test_remove_user_done(struct tevent_req *subreq); + +static void test_remove_user(struct tevent_req *req) { - struct test_data *data = talloc_get_type(pvt, struct test_data); - struct sysdb_ctx *ctx; + struct test_data *data = tevent_req_callback_data(req, struct test_data); struct ldb_dn *user_dn; + struct tevent_req *subreq; int ret; - data->handle = handle; - ctx = sysdb_handle_get_ctx(handle); + ret = sysdb_transaction_recv(req, data, &data->handle); + if (ret != EOK) { + return test_return(data, ret); + } - user_dn = sysdb_user_dn(ctx, data, "LOCAL", data->username); - if (!user_dn) return test_return(data, ENOMEM, NULL); + user_dn = sysdb_user_dn(data->ctx->sysdb, data, "LOCAL", data->username); + if (!user_dn) return test_return(data, ENOMEM); - ret = sysdb_delete_entry(handle, user_dn, data->next_fn, data); - if (ret != EOK) test_return(data, ret, NULL); + subreq = sysdb_delete_entry_send(data, data->ev, data->handle, user_dn); + if (!subreq) return test_return(data, ENOMEM); + + tevent_req_set_callback(subreq, test_remove_user_done, data); } -static void test_remove_user_by_uid(struct sysdb_handle *handle, void *pvt) +static void test_remove_user_done(struct tevent_req *subreq) { - struct test_data *data = talloc_get_type(pvt, struct test_data); - struct sysdb_ctx *ctx; + struct test_data *data = tevent_req_callback_data(subreq, + struct test_data); int ret; - data->handle = handle; - ctx = sysdb_handle_get_ctx(handle); + ret = sysdb_delete_entry_recv(subreq); + talloc_zfree(subreq); - ret = sysdb_delete_user_by_uid(handle, data->domain, data->uid, - data->next_fn, data); - if (ret != EOK) test_return(data, ret, NULL); + return test_return(data, ret); } -static void test_add_group(struct sysdb_handle *handle, void *pvt) +static void test_remove_user_by_uid_done(struct tevent_req *subreq); + +static void test_remove_user_by_uid(struct tevent_req *req) { - struct test_data *data = talloc_get_type(pvt, struct test_data); - struct sysdb_ctx *ctx; + struct test_data *data = tevent_req_callback_data(req, struct test_data); + struct tevent_req *subreq; int ret; - data->handle = handle; - ctx = sysdb_handle_get_ctx(handle); - - ret = sysdb_add_group(handle, data->domain, - data->groupname, data->gid, - data->next_fn, data); + ret = sysdb_transaction_recv(req, data, &data->handle); if (ret != EOK) { - test_return(data, ret, NULL); + return test_return(data, ret); } + + subreq = sysdb_delete_user_by_uid_send(data, + data->ev, data->handle, + data->domain, data->uid); + if (!subreq) return test_return(data, ENOMEM); + + tevent_req_set_callback(subreq, test_remove_user_by_uid_done, data); } -static void test_add_legacy_group(struct sysdb_handle *handle, void *pvt) +static void test_remove_user_by_uid_done(struct tevent_req *subreq) { - struct test_data *data = talloc_get_type(pvt, struct test_data); - struct sysdb_ctx *ctx; + struct test_data *data = tevent_req_callback_data(subreq, + struct test_data); int ret; - data->handle = handle; - ctx = sysdb_handle_get_ctx(handle); + ret = sysdb_delete_user_by_uid_recv(subreq); + talloc_zfree(subreq); + + return test_return(data, ret); +} + +static void test_add_group_done(struct tevent_req *subreq); + +static void test_add_group(struct tevent_req *req) +{ + struct test_data *data = tevent_req_callback_data(req, + struct test_data); + struct tevent_req *subreq; + int ret; - ret = sysdb_legacy_store_group(handle, data->domain, - data->groupname, - data->gid, NULL, - data->next_fn, data); + ret = sysdb_transaction_recv(req, data, &data->handle); if (ret != EOK) { - test_return(data, ret, NULL); + return test_return(data, ret); } + + subreq = sysdb_add_group_send(data, data->ev, data->handle, + data->domain, data->groupname, + data->gid, NULL); + if (!subreq) { + test_return(data, ret); + } + tevent_req_set_callback(subreq, test_add_group_done, data); } -static void test_remove_group(struct sysdb_handle *handle, void *pvt) +static void test_add_group_done(struct tevent_req *subreq) { - struct test_data *data = talloc_get_type(pvt, struct test_data); - struct sysdb_ctx *ctx; - struct ldb_dn *group_dn; + struct test_data *data = tevent_req_callback_data(subreq, struct test_data); int ret; - data->handle = handle; - ctx = sysdb_handle_get_ctx(handle); - - group_dn = sysdb_group_dn(ctx, data, "LOCAL", data->groupname); - if (!group_dn) return test_return(data, ENOMEM, NULL); + ret = sysdb_add_group_recv(subreq); + talloc_zfree(subreq); - ret = sysdb_delete_entry(handle, group_dn, data->next_fn, data); - if (ret != EOK) test_return(data, ret, NULL); + return test_return(data, ret); } -static void test_remove_group_by_gid(struct sysdb_handle *handle, void *pvt) +static void test_store_group_done(struct tevent_req *subreq); + +static void test_store_group(struct tevent_req *req) { - struct test_data *data = talloc_get_type(pvt, struct test_data); - struct sysdb_ctx *ctx; + struct test_data *data = tevent_req_callback_data(req, struct test_data); + struct tevent_req *subreq; int ret; - data->handle = handle; - ctx = sysdb_handle_get_ctx(handle); + ret = sysdb_transaction_recv(req, data, &data->handle); + if (ret != EOK) { + return test_return(data, ret); + } - ret = sysdb_delete_group_by_gid(handle, data->domain, data->gid, - data->next_fn, data); - if (ret != EOK) test_return(data, ret, NULL); + subreq = sysdb_store_group_send(data, data->ev, data->handle, + data->domain, data->groupname, + data->gid, NULL); + if (!subreq) { + test_return(data, ret); + } + tevent_req_set_callback(subreq, test_store_group_done, data); } -static void test_add_legacy_group_member(struct sysdb_handle *handle, void *pvt) +static void test_store_group_done(struct tevent_req *subreq) { - struct test_data *data = talloc_get_type(pvt, struct test_data); - struct sysdb_ctx *ctx; + struct test_data *data = tevent_req_callback_data(subreq, struct test_data); int ret; - data->handle = handle; - ctx = sysdb_handle_get_ctx(handle); + ret = sysdb_store_group_recv(subreq); + talloc_zfree(subreq); + + return test_return(data, ret); +} - ret = sysdb_legacy_add_group_member(handle, data->domain, - data->groupname, - data->username, - data->next_fn, data); +static void test_remove_group_done(struct tevent_req *subreq); + +static void test_remove_group(struct tevent_req *req) +{ + struct test_data *data = tevent_req_callback_data(req, struct test_data); + struct tevent_req *subreq; + struct ldb_dn *group_dn; + int ret; + + ret = sysdb_transaction_recv(req, data, &data->handle); if (ret != EOK) { - test_return(data, ret, NULL); + return test_return(data, ret); } + + group_dn = sysdb_group_dn(data->ctx->sysdb, data, "LOCAL", data->groupname); + if (!group_dn) return test_return(data, ENOMEM); + + subreq = sysdb_delete_entry_send(data, data->ev, data->handle, group_dn); + if (!subreq) return test_return(data, ENOMEM); + + tevent_req_set_callback(subreq, test_remove_group_done, data); } -static void test_remove_legacy_group_member(struct sysdb_handle *handle, void *pvt) +static void test_remove_group_done(struct tevent_req *subreq) { - struct test_data *data = talloc_get_type(pvt, struct test_data); - struct sysdb_ctx *ctx; + struct test_data *data = tevent_req_callback_data(subreq, + struct test_data); int ret; - data->handle = handle; - ctx = sysdb_handle_get_ctx(handle); + ret = sysdb_delete_entry_recv(subreq); + talloc_zfree(subreq); + + return test_return(data, ret); +} - ret = sysdb_legacy_remove_group_member(handle, data->domain, - data->groupname, - data->username, - data->next_fn, data); +static void test_remove_group_by_gid_done(struct tevent_req *subreq); +static void test_remove_group_by_gid(struct tevent_req *req) +{ + struct test_data *data = tevent_req_callback_data(req, struct test_data); + struct tevent_req *subreq; + int ret; + + ret = sysdb_transaction_recv(req, data, &data->handle); if (ret != EOK) { - test_return(data, ret, NULL); + return test_return(data, ret); } + + subreq = sysdb_delete_group_by_gid_send(data, data->ev, data->handle, + data->domain, data->gid); + if (!subreq) return test_return(data, ENOMEM); + + tevent_req_set_callback(subreq, test_remove_group_by_gid_done, data); +} + +static void test_remove_group_by_gid_done(struct tevent_req *subreq) +{ + struct test_data *data = tevent_req_callback_data(subreq, + struct test_data); + int ret; + + ret = sysdb_delete_group_by_gid_recv(subreq); + talloc_zfree(subreq); + + return test_return(data, ret); } static void test_getpwent(void *pvt, int error, struct ldb_result *res) @@ -456,7 +600,8 @@ static void test_getpwuid(void *pvt, int error, struct ldb_result *res) static void test_enumgrent(void *pvt, int error, struct ldb_result *res) { struct test_data *data = talloc_get_type(pvt, struct test_data); - const int expected = 30; /* 15 groups + 15 users (we're MPG) */ +/* const int expected = 30; /* 15 groups + 15 users (we're MPG) */ + const int expected = 15; data->finished = true; @@ -493,20 +638,36 @@ static void test_enumpwent(void *pvt, int error, struct ldb_result *res) data->error = EOK; } -static void test_set_user_attr(struct sysdb_handle *handle, void *pvt) +static void test_set_user_attr_done(struct tevent_req *subreq); +static void test_set_user_attr(struct tevent_req *req) { - struct test_data *data = talloc_get_type(pvt, struct test_data); + struct test_data *data = tevent_req_callback_data(req, struct test_data); + struct tevent_req *subreq; int ret; - data->handle = handle; + ret = sysdb_transaction_recv(req, data, &data->handle); + if (ret != EOK) { + return test_return(data, ret); + } - ret = sysdb_set_user_attr(handle, - data->domain, - data->username, - data->attrs, - data->next_fn, - data); - if (ret != EOK) test_return(data, ret, NULL); + subreq = sysdb_set_user_attr_send(data, data->ev, data->handle, + data->domain, data->username, + data->attrs, SYSDB_MOD_REP); + if (!subreq) return test_return(data, ENOMEM); + + tevent_req_set_callback(subreq, test_set_user_attr_done, data); +} + +static void test_set_user_attr_done(struct tevent_req *subreq) +{ + struct test_data *data = tevent_req_callback_data(subreq, + struct test_data); + int ret; + + ret = sysdb_set_user_attr_recv(subreq); + talloc_zfree(subreq); + + return test_return(data, ret); } static void test_get_user_attr(void *pvt, int error, struct ldb_result *res) @@ -534,248 +695,87 @@ static void test_get_user_attr(void *pvt, int error, struct ldb_result *res) } } -static void test_add_group_member(struct sysdb_handle *handle, void *pvt) -{ - struct test_data *data = talloc_get_type(pvt, struct test_data); - struct ldb_dn *user_dn; - struct ldb_dn *group_dn; - const char *username; - int ret; - TALLOC_CTX *tmp_ctx; - - tmp_ctx = talloc_new(NULL); - if (!tmp_ctx) { - test_return(data, ENOMEM, NULL); - } +static void test_add_group_member_done(struct tevent_req *subreq); - username = talloc_asprintf(tmp_ctx, "testuser%d", data->uid); - if (username == NULL) { - test_return(data, ENOMEM, NULL); - } - user_dn = sysdb_user_dn(data->ctx->sysdb, - data, - data->domain->name, - username); - if (user_dn == NULL) { - test_return(data, ENOMEM, NULL); - } - group_dn = sysdb_group_dn(data->ctx->sysdb, - data, - data->domain->name, - data->groupname); - if (group_dn == NULL) { - test_return(data, ENOMEM, NULL); - } - - data->handle = handle; - - ret = sysdb_add_group_member(handle, - user_dn, - group_dn, - test_return, - data); - if (ret != EOK) { - talloc_free(tmp_ctx); - test_return(data, ret, NULL); - } - talloc_free(tmp_ctx); -} - -static void test_remove_group_member(struct sysdb_handle *handle, void *pvt) +static void test_add_group_member(struct tevent_req *req) { - struct test_data *data = talloc_get_type(pvt, struct test_data); - struct ldb_dn *user_dn; - struct ldb_dn *group_dn; + struct test_data *data = tevent_req_callback_data(req, struct test_data); + struct tevent_req *subreq; const char *username; int ret; - TALLOC_CTX *tmp_ctx; - tmp_ctx = talloc_new(NULL); - if (!tmp_ctx) { - test_return(data, ENOMEM, NULL); - } - - username = talloc_asprintf(tmp_ctx, "testuser%d", data->uid); - if (username == NULL) { - test_return(data, ENOMEM, NULL); - } - user_dn = sysdb_user_dn(data->ctx->sysdb, - data, - data->domain->name, - username); - if (user_dn == NULL) { - test_return(data, ENOMEM, NULL); - } - group_dn = sysdb_group_dn(data->ctx->sysdb, - data, - data->domain->name, - username); - if (group_dn == NULL) { - test_return(data, ENOMEM, NULL); - } - - data->handle = handle; - - ret = sysdb_remove_group_member(handle, - user_dn, - group_dn, - test_return, - data); + ret = sysdb_transaction_recv(req, data, &data->handle); if (ret != EOK) { - talloc_free(tmp_ctx); - test_return(data, ret, NULL); + return test_return(data, ret); } - talloc_free(tmp_ctx); -} - -START_TEST (test_sysdb_store_legacy_user) -{ - struct sysdb_test_ctx *test_ctx; - struct test_data *data; - int ret; - - /* Setup */ - ret = setup_sysdb_tests(&test_ctx); - if (ret != EOK) { - fail("Could not set up the test"); - return; + username = talloc_asprintf(data, "testuser%d", data->uid); + if (username == NULL) { + test_return(data, ENOMEM); } - data = talloc_zero(test_ctx, struct test_data); - data->ctx = test_ctx; - data->uid = _i; - data->gid = _i; - data->next_fn = test_return; - data->username = talloc_asprintf(data, "testuser%d", _i); - data->domain = get_local_domain(test_ctx->domains); - - ret = sysdb_transaction(data, test_ctx->sysdb, - test_add_legacy_user, data); - if (ret == EOK) { - ret = test_loop(data); + subreq = sysdb_add_group_member_send(data, data->ev, + data->handle, data->domain, + data->groupname, username); + if (!subreq) { + test_return(data, ENOMEM); } - fail_if(ret != EOK, "Could not store legacy user %s", data->username); - talloc_free(test_ctx); + tevent_req_set_callback(subreq, test_add_group_member_done, data); } -END_TEST -START_TEST (test_sysdb_store_legacy_group) +static void test_add_group_member_done(struct tevent_req *subreq) { - struct sysdb_test_ctx *test_ctx; - struct test_data *data; - int ret; + struct test_data *data = tevent_req_callback_data(subreq, + struct test_data); + int ret = sysdb_add_group_member_recv(subreq); - /* Setup */ - ret = setup_sysdb_tests(&test_ctx); - if (ret != EOK) { - fail("Could not set up the test"); - return; - } - - data = talloc_zero(test_ctx, struct test_data); - data->ctx = test_ctx; - data->gid = _i; - data->next_fn = test_return; - data->groupname = talloc_asprintf(data, "testgroup%d", _i); - data->domain = get_local_domain(test_ctx->domains); - - ret = sysdb_transaction(data, test_ctx->sysdb, - test_add_legacy_group, data); - if (ret == EOK) { - ret = test_loop(data); - } - - fail_if(ret != EOK, "Could not store POSIX group #%d", _i); - talloc_free(test_ctx); + test_return(data, ret); } -END_TEST -START_TEST (test_sysdb_get_local_group) +static void test_remove_group_member_done(struct tevent_req *subreq); + +static void test_remove_group_member(struct tevent_req *req) { + struct test_data *data = tevent_req_callback_data(req, struct test_data); + struct tevent_req *subreq; + const char *username; int ret; - struct sysdb_test_ctx *test_ctx; - struct ldb_result *res; - struct ldb_dn *base_group_dn; - const char *attrs[] = { SYSDB_NAME, SYSDB_GIDNUM, NULL }; - const char *name; - char *expected_group; - gid_t test_gid; - /* Setup */ - ret = setup_sysdb_tests(&test_ctx); + ret = sysdb_transaction_recv(req, data, &data->handle); if (ret != EOK) { - fail("Could not set up the test"); - return; - } - - expected_group = talloc_asprintf(test_ctx, "testgroup%d", _i); - fail_if(expected_group == NULL, "Could not allocate expected_group"); - - /* Set up the base DN */ - base_group_dn = ldb_dn_new_fmt(test_ctx, sysdb_ctx_get_ldb(test_ctx->sysdb), - SYSDB_TMPL_GROUP_BASE, "LOCAL"); - if (base_group_dn == NULL) { - fail("Could not create basedn for LOCAL groups"); - return; + return test_return(data, ret); } - /* Look up the group by gid */ - ret = ldb_search(sysdb_ctx_get_ldb(test_ctx->sysdb), test_ctx, - &res, base_group_dn, LDB_SCOPE_ONELEVEL, - attrs, SYSDB_GRGID_FILTER, (unsigned long)_i); - if (ret != LDB_SUCCESS) { - fail("Could not locate group %d", _i); - return; - } - - if (res->count < 1) { - fail("Local group %d doesn't exist.\n", _i); - return; - } - else if (res->count > 1) { - fail("More than one group shared gid %d", _i); - return; + username = talloc_asprintf(data, "testuser%d", data->uid); + if (username == NULL) { + test_return(data, ENOMEM); } - name = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_NAME, NULL); - fail_unless(strcmp(name, expected_group) == 0, - "Returned group name was %s, expecting %s", - name, expected_group); - talloc_free(res); - - /* Look up the group by name */ - ret = ldb_search(sysdb_ctx_get_ldb(test_ctx->sysdb), test_ctx, - &res, base_group_dn, LDB_SCOPE_ONELEVEL, - attrs, SYSDB_GRNAM_FILTER, expected_group); - if (ret != LDB_SUCCESS) { - fail("Could not locate group %d", _i); - return; + subreq = sysdb_remove_group_member_send(data, data->ev, + data->handle, data->domain, + data->groupname, username); + if (!subreq) { + test_return(data, ENOMEM); } - if (res->count < 1) { - fail("Local group %s doesn't exist.", expected_group); - return; - } - else if (res->count > 1) { - fail("More than one group shared name %s", expected_group); - return; - } + tevent_req_set_callback(subreq, test_remove_group_member_done, data); +} - test_gid = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_GIDNUM, 0); - fail_unless(test_gid == _i, - "Returned group id was %lu, expecting %lu", - test_gid, _i); +static void test_remove_group_member_done(struct tevent_req *subreq) +{ + struct test_data *data = tevent_req_callback_data(subreq, + struct test_data); + int ret = sysdb_remove_group_member_recv(subreq); - talloc_free(test_ctx); + test_return(data, ret); } -END_TEST -START_TEST (test_sysdb_add_legacy_group_member) +START_TEST (test_sysdb_store_user) { struct sysdb_test_ctx *test_ctx; struct test_data *data; + struct tevent_req *req; int ret; /* Setup */ @@ -787,191 +787,33 @@ START_TEST (test_sysdb_add_legacy_group_member) data = talloc_zero(test_ctx, struct test_data); data->ctx = test_ctx; - data->next_fn = test_return; - data->groupname = talloc_asprintf(data, "testgroup%d", _i); + data->ev = test_ctx->ev; + data->uid = _i; + data->gid = _i; data->username = talloc_asprintf(data, "testuser%d", _i); data->domain = get_local_domain(test_ctx->domains); - ret = sysdb_transaction(data, test_ctx->sysdb, - test_add_legacy_group_member, data); - if (ret == EOK) { - ret = test_loop(data); - } - - fail_if(ret != EOK, "Failed to add user %s to group %s.", - data->username, data->groupname); - talloc_free(test_ctx); -} -END_TEST - -START_TEST (test_sysdb_verify_legacy_group_members) -{ - char found_group; - int ret, i; - struct sysdb_test_ctx *test_ctx; - char *username; - char *groupname; - struct ldb_dn *group_dn; - struct ldb_dn *user_dn; - struct ldb_result *res; - struct ldb_message_element *el; - const char *group_attrs[] = { SYSDB_LEGACY_MEMBER, NULL }; - - /* Setup */ - ret = setup_sysdb_tests(&test_ctx); - if (ret != EOK) { - fail("Could not set up the test"); - return; - } - - username = talloc_asprintf(test_ctx, "testuser%d", _i); - fail_if (username == NULL, "Could not allocate username"); - - user_dn = sysdb_user_dn(test_ctx->sysdb, test_ctx, "LOCAL", username); - fail_if(user_dn == NULL, "Could not create user_dn object"); - - groupname = talloc_asprintf(test_ctx, "testgroup%d", _i); - fail_if (groupname == NULL, "Could not allocate groupname"); - - group_dn = sysdb_group_dn(test_ctx->sysdb, test_ctx, "LOCAL", groupname); - fail_if(group_dn == NULL, "Could not create group_dn object"); - - /* Look up the group by name */ - ret = ldb_search(sysdb_ctx_get_ldb(test_ctx->sysdb), test_ctx, - &res, group_dn, LDB_SCOPE_BASE, - group_attrs, SYSDB_GRNAM_FILTER, groupname); - if (ret != LDB_SUCCESS) { - fail("Could not locate group %d", _i); - return; - } - - if (res->count < 1) { - fail("Local group %s doesn't exist.", groupname); - return; - } - else if (res->count > 1) { - fail("More than one group shared name testgroup"); - return; - } - - /* Check the members for the requested user */ - found_group = i = 0; - el = ldb_msg_find_element(res->msgs[0], SYSDB_LEGACY_MEMBER); - if (el && el->num_values > 0) { - while (i < el->num_values && !found_group) { - struct ldb_val v = el->values[i]; - char *value = talloc_strndup(test_ctx, (char *)v.data, v.length); - if (strcmp(value, username) == 0) { - found_group = 1; - } - talloc_free(value); - i++; - } - } - else { - fail("No member attributes for group testgroup"); + req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb); + if (!req) { + ret = ENOMEM; } - fail_unless(found_group == 1, "testgroup does not have %s as a member", - username); -} -END_TEST - -#if 0 -START_TEST (test_sysdb_add_invalid_member) -{ - char found_group; - int ret, i; - struct sysdb_test_ctx *test_ctx; - char *username; - char *member; - char *group; - char *group_name; - struct ldb_dn *group_dn; - struct ldb_result *res; - struct ldb_message_element *el; - const char *group_attrs[] = { SYSDB_MEMBER, NULL }; - - /* Setup */ - ret = setup_sysdb_tests(&test_ctx); - if (ret != EOK) { - fail("Could not set up the test"); - return; - } - - group_name = talloc_asprintf(test_ctx, "testgroup%d", _i); - group = talloc_asprintf(test_ctx, - SYSDB_NAME"=%s,"SYSDB_TMPL_GROUP_BASE, - group_name, "LOCAL"); - fail_if(group == NULL, "Could not allocate group dn"); - - /* Add nonexistent user to test group */ - username = talloc_asprintf(test_ctx, "nonexistentuser%d", _i); - ret = sysdb_add_user_to_group(test_ctx, - test_ctx->sysdb, - "LOCAL", - group, - username); - fail_if(ret == EOK, - "Unexpected success adding user %s to group testgroup." - "Error was: %d", username, ret); - -/* Verify that the member wasn't added anyway */ - - member = talloc_asprintf(test_ctx, - SYSDB_NAME"=%s,"SYSDB_TMPL_USER_BASE, - username, "LOCAL"); - fail_if(member == NULL, "Could not allocate member dn"); - - group_dn = ldb_dn_new_fmt(test_ctx, sysdb_ctx_get_ldb(test_ctx->sysdb), group); - fail_if(group_dn == NULL, "Could not create group_dn object"); - - /* Look up the group by name */ - ret = ldb_search(sysdb_ctx_get_ldb(test_ctx->sysdb), test_ctx, - &res, group_dn, LDB_SCOPE_BASE, - group_attrs, SYSDB_GRNAM_FILTER, group_name); - if (ret != LDB_SUCCESS) { - fail("Could not locate group %d", _i); - return; - } - - if (res->count < 1) { - fail("Local group %s doesn't exist.", group_name); - return; - } - else if (res->count > 1) { - fail("More than one group shared name %s", group_name); - return; - } + if (ret == EOK) { + tevent_req_set_callback(req, test_store_user, data); - /* Check the members for the requested user */ - found_group = i = 0; - el = ldb_msg_find_element(res->msgs[0], SYSDB_MEMBER); - if (el && el->num_values > 0) { - while (i < el->num_values && !found_group) { - struct ldb_val v = el->values[i]; - char *value = talloc_strndup(test_ctx, (char *)v.data, v.length); - if (strcmp(value, member) == 0) { - found_group = 1; - } - talloc_free(value); - i++; - } - } - else { - fail("No member attributes for group testgroup"); + ret = test_loop(data); } - fail_if(found_group == 1, "testgroup has added %s as a member", username); + fail_if(ret != EOK, "Could not store legacy user %s", data->username); talloc_free(test_ctx); } END_TEST -#endif -START_TEST (test_sysdb_remove_legacy_group_member) +START_TEST (test_sysdb_store_group) { struct sysdb_test_ctx *test_ctx; struct test_data *data; + struct tevent_req *req; int ret; /* Setup */ @@ -983,19 +825,23 @@ START_TEST (test_sysdb_remove_legacy_group_member) data = talloc_zero(test_ctx, struct test_data); data->ctx = test_ctx; - data->next_fn = test_return; + data->ev = test_ctx->ev; + data->gid = _i; data->groupname = talloc_asprintf(data, "testgroup%d", _i); - data->username = talloc_asprintf(data, "testuser%d", _i); data->domain = get_local_domain(test_ctx->domains); - ret = sysdb_transaction(data, test_ctx->sysdb, - test_remove_legacy_group_member, data); + req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb); + if (!req) { + ret = ENOMEM; + } + if (ret == EOK) { + tevent_req_set_callback(req, test_store_group, data); + ret = test_loop(data); } - fail_if(ret != EOK, "Failed to remove user %s to group %s.", - data->username, data->groupname, ret); + fail_if(ret != EOK, "Could not store POSIX group #%d", _i); talloc_free(test_ctx); } END_TEST @@ -1004,6 +850,7 @@ START_TEST (test_sysdb_remove_local_user) { struct sysdb_test_ctx *test_ctx; struct test_data *data; + struct tevent_req *req; int ret; /* Setup */ @@ -1015,12 +862,17 @@ START_TEST (test_sysdb_remove_local_user) data = talloc_zero(test_ctx, struct test_data); data->ctx = test_ctx; - data->next_fn = test_return; + data->ev = test_ctx->ev; data->username = talloc_asprintf(data, "testuser%d", _i); - ret = sysdb_transaction(data, test_ctx->sysdb, - test_remove_user, data); + req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb); + if (!req) { + ret = ENOMEM; + } + if (ret == EOK) { + tevent_req_set_callback(req, test_remove_user, data); + ret = test_loop(data); } @@ -1033,6 +885,7 @@ START_TEST (test_sysdb_remove_local_user_by_uid) { struct sysdb_test_ctx *test_ctx; struct test_data *data; + struct tevent_req *req; int ret; /* Setup */ @@ -1044,13 +897,18 @@ START_TEST (test_sysdb_remove_local_user_by_uid) data = talloc_zero(test_ctx, struct test_data); data->ctx = test_ctx; - data->next_fn = test_return; + data->ev = test_ctx->ev; data->uid = _i; data->domain = get_local_domain(test_ctx->domains); - ret = sysdb_transaction(data, test_ctx->sysdb, - test_remove_user_by_uid, data); + req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb); + if (!req) { + ret = ENOMEM; + } + if (ret == EOK) { + tevent_req_set_callback(req, test_remove_user_by_uid, data); + ret = test_loop(data); } @@ -1063,6 +921,7 @@ START_TEST (test_sysdb_remove_local_group) { struct sysdb_test_ctx *test_ctx; struct test_data *data; + struct tevent_req *req; int ret; /* Setup */ @@ -1074,12 +933,17 @@ START_TEST (test_sysdb_remove_local_group) data = talloc_zero(test_ctx, struct test_data); data->ctx = test_ctx; - data->next_fn = test_return; + data->ev = test_ctx->ev; data->groupname = talloc_asprintf(data, "testgroup%d", _i); - ret = sysdb_transaction(data, test_ctx->sysdb, - test_remove_group, data); + req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb); + if (!req) { + ret = ENOMEM; + } + if (ret == EOK) { + tevent_req_set_callback(req, test_remove_group, data); + ret = test_loop(data); } @@ -1092,6 +956,7 @@ START_TEST (test_sysdb_remove_local_group_by_gid) { struct sysdb_test_ctx *test_ctx; struct test_data *data; + struct tevent_req *req; int ret; /* Setup */ @@ -1103,13 +968,18 @@ START_TEST (test_sysdb_remove_local_group_by_gid) data = talloc_zero(test_ctx, struct test_data); data->ctx = test_ctx; - data->next_fn = test_return; + data->ev = test_ctx->ev; data->gid = _i; data->domain = get_local_domain(test_ctx->domains); - ret = sysdb_transaction(data, test_ctx->sysdb, - test_remove_group_by_gid, data); + req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb); + if (!req) { + ret = ENOMEM; + } + if (ret == EOK) { + tevent_req_set_callback(req, test_remove_group_by_gid, data); + ret = test_loop(data); } @@ -1122,6 +992,7 @@ START_TEST (test_sysdb_add_user) { struct sysdb_test_ctx *test_ctx; struct test_data *data; + struct tevent_req *subreq; int ret; /* Setup */ @@ -1133,16 +1004,20 @@ START_TEST (test_sysdb_add_user) data = talloc_zero(test_ctx, struct test_data); data->ctx = test_ctx; - + data->ev = test_ctx->ev; data->uid = _i; data->gid = _i; - data->next_fn = test_return; data->username = talloc_asprintf(data, "testuser%d", _i); data->domain = get_local_domain(test_ctx->domains); - ret = sysdb_transaction(data, test_ctx->sysdb, - test_add_user, data); + subreq = sysdb_transaction_send(data, data->ev, test_ctx->sysdb); + if (!subreq) { + ret = ENOMEM; + } + if (ret == EOK) { + tevent_req_set_callback(subreq, test_add_user, data); + ret = test_loop(data); } @@ -1155,6 +1030,7 @@ START_TEST (test_sysdb_add_group) { struct sysdb_test_ctx *test_ctx; struct test_data *data; + struct tevent_req *subreq; int ret; /* Setup */ @@ -1166,16 +1042,20 @@ START_TEST (test_sysdb_add_group) data = talloc_zero(test_ctx, struct test_data); data->ctx = test_ctx; - + data->ev = test_ctx->ev; data->uid = _i; data->gid = _i; - data->next_fn = test_return; data->groupname = talloc_asprintf(data, "testgroup%d", _i); data->domain = get_local_domain(test_ctx->domains); - ret = sysdb_transaction(data, test_ctx->sysdb, - test_add_group, data); + subreq = sysdb_transaction_send(data, data->ev, test_ctx->sysdb); + if (!subreq) { + ret = ENOMEM; + } + if (ret == EOK) { + tevent_req_set_callback(subreq, test_add_group, data); + ret = test_loop(data); } @@ -1199,7 +1079,6 @@ START_TEST (test_sysdb_getpwnam) data = talloc_zero(test_ctx, struct test_data); data->ctx = test_ctx; - data->next_fn = test_getpwent; data->username = talloc_asprintf(data, "testuser%d", _i); data->domain = get_local_domain(test_ctx->domains); @@ -1207,18 +1086,20 @@ START_TEST (test_sysdb_getpwnam) test_ctx->sysdb, data->domain, data->username, - data->next_fn, + test_getpwent, data); if (ret == EOK) { ret = test_loop(data); } - fail_unless(ret == EOK, - "sysdb_getpwnam failed for username %d (%s)", - data->username, ret, strerror(ret)); + if (ret) { + fail("sysdb_getpwnam failed for username %s (%d: %s)", + data->username, ret, strerror(ret)); + goto done; + } fail_unless(data->uid == _i, "Did not find the expected UID"); - +done: talloc_free(test_ctx); } END_TEST @@ -1238,7 +1119,6 @@ START_TEST (test_sysdb_getgrnam) data = talloc_zero(test_ctx, struct test_data); data->ctx = test_ctx; - data->next_fn = test_getgrent; data->groupname = talloc_asprintf(data, "testgroup%d", _i); data->domain = get_local_domain(test_ctx->domains); @@ -1246,19 +1126,21 @@ START_TEST (test_sysdb_getgrnam) test_ctx->sysdb, data->domain, data->groupname, - data->next_fn, + test_getgrent, data); if (ret == EOK) { ret = test_loop(data); } - fail_unless(ret == EOK, - "sysdb_getgrnam failed for groupname %s (%d: %s)", - data->groupname, ret, strerror(ret)); + if (ret) { + fail("sysdb_getgrnam failed for groupname %s (%d: %s)", + data->groupname, ret, strerror(ret)); + goto done; + } fail_unless(data->gid == _i, "Did not find the expected GID (found %d expected %d)", data->gid, _i); - +done: talloc_free(test_ctx); } END_TEST @@ -1285,7 +1167,6 @@ START_TEST (test_sysdb_getgrgid) data = talloc_zero(test_ctx, struct test_data); data->ctx = test_ctx; - data->next_fn = test_getgrgid; data->gid = _i; data->domain = get_local_domain(test_ctx->domains); @@ -1293,19 +1174,21 @@ START_TEST (test_sysdb_getgrgid) test_ctx->sysdb, data->domain, data->gid, - data->next_fn, + test_getgrgid, data); if (ret == EOK) { ret = test_loop(data); } - fail_unless(ret == EOK, - "sysdb_getgrgid failed for gid %d (%d: %s)", - data->gid, ret, strerror(ret)); + if (ret) { + fail("sysdb_getgrgid failed for gid %d (%d: %s)", + data->gid, ret, strerror(ret)); + goto done; + } fail_unless(strcmp(data->groupname, groupname) == 0, "Did not find the expected groupname (found %s expected %s)", data->groupname, groupname); - +done: talloc_free(test_ctx); } END_TEST @@ -1332,7 +1215,6 @@ START_TEST (test_sysdb_getpwuid) data = talloc_zero(test_ctx, struct test_data); data->ctx = test_ctx; - data->next_fn = test_getpwuid; data->uid = _i; data->domain = get_local_domain(test_ctx->domains); @@ -1340,19 +1222,22 @@ START_TEST (test_sysdb_getpwuid) test_ctx->sysdb, data->domain, data->uid, - data->next_fn, + test_getpwuid, data); if (ret == EOK) { ret = test_loop(data); } - fail_unless(ret == EOK, - "sysdb_getpwuid failed for uid %d (%d: %s)", - data->uid, ret, strerror(ret)); + if (ret) { + fail("sysdb_getpwuid failed for uid %d (%d: %s)", + data->uid, ret, strerror(ret)); + goto done; + } + fail_unless(strcmp(data->username, username) == 0, "Did not find the expected username (found %s expected %s)", data->username, username); - +done: talloc_free(test_ctx); } END_TEST @@ -1372,13 +1257,12 @@ START_TEST (test_sysdb_enumgrent) data = talloc_zero(test_ctx, struct test_data); data->ctx = test_ctx; - data->next_fn = test_enumgrent; data->domain = get_local_domain(test_ctx->domains); ret = sysdb_enumgrent(test_ctx, test_ctx->sysdb, data->domain, - data->next_fn, + test_enumgrent, data); if (ret == EOK) { ret = test_loop(data); @@ -1407,14 +1291,13 @@ START_TEST (test_sysdb_enumpwent) data = talloc_zero(test_ctx, struct test_data); data->ctx = test_ctx; - data->next_fn = test_enumpwent; data->domain = get_local_domain(test_ctx->domains); ret = sysdb_enumpwent(test_ctx, test_ctx->sysdb, data->domain, NULL, - data->next_fn, + test_enumpwent, data); if (ret == EOK) { ret = test_loop(data); @@ -1433,6 +1316,7 @@ START_TEST (test_sysdb_set_user_attr) { struct sysdb_test_ctx *test_ctx; struct test_data *data; + struct tevent_req *req; int ret; /* Setup */ @@ -1444,9 +1328,9 @@ START_TEST (test_sysdb_set_user_attr) data = talloc_zero(test_ctx, struct test_data); data->ctx = test_ctx; + data->ev = test_ctx->ev; data->username = talloc_asprintf(data, "testuser%d", _i); data->domain = get_local_domain(test_ctx->domains); - data->next_fn = test_return; data->attrs = sysdb_new_attrs(test_ctx); if (ret != EOK) { @@ -1462,9 +1346,14 @@ START_TEST (test_sysdb_set_user_attr) return; } - ret = sysdb_transaction(data, test_ctx->sysdb, - test_set_user_attr, data); + req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb); + if (!req) { + ret = ENOMEM; + } + if (ret == EOK) { + tevent_req_set_callback(req, test_set_user_attr, data); + ret = test_loop(data); } @@ -1492,24 +1381,26 @@ START_TEST (test_sysdb_get_user_attr) data->ctx = test_ctx; data->username = talloc_asprintf(data, "testuser%d", _i); data->domain = get_local_domain(test_ctx->domains); - data->next_fn = test_get_user_attr; ret = sysdb_get_user_attr(data, data->ctx->sysdb, data->domain, data->username, attrs, - data->next_fn, + test_get_user_attr, data); if (ret == EOK) { ret = test_loop(data); } - fail_if(ret != EOK, "Could not get attributes for user %s", data->username); + if (ret) { + fail("Could not get attributes for user %s", data->username); + goto done; + } fail_if(strcmp(data->attrval, "/bin/ksh"), "Got bad attribute value for user %s", data->username); - +done: talloc_free(test_ctx); } END_TEST @@ -1518,6 +1409,7 @@ START_TEST (test_sysdb_add_group_member) { struct sysdb_test_ctx *test_ctx; struct test_data *data; + struct tevent_req *req; int ret; /* Setup */ @@ -1529,14 +1421,19 @@ START_TEST (test_sysdb_add_group_member) data = talloc_zero(test_ctx, struct test_data); data->ctx = test_ctx; + data->ev = test_ctx->ev; data->groupname = talloc_asprintf(data, "testgroup%d", _i); data->uid = _i - 1000; /* the UID of user to add */ data->domain = get_local_domain(test_ctx->domains); - data->next_fn = test_return; - ret = sysdb_transaction(data, test_ctx->sysdb, - test_add_group_member, data); + req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb); + if (!req) { + ret = ENOMEM; + } + if (ret == EOK) { + tevent_req_set_callback(req, test_add_group_member, data); + ret = test_loop(data); } @@ -1549,6 +1446,7 @@ START_TEST (test_sysdb_remove_group_member) { struct sysdb_test_ctx *test_ctx; struct test_data *data; + struct tevent_req *req; int ret; /* Setup */ @@ -1560,13 +1458,19 @@ START_TEST (test_sysdb_remove_group_member) data = talloc_zero(test_ctx, struct test_data); data->ctx = test_ctx; + data->ev = test_ctx->ev; data->groupname = talloc_asprintf(data, "testgroup%d", _i); data->uid = _i - 1000; /* the UID of user to add */ data->domain = get_local_domain(test_ctx->domains); - ret = sysdb_transaction(data, test_ctx->sysdb, - test_remove_group_member, data); + req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb); + if (!req) { + ret = ENOMEM; + } + if (ret == EOK) { + tevent_req_set_callback(req, test_remove_group_member, data); + ret = test_loop(data); } @@ -1581,29 +1485,17 @@ Suite *create_sysdb_suite(void) TCase *tc_sysdb = tcase_create("SYSDB Tests"); /* Create a new user (legacy) */ - tcase_add_loop_test(tc_sysdb, test_sysdb_store_legacy_user,27000,27010); + tcase_add_loop_test(tc_sysdb, test_sysdb_store_user,27000,27010); /* Verify the users were added */ tcase_add_loop_test(tc_sysdb, test_sysdb_getpwnam, 27000, 27010); /* Create a new group (legacy) */ - tcase_add_loop_test(tc_sysdb, test_sysdb_store_legacy_group,27000,27010); + tcase_add_loop_test(tc_sysdb, test_sysdb_store_group,27000,27010); /* Verify the groups were added */ tcase_add_loop_test(tc_sysdb, test_sysdb_getgrnam, 27000, 27010); - /* Add users to the group */ - tcase_add_loop_test(tc_sysdb, test_sysdb_add_legacy_group_member, 27000, 27010); - - /* Verify member and memberOf */ - tcase_add_loop_test(tc_sysdb, test_sysdb_verify_legacy_group_members, 27000, 27010); -#if 0 - /* A negative test: add nonexistent users as members of a group */ - tcase_add_loop_test(tc_sysdb, test_sysdb_add_invalid_member, 27000, 27010); -#endif - /* Remove users from their groups */ - tcase_add_loop_test(tc_sysdb, test_sysdb_remove_legacy_group_member, 27000, 27010); - /* Remove the other half by gid */ tcase_add_loop_test(tc_sysdb, test_sysdb_remove_local_group_by_gid, 27000, 27005); diff --git a/server/tools/sss_groupadd.c b/server/tools/sss_groupadd.c index acb26f3aa..ea7320161 100644 --- a/server/tools/sss_groupadd.c +++ b/server/tools/sss_groupadd.c @@ -44,6 +44,7 @@ #endif struct group_add_ctx { + struct tevent_context *ev; struct sysdb_handle *handle; struct sss_domain_info *domain; @@ -56,36 +57,75 @@ struct group_add_ctx { bool done; }; -/* sysdb callback */ -static void add_group_done(void *pvt, int error, struct ldb_result *ignore) +static void add_group_req_done(struct tevent_req *req) { - struct group_add_ctx *data = talloc_get_type(pvt, struct group_add_ctx); + struct group_add_ctx *data = tevent_req_callback_data(req, + struct group_add_ctx); + data->error = sysdb_transaction_commit_recv(req); data->done = true; - sysdb_transaction_done(data->handle, error); + talloc_zfree(data->handle); +} + +static void add_group_terminate(struct group_add_ctx *data, int error) +{ + struct tevent_req *req; + + if (error != EOK) { + goto fail; + } - if (error) - data->error = error; + req = sysdb_transaction_commit_send(data, data->ev, data->handle); + if (!req) { + error = ENOMEM; + goto fail; + } + tevent_req_set_callback(req, add_group_req_done, data); + + return; + +fail: + /* free transaction */ + talloc_zfree(data->handle); + + data->error = error; + data->done = true; } -/* sysdb_fn_t */ -static void add_group(struct sysdb_handle *handle, void *pvt) +static void add_group_done(struct tevent_req *subreq); + +static void add_group(struct tevent_req *req) { - struct group_add_ctx *group_ctx; + struct group_add_ctx *data = tevent_req_callback_data(req, + struct group_add_ctx); + struct tevent_req *subreq; int ret; - group_ctx = talloc_get_type(pvt, struct group_add_ctx); - group_ctx->handle = handle; + ret = sysdb_transaction_recv(req, data, &data->handle); + if (ret != EOK) { + return add_group_terminate(data, ret); + } - ret = sysdb_add_group(handle, group_ctx->domain, - group_ctx->groupname, - group_ctx->gid, - add_group_done, - group_ctx); + subreq = sysdb_add_group_send(data, data->ev, data->handle, + data->domain, data->groupname, + data->gid, NULL); + if (!subreq) { + add_group_terminate(data, ENOMEM); + } + tevent_req_set_callback(subreq, add_group_done, data); +} - if(ret != EOK) - add_group_done(group_ctx, ret, NULL); +static void add_group_done(struct tevent_req *subreq) +{ + struct group_add_ctx *data = tevent_req_callback_data(subreq, + struct group_add_ctx); + int ret; + + ret = sysdb_add_group_recv(subreq); + talloc_zfree(subreq); + + return add_group_terminate(data, ret); } static int groupadd_legacy(struct group_add_ctx *ctx) @@ -130,6 +170,7 @@ int main(int argc, const char **argv) struct sss_domain_info *dom; poptContext pc = NULL; struct tools_ctx *ctx = NULL; + struct tevent_req *req; struct group_add_ctx *group_ctx = NULL; int ret = EXIT_SUCCESS; @@ -202,13 +243,14 @@ int main(int argc, const char **argv) } /* add_group */ - ret = sysdb_transaction(ctx, ctx->sysdb, add_group, group_ctx); - if(ret != EOK) { + req = sysdb_transaction_send(ctx, ctx->ev, ctx->sysdb); + if (!req) { DEBUG(1, ("Could not start transaction (%d)[%s]\n", ret, strerror(ret))); ERROR("Transaction error. Could not add group.\n"); ret = EXIT_FAILURE; goto fini; } + tevent_req_set_callback(req, add_group, group_ctx); while (!group_ctx->done) { tevent_loop_once(ctx->ev); diff --git a/server/tools/sss_groupdel.c b/server/tools/sss_groupdel.c index 820cf2520..194285c97 100644 --- a/server/tools/sss_groupdel.c +++ b/server/tools/sss_groupdel.c @@ -41,6 +41,7 @@ struct group_del_ctx { + struct tevent_context *ev; struct sysdb_handle *handle; sysdb_callback_t next_fn; @@ -55,35 +56,77 @@ struct group_del_ctx { bool done; }; +static void groupdel_req_done(struct tevent_req *req) +{ + struct group_del_ctx *data = tevent_req_callback_data(req, + struct group_del_ctx); + + data->error = sysdb_transaction_commit_recv(req); + data->done = true; + + talloc_zfree(data->handle); +} + /* sysdb callback */ static void groupdel_done(void *pvt, int error, struct ldb_result *ignore) { struct group_del_ctx *data = talloc_get_type(pvt, struct group_del_ctx); + struct tevent_req *req; - data->done = true; + if (error != EOK) { + goto fail; + } + + req = sysdb_transaction_commit_send(data, data->ev, data->handle); + if (!req) { + error = ENOMEM; + goto fail; + } + tevent_req_set_callback(req, groupdel_req_done, data); + + return; - sysdb_transaction_done(data->handle, error); +fail: + /* free transaction */ + talloc_zfree(data->handle); - if (error) - data->error = error; + data->error = error; + data->done = true; } -/* sysdb_fn_t */ -static void group_del(struct sysdb_handle *handle, void *pvt) +static void group_del_done(struct tevent_req *subreq); + +static void group_del(struct tevent_req *req) { - struct group_del_ctx *group_ctx; + struct group_del_ctx *data = tevent_req_callback_data(req, + struct group_del_ctx); + struct tevent_req *subreq; int ret; - group_ctx = talloc_get_type(pvt, struct group_del_ctx); - group_ctx->handle = handle; + ret = sysdb_transaction_recv(req, data, &data->handle); + if (ret != EOK) { + return groupdel_done(data, ret, NULL); + } + + subreq = sysdb_delete_entry_send(data, + data->ev, + data->handle, + data->group_dn); + if (!subreq) + return groupdel_done(data, ret, NULL); + + tevent_req_set_callback(subreq, group_del_done, data); +} - ret = sysdb_delete_entry(handle, - group_ctx->group_dn, - groupdel_done, - group_ctx); +static void group_del_done(struct tevent_req *subreq) +{ + struct group_del_ctx *data = tevent_req_callback_data(subreq, + struct group_del_ctx); + int ret; - if(ret != EOK) - groupdel_done(group_ctx, ret, NULL); + ret = sysdb_delete_entry_recv(subreq); + + return groupdel_done(data, ret, NULL); } static int groupdel_legacy(struct group_del_ctx *ctx) @@ -115,6 +158,7 @@ int main(int argc, const char **argv) int pc_debug = 0; struct group_del_ctx *group_ctx = NULL; struct tools_ctx *ctx = NULL; + struct tevent_req *req; struct sss_domain_info *dom; struct group *grp_info; @@ -208,13 +252,14 @@ int main(int argc, const char **argv) } /* groupdel */ - ret = sysdb_transaction(ctx, ctx->sysdb, group_del, group_ctx); - if(ret != EOK) { + req = sysdb_transaction_send(ctx, ctx->ev, ctx->sysdb); + if (!req) { DEBUG(1, ("Could not start transaction (%d)[%s]\n", ret, strerror(ret))); ERROR("Transaction error. Could not remove group.\n"); ret = EXIT_FAILURE; goto fini; } + tevent_req_set_callback(req, group_del, group_ctx); while (!group_ctx->done) { tevent_loop_once(ctx->ev); diff --git a/server/tools/sss_groupmod.c b/server/tools/sss_groupmod.c index 0c2abda8f..cc7665d9d 100644 --- a/server/tools/sss_groupmod.c +++ b/server/tools/sss_groupmod.c @@ -45,6 +45,7 @@ #endif struct group_mod_ctx { + struct tevent_context *ev; struct sysdb_handle *handle; struct sss_domain_info *domain; @@ -61,132 +62,225 @@ struct group_mod_ctx { bool done; }; -/* sysdb callback */ -static void mod_group_done(void *pvt, int error, struct ldb_result *ignore) +static void mod_group_req_done(struct tevent_req *req) { - struct group_mod_ctx *data = talloc_get_type(pvt, struct group_mod_ctx); + struct group_mod_ctx *data = tevent_req_callback_data(req, + struct group_mod_ctx); + data->error = sysdb_transaction_commit_recv(req); data->done = true; - sysdb_transaction_done(data->handle, error); + talloc_zfree(data->handle); +} + +static void mod_group_done(struct group_mod_ctx *data, int error) +{ + struct tevent_req *req; + + if (error != EOK) { + goto fail; + } + + req = sysdb_transaction_commit_send(data, data->ev, data->handle); + if (!req) { + error = ENOMEM; + goto fail; + } + tevent_req_set_callback(req, mod_group_req_done, data); + + return; - if (error) - data->error = error; +fail: + /* free transaction */ + talloc_zfree(data->handle); + + data->error = error; + data->done = true; } -static void add_to_groups(void *, int, struct ldb_result *); +static void mod_group_attr_done(struct tevent_req *req); +static void mod_group_cont(struct group_mod_ctx *data); +static void remove_from_groups(struct group_mod_ctx *data); +static void remove_from_groups_done(struct tevent_req *req); +static void add_to_groups(struct group_mod_ctx *data); +static void add_to_groups_done(struct tevent_req *req); -/* sysdb_fn_t */ -static void mod_group(struct sysdb_handle *handle, void *pvt) +static void mod_group(struct tevent_req *req) { - struct group_mod_ctx *group_ctx; + struct group_mod_ctx *data; + struct tevent_req *subreq; + struct sysdb_attrs *attrs; int ret; - group_ctx = talloc_get_type(pvt, struct group_mod_ctx); - group_ctx->handle = handle; - - if(group_ctx->gid == 0) { - add_to_groups(group_ctx, EOK, NULL); - } else { - ret = sysdb_set_group_gid(handle, - group_ctx->domain, - group_ctx->groupname, - group_ctx->gid, - mod_group_done, - group_ctx); - if (ret != EOK) { - mod_group_done(group_ctx, ret, NULL); + data = tevent_req_callback_data(req, struct group_mod_ctx); + + ret = sysdb_transaction_recv(req, data, &data->handle); + if (ret != EOK) { + return mod_group_done(data, ret); + } + talloc_zfree(req); + + if (data->gid != 0) { + attrs = sysdb_new_attrs(data); + if (!attrs) { + mod_group_done(data, ENOMEM); + } + ret = sysdb_attrs_add_uint32(attrs, SYSDB_GIDNUM, data->gid); + if (ret) { + mod_group_done(data, ret); } + + subreq = sysdb_set_group_attr_send(data, data->ev, data->handle, + data->domain, data->groupname, + attrs, SYSDB_MOD_REP); + if (!subreq) { + return mod_group_done(data, ret); + } + tevent_req_set_callback(subreq, mod_group_attr_done, data); + return; } + + return mod_group_cont(data); } -static void remove_from_groups(void *pvt, int error, struct ldb_result *ignore) +static void mod_group_attr_done(struct tevent_req *subreq) { - struct group_mod_ctx *group_ctx = talloc_get_type(pvt, struct group_mod_ctx); - struct ldb_dn *group_dn; - struct ldb_dn *parent_group_dn; + struct group_mod_ctx *data = tevent_req_callback_data(subreq, + struct group_mod_ctx); int ret; - if (error) { - mod_group_done(pvt, error, NULL); - return; + ret = sysdb_set_group_attr_recv(subreq); + talloc_zfree(subreq); + if (ret != EOK) { + return mod_group_done(data, ret); } - /* check if we removed all of them */ - if (group_ctx->rmgroups == NULL || - group_ctx->rmgroups[group_ctx->cur] == NULL) { - mod_group_done(group_ctx, EOK, NULL); - return; + mod_group_cont(data); +} + +static void mod_group_cont(struct group_mod_ctx *data) +{ + if (data->rmgroups != NULL) { + return remove_from_groups(data); } - group_dn = sysdb_group_dn(group_ctx->ctx->sysdb, group_ctx, - group_ctx->domain->name, group_ctx->groupname); - if (!group_dn) { - mod_group_done(pvt, ENOMEM, NULL); - return; + if (data->addgroups != NULL) { + return add_to_groups(data); } - parent_group_dn = sysdb_group_dn(group_ctx->ctx->sysdb, group_ctx, - group_ctx->domain->name, - group_ctx->rmgroups[group_ctx->cur]); - if (!parent_group_dn) { - mod_group_done(pvt, ENOMEM, NULL); - return; + return mod_group_done(data, EOK); +} + +static void remove_from_groups(struct group_mod_ctx *data) +{ + struct ldb_dn *parent_dn; + struct ldb_dn *member_dn; + struct tevent_req *req; + + member_dn = sysdb_group_dn(data->ctx->sysdb, data, + data->domain->name, data->groupname); + if (!member_dn) { + return mod_group_done(data, ENOMEM); } - ret = sysdb_remove_group_member(group_ctx->handle, - group_dn, parent_group_dn, - remove_from_groups, group_ctx); - if (ret != EOK) - mod_group_done(group_ctx, ret, NULL); + parent_dn = sysdb_group_dn(data->ctx->sysdb, data, + data->domain->name, + data->rmgroups[data->cur]); + if (!parent_dn) { + return mod_group_done(data, ENOMEM); + } - /* go on to next group */ - group_ctx->cur++; + req = sysdb_mod_group_member_send(data, + data->ev, + data->handle, + member_dn, + parent_dn, + LDB_FLAG_MOD_DELETE); + if (!req) { + return mod_group_done(data, ENOMEM); + } + tevent_req_set_callback(req, remove_from_groups_done, data); } -static void add_to_groups(void *pvt, int error, struct ldb_result *ignore) +static void remove_from_groups_done(struct tevent_req *req) { - struct group_mod_ctx *group_ctx = talloc_get_type(pvt, struct group_mod_ctx); - struct ldb_dn *group_dn; - struct ldb_dn *parent_group_dn; + struct group_mod_ctx *data = tevent_req_callback_data(req, + struct group_mod_ctx); int ret; - if (error) { - mod_group_done(pvt, error, NULL); - return; + ret = sysdb_mod_group_member_recv(req); + if (ret) { + return mod_group_done(data, ret); } + talloc_zfree(req); + + /* go on to next group */ + data->cur++; /* check if we added all of them */ - if (group_ctx->addgroups == NULL || - group_ctx->addgroups[group_ctx->cur] == NULL) { - group_ctx->cur = 0; - remove_from_groups(group_ctx, EOK, NULL); - return; + if (data->rmgroups[data->cur] == NULL) { + data->cur = 0; + if (data->addgroups != NULL) { + return remove_from_groups(data); + } + return mod_group_done(data, EOK); } - group_dn = sysdb_group_dn(group_ctx->ctx->sysdb, group_ctx, - group_ctx->domain->name, group_ctx->groupname); - if (!group_dn) { - mod_group_done(pvt, ENOMEM, NULL); - return; + return remove_from_groups(data); +} + +static void add_to_groups(struct group_mod_ctx *data) +{ + struct ldb_dn *parent_dn; + struct ldb_dn *member_dn; + struct tevent_req *req; + + member_dn = sysdb_group_dn(data->ctx->sysdb, data, + data->domain->name, data->groupname); + if (!member_dn) { + return mod_group_done(data, ENOMEM); } - parent_group_dn = sysdb_group_dn(group_ctx->ctx->sysdb, group_ctx, - group_ctx->domain->name, - group_ctx->addgroups[group_ctx->cur]); - if (!parent_group_dn) { - mod_group_done(pvt, ENOMEM, NULL); - return; + parent_dn = sysdb_group_dn(data->ctx->sysdb, data, + data->domain->name, + data->addgroups[data->cur]); + if (!parent_dn) { + return mod_group_done(data, ENOMEM); + } + + req = sysdb_mod_group_member_send(data, + data->ev, + data->handle, + member_dn, + parent_dn, + LDB_FLAG_MOD_ADD); + if (!req) { + return mod_group_done(data, ENOMEM); } + tevent_req_set_callback(req, add_to_groups_done, data); +} + +static void add_to_groups_done(struct tevent_req *req) +{ + struct group_mod_ctx *data = tevent_req_callback_data(req, + struct group_mod_ctx); + int ret; - ret = sysdb_add_group_member(group_ctx->handle, - group_dn, parent_group_dn, - add_to_groups, group_ctx); - if (ret != EOK) - mod_group_done(group_ctx, ret, NULL); + ret = sysdb_mod_group_member_recv(req); + if (ret) { + return mod_group_done(data, ret); + } + talloc_zfree(req); /* go on to next group */ - group_ctx->cur++; + data->cur++; + + /* check if we added all of them */ + if (data->addgroups[data->cur] == NULL) { + return mod_group_done(data, EOK); + } + + return add_to_groups(data); } static int groupmod_legacy(struct tools_ctx *tools_ctx, struct group_mod_ctx *ctx, int old_domain) @@ -247,6 +341,7 @@ int main(int argc, const char **argv) struct sss_domain_info *dom; struct group_mod_ctx *group_ctx = NULL; struct tools_ctx *ctx = NULL; + struct tevent_req *req; char *groups; int ret; struct group *grp_info; @@ -344,13 +439,14 @@ int main(int argc, const char **argv) goto fini; } - ret = sysdb_transaction(ctx, ctx->sysdb, mod_group, group_ctx); - if (ret != EOK) { + req = sysdb_transaction_send(ctx, ctx->ev, ctx->sysdb); + if (!req) { DEBUG(1, ("Could not start transaction (%d)[%s]\n", ret, strerror(ret))); ERROR("Transaction error. Could not modify group.\n"); ret = EXIT_FAILURE; goto fini; } + tevent_req_set_callback(req, mod_group, group_ctx); while (!group_ctx->done) { tevent_loop_once(ctx->ev); diff --git a/server/tools/sss_useradd.c b/server/tools/sss_useradd.c index d1d83cf1d..ed9974fe8 100644 --- a/server/tools/sss_useradd.c +++ b/server/tools/sss_useradd.c @@ -84,6 +84,7 @@ #define DFL_BASEDIR_VAL "/home" struct user_add_ctx { + struct tevent_context *ev; struct sysdb_handle *handle; struct sss_domain_info *domain; @@ -187,85 +188,137 @@ done: return ret; } -static void add_to_groups(void *, int, struct ldb_result *); - -/* sysdb callback */ -static void add_user_done(void *pvt, int error, struct ldb_result *ignore) +static void add_user_req_done(struct tevent_req *req) { - struct user_add_ctx *data = talloc_get_type(pvt, struct user_add_ctx); + struct user_add_ctx *data = tevent_req_callback_data(req, + struct user_add_ctx); + data->error = sysdb_transaction_commit_recv(req); data->done = true; - sysdb_transaction_done(data->handle, error); + talloc_zfree(data->handle); +} - if (error) - data->error = error; +static void add_user_terminate(struct user_add_ctx *data, int error) +{ + struct tevent_req *req; + + if (error != EOK) { + goto fail; + } + + req = sysdb_transaction_commit_send(data, data->ev, data->handle); + if (!req) { + error = ENOMEM; + goto fail; + } + tevent_req_set_callback(req, add_user_req_done, data); + + return; + +fail: + /* free transaction */ + talloc_zfree(data->handle); + + data->error = error; + data->done = true; } -/* sysdb_fn_t */ -static void add_user(struct sysdb_handle *handle, void *pvt) +static void add_user_done(struct tevent_req *subreq); +static void add_to_groups(struct user_add_ctx *data); +static void add_to_groups_done(struct tevent_req *req); + +static void add_user(struct tevent_req *req) { - struct user_add_ctx *user_ctx; + struct user_add_ctx *data = tevent_req_callback_data(req, + struct user_add_ctx); + struct tevent_req *subreq; int ret; - user_ctx = talloc_get_type(pvt, struct user_add_ctx); - user_ctx->handle = handle; - - ret = sysdb_add_user(handle, user_ctx->domain, - user_ctx->username, - user_ctx->uid, - user_ctx->gid, - user_ctx->gecos, - user_ctx->home, - user_ctx->shell, - add_to_groups, user_ctx); + ret = sysdb_transaction_recv(req, data, &data->handle); + if (ret != EOK) { + return add_user_terminate(data, ret); + } - if (ret != EOK) - add_user_done(user_ctx, ret, NULL); + subreq = sysdb_add_user_send(data, data->ev, data->handle, + data->domain, data->username, + data->uid, data->gid, + data->gecos, data->home, + data->shell, NULL); + if (!subreq) { + add_user_terminate(data, ENOMEM); + } + tevent_req_set_callback(subreq, add_user_done, data); } -static void add_to_groups(void *pvt, int error, struct ldb_result *ignore) +static void add_user_done(struct tevent_req *subreq) { - struct user_add_ctx *user_ctx = talloc_get_type(pvt, struct user_add_ctx); - struct ldb_dn *group_dn; - struct ldb_dn *user_dn; + struct user_add_ctx *data = tevent_req_callback_data(subreq, + struct user_add_ctx); int ret; - if (error) { - add_user_done(pvt, error, NULL); - return; + ret = sysdb_add_user_recv(subreq); + talloc_zfree(subreq); + if (ret) { + return add_user_terminate(data, ret); } - /* check if we added all of them */ - if (user_ctx->groups == NULL || - user_ctx->groups[user_ctx->cur] == NULL) { - add_user_done(user_ctx, EOK, NULL); - return; + if (data->groups) { + return add_to_groups(data); } - user_dn = sysdb_user_dn(user_ctx->ctx->sysdb, user_ctx, - user_ctx->domain->name, user_ctx->username); - if (!user_dn) { - add_user_done(pvt, ENOMEM, NULL); - return; + return add_user_terminate(data, ret); +} + +static void add_to_groups(struct user_add_ctx *data) +{ + struct ldb_dn *parent_dn; + struct ldb_dn *member_dn; + struct tevent_req *subreq; + + member_dn = sysdb_group_dn(data->ctx->sysdb, data, + data->domain->name, data->username); + if (!member_dn) { + return add_user_terminate(data, ENOMEM); } - group_dn = sysdb_group_dn(user_ctx->ctx->sysdb, user_ctx, - user_ctx->domain->name, - user_ctx->groups[user_ctx->cur]); - if (!group_dn) { - add_user_done(pvt, ENOMEM, NULL); - return; + parent_dn = sysdb_group_dn(data->ctx->sysdb, data, + data->domain->name, + data->groups[data->cur]); + if (!parent_dn) { + return add_user_terminate(data, ENOMEM); } - ret = sysdb_add_group_member(user_ctx->handle, - user_dn, group_dn, - add_to_groups, user_ctx); - if (ret != EOK) - add_user_done(user_ctx, ret, NULL); + subreq = sysdb_mod_group_member_send(data, data->ev, data->handle, + member_dn, parent_dn, + LDB_FLAG_MOD_ADD); + if (!subreq) { + return add_user_terminate(data, ENOMEM); + } + tevent_req_set_callback(subreq, add_to_groups_done, data); +} + +static void add_to_groups_done(struct tevent_req *subreq) +{ + struct user_add_ctx *data = tevent_req_callback_data(subreq, + struct user_add_ctx); + int ret; + + ret = sysdb_mod_group_member_recv(subreq); + talloc_zfree(subreq); + if (ret) { + return add_user_terminate(data, ret); + } /* go on to next group */ - user_ctx->cur++; + data->cur++; + + /* check if we added all of them */ + if (data->groups[data->cur] == NULL) { + return add_user_terminate(data, EOK); + } + + return add_to_groups(data); } static int useradd_legacy(struct user_add_ctx *ctx, char *grouplist) @@ -332,6 +385,7 @@ int main(int argc, const char **argv) struct sss_domain_info *dom = NULL; struct user_add_ctx *user_ctx = NULL; struct tools_ctx *ctx = NULL; + struct tevent_req *req; char *groups = NULL; int ret; @@ -352,6 +406,7 @@ int main(int argc, const char **argv) return ENOMEM; } user_ctx->ctx = ctx; + user_ctx->ev = ctx->ev; /* parse user_ctx */ pc = poptGetContext(NULL, argc, argv, long_options, 0); @@ -478,13 +533,14 @@ int main(int argc, const char **argv) } /* useradd */ - ret = sysdb_transaction(ctx, ctx->sysdb, add_user, user_ctx); - if (ret != EOK) { + req = sysdb_transaction_send(ctx, ctx->ev, ctx->sysdb); + if (!req) { DEBUG(1, ("Could not start transaction (%d)[%s]\n", ret, strerror(ret))); ERROR("Transaction error. Could not modify user.\n"); ret = EXIT_FAILURE; goto fini; } + tevent_req_set_callback(req, add_user, user_ctx); while (!user_ctx->done) { tevent_loop_once(ctx->ev); diff --git a/server/tools/sss_userdel.c b/server/tools/sss_userdel.c index 0222d00cc..bb0673b0a 100644 --- a/server/tools/sss_userdel.c +++ b/server/tools/sss_userdel.c @@ -40,6 +40,7 @@ #endif struct user_del_ctx { + struct tevent_context *ev; struct sysdb_handle *handle; sysdb_callback_t next_fn; @@ -54,37 +55,81 @@ struct user_del_ctx { bool done; }; +static void userdel_req_done(struct tevent_req *req) +{ + struct user_del_ctx *data = tevent_req_callback_data(req, + struct user_del_ctx); + + data->error = sysdb_transaction_commit_recv(req); + data->done = true; + + talloc_zfree(data->handle); +} + /* sysdb callback */ static void userdel_done(void *pvt, int error, struct ldb_result *ignore) { struct user_del_ctx *data = talloc_get_type(pvt, struct user_del_ctx); + struct tevent_req *req; - data->done = true; + if (error != EOK) { + goto fail; + } + + req = sysdb_transaction_commit_send(data, data->ev, data->handle); + if (!req) { + error = ENOMEM; + goto fail; + } + tevent_req_set_callback(req, userdel_req_done, data); + + return; - sysdb_transaction_done(data->handle, error); +fail: + /* free transaction */ + talloc_zfree(data->handle); - if (error) - data->error = error; + data->error = error; + data->done = true; } -/* sysdb_fn_t */ -static void user_del(struct sysdb_handle *handle, void *pvt) +static void user_del_done(struct tevent_req *subreq); + +static void user_del(struct tevent_req *req) { - struct user_del_ctx *user_ctx; + struct user_del_ctx *data; + struct tevent_req *subreq; int ret; - user_ctx = talloc_get_type(pvt, struct user_del_ctx); - user_ctx->handle = handle; + data = tevent_req_callback_data(req, struct user_del_ctx); + + ret = sysdb_transaction_recv(req, data, &data->handle); + if (ret != EOK) { + return userdel_done(data, ret, NULL); + } - ret = sysdb_delete_entry(handle, - user_ctx->user_dn, - userdel_done, - user_ctx); + subreq = sysdb_delete_entry_send(data, + data->ev, + data->handle, + data->user_dn); + if (!subreq) + return userdel_done(data, ret, NULL); - if(ret != EOK) - userdel_done(user_ctx, ret, NULL); + tevent_req_set_callback(subreq, user_del_done, data); } +static void user_del_done(struct tevent_req *subreq) +{ + struct user_del_ctx *data = tevent_req_callback_data(subreq, + struct user_del_ctx); + int ret; + + ret = sysdb_delete_entry_recv(subreq); + + return userdel_done(data, ret, NULL); +} + + static int userdel_legacy(struct user_del_ctx *ctx) { int ret = EOK; @@ -113,6 +158,7 @@ int main(int argc, const char **argv) int ret = EXIT_SUCCESS; struct user_del_ctx *user_ctx = NULL; struct tools_ctx *ctx = NULL; + struct tevent_req *req; struct sss_domain_info *dom; struct passwd *pwd_info; @@ -141,6 +187,7 @@ int main(int argc, const char **argv) return ENOMEM; } user_ctx->ctx = ctx; + user_ctx->ev = ctx->ev; /* parse user_ctx */ pc = poptGetContext(NULL, argc, argv, long_options, 0); @@ -208,13 +255,14 @@ int main(int argc, const char **argv) /* userdel */ - ret = sysdb_transaction(ctx, ctx->sysdb, user_del, user_ctx); - if(ret != EOK) { + req = sysdb_transaction_send(ctx, ctx->ev, ctx->sysdb); + if (!req) { DEBUG(1, ("Could not start transaction (%d)[%s]\n", ret, strerror(ret))); ERROR("Transaction error. Could not remove user.\n"); ret = EXIT_FAILURE; goto fini; } + tevent_req_set_callback(req, user_del, user_ctx); while (!user_ctx->done) { tevent_loop_once(ctx->ev); diff --git a/server/tools/sss_usermod.c b/server/tools/sss_usermod.c index 7bb8d663a..521c52645 100644 --- a/server/tools/sss_usermod.c +++ b/server/tools/sss_usermod.c @@ -82,6 +82,7 @@ #endif struct user_mod_ctx { + struct tevent_context *ev; struct sysdb_handle *handle; struct sss_domain_info *domain; @@ -98,133 +99,214 @@ struct user_mod_ctx { bool done; }; -/* sysdb callback */ -static void mod_user_done(void *pvt, int error, struct ldb_result *ignore) +static void mod_user_req_done(struct tevent_req *req) { - struct user_mod_ctx *data = talloc_get_type(pvt, struct user_mod_ctx); + struct user_mod_ctx *data = tevent_req_callback_data(req, + struct user_mod_ctx); + data->error = sysdb_transaction_commit_recv(req); data->done = true; - sysdb_transaction_done(data->handle, error); + talloc_zfree(data->handle); +} + +static void mod_user_done(struct user_mod_ctx *data, int error) +{ + struct tevent_req *req; + + if (error != EOK) { + goto fail; + } + + req = sysdb_transaction_commit_send(data, data->ev, data->handle); + if (!req) { + error = ENOMEM; + goto fail; + } + tevent_req_set_callback(req, mod_user_req_done, data); - if (error) - data->error = error; + return; + +fail: + /* free transaction */ + talloc_zfree(data->handle); + + data->error = error; + data->done = true; } -static void add_to_groups(void *, int, struct ldb_result *); +static void mod_user_attr_done(struct tevent_req *req); +static void mod_user_cont(struct user_mod_ctx *data); +static void remove_from_groups(struct user_mod_ctx *data); +static void remove_from_groups_done(struct tevent_req *req); +static void add_to_groups(struct user_mod_ctx *data); +static void add_to_groups_done(struct tevent_req *req); -/* sysdb_fn_t */ -static void mod_user(struct sysdb_handle *handle, void *pvt) +static void mod_user(struct tevent_req *req) { - struct user_mod_ctx *user_ctx; + struct user_mod_ctx *data; + struct tevent_req *subreq; int ret; - user_ctx = talloc_get_type(pvt, struct user_mod_ctx); - user_ctx->handle = handle; - - if(user_ctx->attrs->num == 0) { - add_to_groups(user_ctx, EOK, NULL); - } else { - ret = sysdb_set_user_attr(handle, - user_ctx->domain, - user_ctx->username, - user_ctx->attrs, - add_to_groups, - user_ctx); - - if (ret != EOK) { - mod_user_done(user_ctx, ret, NULL); + data = tevent_req_callback_data(req, struct user_mod_ctx); + + ret = sysdb_transaction_recv(req, data, &data->handle); + if (ret != EOK) { + return mod_user_done(data, ret); + } + + if (data->attrs->num != 0) { + subreq = sysdb_set_user_attr_send(data, data->ev, data->handle, + data->domain, data->username, + data->attrs, SYSDB_MOD_REP); + if (!subreq) { + return mod_user_done(data, ret); } + tevent_req_set_callback(subreq, mod_user_attr_done, data); + return; } + + return mod_user_cont(data); } -static void remove_from_groups(void *pvt, int error, struct ldb_result *ignore) +static void mod_user_attr_done(struct tevent_req *subreq) { - struct user_mod_ctx *user_ctx = talloc_get_type(pvt, struct user_mod_ctx); - struct ldb_dn *group_dn; - struct ldb_dn *user_dn; + struct user_mod_ctx *data = tevent_req_callback_data(subreq, + struct user_mod_ctx); int ret; - if (error) { - mod_user_done(pvt, error, NULL); - return; + ret = sysdb_set_user_attr_recv(subreq); + talloc_zfree(subreq); + if (ret != EOK) { + return mod_user_done(data, ret); } - /* check if we removed all of them */ - if (user_ctx->rmgroups == NULL || - user_ctx->rmgroups[user_ctx->cur] == NULL) { - mod_user_done(user_ctx, EOK, NULL); - return; + mod_user_cont(data); +} + +static void mod_user_cont(struct user_mod_ctx *data) +{ + if (data->rmgroups != NULL) { + return remove_from_groups(data); } - user_dn = sysdb_user_dn(user_ctx->ctx->sysdb, user_ctx, - user_ctx->domain->name, user_ctx->username); - if (!user_dn) { - mod_user_done(pvt, ENOMEM, NULL); - return; + if (data->addgroups != NULL) { + return add_to_groups(data); } - group_dn = sysdb_group_dn(user_ctx->ctx->sysdb, user_ctx, - user_ctx->domain->name, - user_ctx->rmgroups[user_ctx->cur]); - if (!group_dn) { - mod_user_done(pvt, ENOMEM, NULL); - return; + return mod_user_done(data, EOK); +} + +static void remove_from_groups(struct user_mod_ctx *data) +{ + struct ldb_dn *parent_dn; + struct ldb_dn *member_dn; + struct tevent_req *req; + + member_dn = sysdb_group_dn(data->ctx->sysdb, data, + data->domain->name, data->username); + if (!member_dn) { + return mod_user_done(data, ENOMEM); } - ret = sysdb_remove_group_member(user_ctx->handle, - user_dn, group_dn, - remove_from_groups, user_ctx); - if (ret != EOK) - mod_user_done(user_ctx, ret, NULL); + parent_dn = sysdb_group_dn(data->ctx->sysdb, data, + data->domain->name, + data->rmgroups[data->cur]); + if (!parent_dn) { + return mod_user_done(data, ENOMEM); + } - /* go on to next group */ - user_ctx->cur++; + req = sysdb_mod_group_member_send(data, + data->ev, + data->handle, + member_dn, + parent_dn, + LDB_FLAG_MOD_DELETE); + if (!req) { + return mod_user_done(data, ENOMEM); + } + tevent_req_set_callback(req, remove_from_groups_done, data); } -static void add_to_groups(void *pvt, int error, struct ldb_result *ignore) +static void remove_from_groups_done(struct tevent_req *req) { - struct user_mod_ctx *user_ctx = talloc_get_type(pvt, struct user_mod_ctx); - struct ldb_dn *group_dn; - struct ldb_dn *user_dn; + struct user_mod_ctx *data = tevent_req_callback_data(req, + struct user_mod_ctx); int ret; - if (error) { - mod_user_done(pvt, error, NULL); - return; + ret = sysdb_mod_group_member_recv(req); + if (ret) { + return mod_user_done(data, ret); } + talloc_zfree(req); + + /* go on to next group */ + data->cur++; /* check if we added all of them */ - if (user_ctx->addgroups == NULL || - user_ctx->addgroups[user_ctx->cur] == NULL) { - user_ctx->cur = 0; - remove_from_groups(user_ctx, EOK, NULL); - return; + if (data->rmgroups[data->cur] == NULL) { + data->cur = 0; + if (data->addgroups != NULL) { + return remove_from_groups(data); + } + return mod_user_done(data, EOK); } - user_dn = sysdb_user_dn(user_ctx->ctx->sysdb, user_ctx, - user_ctx->domain->name, user_ctx->username); - if (!user_dn) { - mod_user_done(pvt, ENOMEM, NULL); - return; + return remove_from_groups(data); +} + +static void add_to_groups(struct user_mod_ctx *data) +{ + struct ldb_dn *parent_dn; + struct ldb_dn *member_dn; + struct tevent_req *req; + + member_dn = sysdb_group_dn(data->ctx->sysdb, data, + data->domain->name, data->username); + if (!member_dn) { + return mod_user_done(data, ENOMEM); } - group_dn = sysdb_group_dn(user_ctx->ctx->sysdb, user_ctx, - user_ctx->domain->name, - user_ctx->addgroups[user_ctx->cur]); - if (!group_dn) { - mod_user_done(pvt, ENOMEM, NULL); - return; + parent_dn = sysdb_group_dn(data->ctx->sysdb, data, + data->domain->name, + data->addgroups[data->cur]); + if (!parent_dn) { + return mod_user_done(data, ENOMEM); + } + + req = sysdb_mod_group_member_send(data, + data->ev, + data->handle, + member_dn, + parent_dn, + LDB_FLAG_MOD_ADD); + if (!req) { + return mod_user_done(data, ENOMEM); } + tevent_req_set_callback(req, add_to_groups_done, data); +} + +static void add_to_groups_done(struct tevent_req *req) +{ + struct user_mod_ctx *data = tevent_req_callback_data(req, + struct user_mod_ctx); + int ret; - ret = sysdb_add_group_member(user_ctx->handle, - user_dn, group_dn, - add_to_groups, user_ctx); - if (ret != EOK) - mod_user_done(user_ctx, ret, NULL); + ret = sysdb_mod_group_member_recv(req); + if (ret) { + return mod_user_done(data, ret); + } + talloc_zfree(req); /* go on to next group */ - user_ctx->cur++; + data->cur++; + + /* check if we added all of them */ + if (data->addgroups[data->cur] == NULL) { + return mod_user_done(data, EOK); + } + + return add_to_groups(data); } static int usermod_legacy(struct tools_ctx *tools_ctx, struct user_mod_ctx *ctx, @@ -316,6 +398,7 @@ int main(int argc, const char **argv) struct sss_domain_info *dom; struct user_mod_ctx *user_ctx = NULL; struct tools_ctx *ctx = NULL; + struct tevent_req *req; char *groups; int ret; struct passwd *pwd_info; @@ -494,13 +577,14 @@ int main(int argc, const char **argv) } user_ctx->domain = dom; - ret = sysdb_transaction(ctx, ctx->sysdb, mod_user, user_ctx); - if (ret != EOK) { + req = sysdb_transaction_send(ctx, ctx->ev, ctx->sysdb); + if (!req) { DEBUG(1, ("Could not start transaction (%d)[%s]\n", ret, strerror(ret))); ERROR("Transaction error. Could not modify user.\n"); ret = EXIT_FAILURE; goto fini; } + tevent_req_set_callback(req, mod_user, user_ctx); while (!user_ctx->done) { tevent_loop_once(ctx->ev); -- cgit