diff options
author | Simo Sorce <ssorce@redhat.com> | 2009-02-27 17:04:11 -0500 |
---|---|---|
committer | Simo Sorce <ssorce@redhat.com> | 2009-02-28 18:55:49 -0500 |
commit | f0cefca80767664b876d10126f7f79fc36dc1993 (patch) | |
tree | 1cc4792533b512da6f16cdce77f171de6aa804ae /server | |
parent | 60398e684b6d4f8880fcda357c8077ccca481041 (diff) | |
download | sssd-f0cefca80767664b876d10126f7f79fc36dc1993.tar.gz sssd-f0cefca80767664b876d10126f7f79fc36dc1993.tar.xz sssd-f0cefca80767664b876d10126f7f79fc36dc1993.zip |
Convert sync calls in sysdb to async, transaction dependent, calls.
Diffstat (limited to 'server')
-rw-r--r-- | server/db/sysdb.c | 13 | ||||
-rw-r--r-- | server/db/sysdb.h | 109 | ||||
-rw-r--r-- | server/db/sysdb_ops.c | 938 | ||||
-rw-r--r-- | server/db/sysdb_private.h | 12 | ||||
-rw-r--r-- | server/db/sysdb_req.c | 11 | ||||
-rw-r--r-- | server/db/sysdb_search.c | 40 | ||||
-rw-r--r-- | server/db/sysdb_sync.c | 880 | ||||
-rw-r--r-- | server/providers/proxy.c | 960 | ||||
-rw-r--r-- | server/server.mk | 2 |
9 files changed, 1652 insertions, 1313 deletions
diff --git a/server/db/sysdb.c b/server/db/sysdb.c index 1c91f1227..84d580a84 100644 --- a/server/db/sysdb.c +++ b/server/db/sysdb.c @@ -24,6 +24,19 @@ #include "confdb/confdb.h" #include <time.h> +struct ldb_dn *sysdb_user_dn(struct sysdb_ctx *ctx, void *memctx, + const char *domain, const char *name) +{ + return ldb_dn_new_fmt(memctx, ctx->ldb, SYSDB_TMPL_USER, name, domain); +} + +struct ldb_dn *sysdb_group_dn(struct sysdb_ctx *ctx, void *memctx, + const char *domain, const char *name) +{ + return ldb_dn_new_fmt(memctx, ctx->ldb, SYSDB_TMPL_GROUP, name, domain); +} + + /************************************************ * Initialiazation stuff */ diff --git a/server/db/sysdb.h b/server/db/sysdb.h index c0ef361be..b8393ffef 100644 --- a/server/db/sysdb.h +++ b/server/db/sysdb.h @@ -32,18 +32,8 @@ #define SYSDB_TMPL_USER_BASE "cn=users,cn=%s,"SYSDB_BASE #define SYSDB_TMPL_GROUP_BASE "cn=groups,cn=%s,"SYSDB_BASE -#define SYSDB_PWNAM_FILTER "(&(objectclass=user)(uid=%s))" -#define SYSDB_PWUID_FILTER "(&(objectclass=user)(uidNumber=%lu))" -#define SYSDB_PWENT_FILTER "(objectclass=user)" - -#define SYSDB_GRNAM_FILTER "(&(objectclass=group)(gid=%s))" -#define SYSDB_GRNA2_FILTER "(&(objectclass=user)(memberof=%s))" -#define SYSDB_GRGID_FILTER "(&(objectclass=group)(gidNumber=%lu))" -#define SYSDB_GRENT_FILTER "(objectclass=group)" - -#define SYSDB_INITGR_FILTER "(&(objectclass=group)(gidNumber=*))" - -#define SYSDB_INITGR_LEGACY_FILTER "(&(objectclass=group)(memberUid=%s))" +#define SYSDB_USER_CLASS "user" +#define SYSDB_GROUP_CLASS "group" #define SYSDB_PW_NAME "uid" #define SYSDB_PW_PWD "userPassword" @@ -61,6 +51,19 @@ #define SYSDB_LAST_UPDATE "lastUpdate" +#define SYSDB_PWNAM_FILTER "(&(objectclass="SYSDB_USER_CLASS")("SYSDB_PW_NAME"=%s))" +#define SYSDB_PWUID_FILTER "(&(objectclass="SYSDB_USER_CLASS")("SYSDB_PW_UIDNUM"=%lu))" +#define SYSDB_PWENT_FILTER "(objectclass="SYSDB_USER_CLASS")" + +#define SYSDB_GRNAM_FILTER "(&(objectclass="SYSDB_GROUP_CLASS")("SYSDB_GR_NAME"=%s))" +#define SYSDB_GRNA2_FILTER "(&(objectclass="SYSDB_USER_CLASS")("SYSDB_PW_MEMBEROF"=%s))" +#define SYSDB_GRGID_FILTER "(&(objectclass="SYSDB_GROUP_CLASS")("SYSDB_GR_GIDNUM"=%lu))" +#define SYSDB_GRENT_FILTER "(objectclass="SYSDB_GROUP_CLASS")" + +#define SYSDB_INITGR_FILTER "(&(objectclass="SYSDB_GROUP_CLASS")("SYSDB_GR_GIDNUM"=*))" + +#define SYSDB_INITGR_LEGACY_FILTER "(&(objectclass="SYSDB_GROUP_CLASS")("SYSDB_LEGACY_MEMBER"=%s))" + #define SYSDB_PW_ATTRS {SYSDB_PW_NAME, SYSDB_PW_UIDNUM, \ SYSDB_PW_GIDNUM, SYSDB_PW_FULLNAME, \ SYSDB_PW_HOMEDIR, SYSDB_PW_SHELL, \ @@ -76,10 +79,15 @@ #define SYSDB_INITGR_ATTRS {SYSDB_GR_GIDNUM, SYSDB_LAST_UPDATE, \ NULL} +#define SYSDB_TMPL_USER SYSDB_PW_NAME"=%s,"SYSDB_TMPL_USER_BASE +#define SYSDB_TMPL_GROUP SYSDB_GR_NAME"=%s,"SYSDB_TMPL_GROUP_BASE + struct confdb_ctx; struct sysdb_ctx; +struct sysdb_req; typedef void (*sysdb_callback_t)(void *, int, struct ldb_result *); +typedef void (*sysdb_req_fn_t)(struct sysdb_req *, void *pvt); int sysdb_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev, @@ -135,60 +143,59 @@ int sysdb_initgroups(TALLOC_CTX *mem_ctx, sysdb_callback_t fn, void *ptr); -/* the following are all SYNCHRONOUS calls - * TODO: make these asynchronous */ +struct sysdb_ctx *sysdb_req_get_ctx(struct sysdb_req *req); -int sysdb_add_group_member(TALLOC_CTX *mem_ctx, - struct sysdb_ctx *sysdb, - struct ldb_dn *member_dn, - struct ldb_dn *group_dn); +int sysdb_transaction(TALLOC_CTX *mem_ctx, + struct sysdb_ctx *ctx, + sysdb_req_fn_t fn, void *pvt); +void sysdb_transaction_done(struct sysdb_req *req, int status); -int sysdb_remove_group_member(TALLOC_CTX *mem_ctx, - struct sysdb_ctx *sysdb, - struct ldb_dn *member_dn, - struct ldb_dn *group_dn); +int sysdb_operation(TALLOC_CTX *mem_ctx, + struct sysdb_ctx *ctx, + sysdb_req_fn_t fn, void *pvt); +void sysdb_operation_done(struct sysdb_req *req); -int sysdb_delete_user(TALLOC_CTX *memctx, - struct sysdb_ctx *sysdb, - const char *domain, const char *name); +struct ldb_dn *sysdb_user_dn(struct sysdb_ctx *ctx, void *memctx, + const char *domain, const char *name); -int sysdb_delete_user_by_uid(TALLOC_CTX *memctx, - struct sysdb_ctx *sysdb, - const char *domain, uid_t uid); +struct ldb_dn *sysdb_group_dn(struct sysdb_ctx *ctx, void *memctx, + const char *domain, const char *name); -int sysdb_add_user_to_group(TALLOC_CTX *mem_ctx, - struct sysdb_ctx *sysdb, - const char *domain, - const char *group, - const char *username); +int sysdb_add_group_member(struct sysdb_req *sysreq, + struct ldb_dn *member_dn, + struct ldb_dn *group_dn, + sysdb_callback_t fn, void *pvt); + +int sysdb_remove_group_member(struct sysdb_req *sysreq, + struct ldb_dn *member_dn, + struct ldb_dn *group_dn, + sysdb_callback_t fn, void *pvt); -int sysdb_remove_user_from_group(TALLOC_CTX *mem_ctx, - struct sysdb_ctx *sysdb, - const char *domain, - const char *group, - const char *username); +int sysdb_delete_entry(struct sysdb_req *sysreq, + struct ldb_dn *dn, + sysdb_callback_t fn, void *pvt); -int sysdb_delete_group(TALLOC_CTX *memctx, - struct sysdb_ctx *sysdb, - const char *domain, const char *name); +int sysdb_delete_user_by_uid(struct sysdb_req *sysreq, + const char *domain, uid_t uid, + sysdb_callback_t fn, void *pvt); -int sysdb_delete_group_by_gid(TALLOC_CTX *memctx, - struct sysdb_ctx *sysdb, - const char *domain, gid_t gid); +int sysdb_delete_group_by_gid(struct sysdb_req *sysreq, + const char *domain, gid_t gid, + sysdb_callback_t fn, void *pvt); -/* legacy synchronous functions for proxy providers */ +/* legacy functions for proxy providers */ -int sysdb_legacy_store_user(TALLOC_CTX *memctx, - struct sysdb_ctx *sysdb, +int sysdb_legacy_store_user(struct sysdb_req *sysreq, const char *domain, const char *name, const char *pwd, uid_t uid, gid_t gid, const char *gecos, - const char *homedir, const char *shell); + const char *homedir, const char *shell, + sysdb_callback_t fn, void *pvt); -int sysdb_legacy_store_group(TALLOC_CTX *memctx, - struct sysdb_ctx *sysdb, +int sysdb_legacy_store_group(struct sysdb_req *sysreq, const char *domain, const char *name, gid_t gid, - char **members); + const char **members, + sysdb_callback_t fn, void *pvt); #endif /* __SYS_DB_H__ */ diff --git a/server/db/sysdb_ops.c b/server/db/sysdb_ops.c new file mode 100644 index 000000000..267771b5a --- /dev/null +++ b/server/db/sysdb_ops.c @@ -0,0 +1,938 @@ +/* + SSSD + + System Database + + Copyright (C) Simo Sorce <ssorce@redhat.com> 2008 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "util/util.h" +#include "db/sysdb_private.h" +#include <time.h> + +#define return_error(ctx, ret) ctx->fn(ctx->pvt, ret, NULL) +#define return_done(ctx) ctx->fn(ctx->pvt, EOK, NULL) + +static int add_string(struct ldb_message *msg, int flags, + const char *attr, const char *value) +{ + int ret; + + ret = ldb_msg_add_empty(msg, attr, flags, NULL); + if (ret == LDB_SUCCESS) { + ret = ldb_msg_add_string(msg, attr, value); + } + return ret; +} + +static int add_ulong(struct ldb_message *msg, int flags, + const char *attr, unsigned long value) +{ + int ret; + + ret = ldb_msg_add_empty(msg, attr, flags, NULL); + if (ret == LDB_SUCCESS) { + ret = ldb_msg_add_fmt(msg, attr, "%lu", value); + } + return ret; +} + +/* the following are all SYNCHRONOUS calls + * TODO: make these asynchronous */ + +struct sysdb_cb_ctx { + sysdb_callback_t fn; + void *pvt; + + bool ignore_not_found; +}; + +static int sysdb_op_callback(struct ldb_request *req, struct ldb_reply *rep) +{ + struct sysdb_cb_ctx *cbctx; + + cbctx = talloc_get_type(req->context, struct sysdb_cb_ctx); + + if (!rep) { + return_error(cbctx, EIO); + return LDB_ERR_OPERATIONS_ERROR; + } + if (rep->error != LDB_SUCCESS) { + if (! (cbctx->ignore_not_found && + rep->error == LDB_ERR_NO_SUCH_OBJECT)) { + return_error(cbctx, sysdb_error_to_errno(rep->error)); + return rep->error; + } + } + + talloc_free(rep); + + if (rep->type != LDB_REPLY_DONE) { + return_error(cbctx, EINVAL); + return LDB_ERR_OPERATIONS_ERROR; + } + + return_done(cbctx); + return LDB_SUCCESS; +} + +int sysdb_add_group_member(struct sysdb_req *sysreq, + struct ldb_dn *member_dn, + struct ldb_dn *group_dn, + sysdb_callback_t fn, void *pvt) +{ + struct sysdb_ctx *ctx; + struct sysdb_cb_ctx *cbctx; + struct ldb_request *req; + struct ldb_message *msg; + const char *dn; + int ret; + + if (!sysdb_req_check_running(sysreq)) { + DEBUG(2, ("Invalid request! Not running at this time.\n")); + return EINVAL; + } + + ctx = sysdb_req_get_ctx(sysreq); + + cbctx = talloc_zero(sysreq, struct sysdb_cb_ctx); + if (!cbctx) return ENOMEM; + + cbctx->fn = fn; + cbctx->pvt = pvt; + + /* Add the member_dn as a member of the group */ + msg = ldb_msg_new(cbctx); + if(msg == NULL) return ENOMEM; + + msg->dn = group_dn; + ret = ldb_msg_add_empty(msg, SYSDB_GR_MEMBER, + LDB_FLAG_MOD_ADD, NULL); + if (ret != LDB_SUCCESS) return ENOMEM; + + dn = ldb_dn_get_linearized(member_dn); + if (!dn) return EINVAL; + + ret = ldb_msg_add_fmt(msg, SYSDB_GR_MEMBER, "%s", dn); + if (ret != LDB_SUCCESS) return EINVAL; + + 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; +} + +int sysdb_remove_group_member(struct sysdb_req *sysreq, + struct ldb_dn *member_dn, + struct ldb_dn *group_dn, + sysdb_callback_t fn, void *pvt) +{ + struct sysdb_ctx *ctx; + struct sysdb_cb_ctx *cbctx; + struct ldb_request *req; + struct ldb_message *msg; + const char *dn; + int ret; + + if (!sysdb_req_check_running(sysreq)) { + DEBUG(2, ("Invalid request! Not running at this time.\n")); + return EINVAL; + } + + ctx = sysdb_req_get_ctx(sysreq); + + cbctx = talloc_zero(sysreq, struct sysdb_cb_ctx); + if (!cbctx) return ENOMEM; + + cbctx->fn = fn; + cbctx->pvt = pvt; + + /* Add the member_dn as a member of the group */ + msg = ldb_msg_new(cbctx); + if(msg == NULL) return ENOMEM; + + msg->dn = group_dn; + ret = ldb_msg_add_empty(msg, SYSDB_GR_MEMBER, + LDB_FLAG_MOD_DELETE, NULL); + if (ret != LDB_SUCCESS) return ENOMEM; + + dn = ldb_dn_get_linearized(member_dn); + if (!dn) return EINVAL; + + ret = ldb_msg_add_fmt(msg, SYSDB_GR_MEMBER, "%s", dn); + if (ret != LDB_SUCCESS) return EINVAL; + + 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; +} + +int sysdb_delete_entry(struct sysdb_req *sysreq, + struct ldb_dn *dn, + sysdb_callback_t fn, void *pvt) +{ + struct sysdb_ctx *ctx; + struct sysdb_cb_ctx *cbctx; + struct ldb_request *req; + int ret; + + if (!sysdb_req_check_running(sysreq)) { + DEBUG(2, ("Invalid request! Not running at this time.\n")); + return EINVAL; + } + + ctx = sysdb_req_get_ctx(sysreq); + + cbctx = talloc_zero(sysreq, struct sysdb_cb_ctx); + if (!cbctx) return ENOMEM; + + cbctx->fn = fn; + cbctx->pvt = pvt; + cbctx->ignore_not_found = true; + + ret = ldb_build_del_req(&req, ctx->ldb, cbctx, dn, NULL, + cbctx, sysdb_op_callback, 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); + } + + ret = ldb_request(ctx->ldb, req); + if (ret != LDB_SUCCESS) return sysdb_error_to_errno(ret); + + return EOK; +} + +struct delete_ctx { + struct sysdb_req *sysreq; + struct sysdb_cb_ctx *cbctx; + + struct ldb_result *res; +}; + +static int delete_callback(struct ldb_request *req, struct ldb_reply *rep) +{ + 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; + + del_ctx = talloc_get_type(req->context, struct delete_ctx); + ctx = sysdb_req_get_ctx(del_ctx->sysreq); + cbctx = del_ctx->cbctx; + res = del_ctx->res; + + if (!rep) { + return_error(cbctx, EIO); + return LDB_ERR_OPERATIONS_ERROR; + } + if (rep->error != LDB_SUCCESS) { + return_error(cbctx, sysdb_error_to_errno(rep->error)); + return rep->error; + } + + switch (rep->type) { + case LDB_REPLY_ENTRY: + res->msgs = talloc_realloc(res, res->msgs, + struct ldb_message *, + res->count + 2); + if (!res->msgs) { + ret = LDB_ERR_OPERATIONS_ERROR; + return_error(cbctx, sysdb_error_to_errno(ret)); + return ret; + } + + res->msgs[res->count + 1] = NULL; + + res->msgs[res->count] = talloc_steal(res->msgs, rep->message); + res->count++; + + break; + + case LDB_REPLY_DONE: + + if (res->count == 0) { + DEBUG(7, ("Base search returned no results\n")); + return_done(cbctx); + break; + } + if (res->count > 1) { + DEBUG(0, ("Cache DB corrupted, base search returned %d results\n", + res->count)); + return_error(cbctx, EFAULT); + return LDB_ERR_OPERATIONS_ERROR; + } + + dn = ldb_dn_copy(del_ctx, res->msgs[0]->dn); + if (!dn) { + return_error(cbctx, ENOMEM); + return LDB_ERR_OPERATIONS_ERROR; + } + + talloc_free(res); + del_ctx->res = res = NULL; + + 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) { + return_error(cbctx, sysdb_error_to_errno(ret)); + return LDB_ERR_OPERATIONS_ERROR; + } + break; + + default: + return_error(cbctx, EINVAL); + return LDB_ERR_OPERATIONS_ERROR; + } + + talloc_free(rep); + return LDB_SUCCESS; +} + +int sysdb_delete_user_by_uid(struct sysdb_req *sysreq, + const char *domain, uid_t uid, + sysdb_callback_t fn, void *pvt) +{ + static const char *attrs[] = { SYSDB_PW_NAME, SYSDB_PW_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_req_check_running(sysreq)) { + DEBUG(2, ("Invalid request! Not running at this time.\n")); + return EINVAL; + } + + ctx = sysdb_req_get_ctx(sysreq); + + del_ctx = talloc_zero(sysreq, struct delete_ctx); + if (!del_ctx) return ENOMEM; + + del_ctx->cbctx = talloc_zero(del_ctx, struct sysdb_cb_ctx); + if (!del_ctx->cbctx) return ENOMEM; + + del_ctx->sysreq = sysreq; + 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, SYSDB_TMPL_USER_BASE, domain); + if (!base_dn) return ENOMEM; + + filter = talloc_asprintf(del_ctx, SYSDB_PWUID_FILTER, (unsigned long)uid); + if (!filter) return ENOMEM; + + 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 = ldb_request(ctx->ldb, req); + if (ret != LDB_SUCCESS) return sysdb_error_to_errno(ret); + + return EOK; +} + +int sysdb_delete_group_by_gid(struct sysdb_req *sysreq, + const char *domain, gid_t gid, + sysdb_callback_t fn, void *pvt) +{ + static const char *attrs[] = { SYSDB_GR_NAME, SYSDB_GR_GIDNUM, 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_req_check_running(sysreq)) { + DEBUG(2, ("Invalid request! Not running at this time.\n")); + return EINVAL; + } + + ctx = sysdb_req_get_ctx(sysreq); + + del_ctx = talloc_zero(sysreq, struct delete_ctx); + if (!del_ctx) return ENOMEM; + + del_ctx->cbctx = talloc_zero(del_ctx, struct sysdb_cb_ctx); + if (!del_ctx->cbctx) return ENOMEM; + + del_ctx->sysreq = sysreq; + 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, SYSDB_TMPL_GROUP_BASE, domain); + if (!base_dn) return ENOMEM; + + filter = talloc_asprintf(del_ctx, SYSDB_GRGID_FILTER, (unsigned long)gid); + if (!filter) return ENOMEM; + + 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 = ldb_request(ctx->ldb, req); + if (ret != LDB_SUCCESS) return sysdb_error_to_errno(ret); + + return EOK; +} + +/* "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 */ + +struct legacy_user_ctx { + struct sysdb_req *sysreq; + struct sysdb_cb_ctx *cbctx; + + struct ldb_dn *dn; + + const char *domain; + 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; +}; + +static int legacy_user_callback(struct ldb_request *req, + struct ldb_reply *rep); + +int sysdb_legacy_store_user(struct sysdb_req *sysreq, + const char *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 const char *attrs[] = { SYSDB_PW_NAME, NULL }; + struct legacy_user_ctx *user_ctx; + struct sysdb_ctx *ctx; + struct ldb_request *req; + int ret; + + if (!sysdb_req_check_running(sysreq)) { + DEBUG(2, ("Invalid request! Not running at this time.\n")); + return EINVAL; + } + + ctx = sysdb_req_get_ctx(sysreq); + + user_ctx = talloc(sysreq, 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; + + user_ctx->dn = sysdb_user_dn(ctx, user_ctx, domain, name); + if (!user_ctx->dn) return ENOMEM; + + user_ctx->sysreq = sysreq; + 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; + + 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); + } + + ret = ldb_request(ctx->ldb, req); + if (ret != LDB_SUCCESS) return sysdb_error_to_errno(ret); + + return EOK; +} + +static int legacy_user_callback(struct ldb_request *req, + struct ldb_reply *rep) +{ + struct legacy_user_ctx *user_ctx; + struct sysdb_cb_ctx *cbctx; + struct sysdb_ctx *ctx; + struct ldb_message *msg; + struct ldb_request *ureq; + struct ldb_result *res; + int flags; + int ret; + + user_ctx = talloc_get_type(req->context, struct legacy_user_ctx); + ctx = sysdb_req_get_ctx(user_ctx->sysreq); + cbctx = user_ctx->cbctx; + res = user_ctx->res; + + if (!rep) { + return_error(cbctx, EIO); + return LDB_ERR_OPERATIONS_ERROR; + } + if (rep->error != LDB_SUCCESS) { + return_error(cbctx, sysdb_error_to_errno(rep->error)); + return rep->error; + } + + switch (rep->type) { + case LDB_REPLY_ENTRY: + res->msgs = talloc_realloc(res, res->msgs, + struct ldb_message *, + res->count + 2); + if (!res->msgs) { + ret = LDB_ERR_OPERATIONS_ERROR; + return_error(cbctx, sysdb_error_to_errno(ret)); + return ret; + } + + 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_error(cbctx, ENOMEM); + return LDB_ERR_OPERATIONS_ERROR; + } + 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_error(cbctx, EFAULT); + return 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_error(cbctx, ENOMEM); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = add_string(msg, flags, SYSDB_PW_NAME, user_ctx->name); + if (ret != LDB_SUCCESS) { + return_error(cbctx, ENOMEM); + return LDB_ERR_OPERATIONS_ERROR; + } + } + + if (user_ctx->pwd && *user_ctx->pwd) { + ret = add_string(msg, flags, SYSDB_PW_PWD, user_ctx->pwd); + } else { + ret = ldb_msg_add_empty(msg, SYSDB_PW_PWD, + LDB_FLAG_MOD_DELETE, NULL); + } + if (ret != LDB_SUCCESS) { + return_error(cbctx, ENOMEM); + return LDB_ERR_OPERATIONS_ERROR; + } + + if (user_ctx->uid) { + ret = add_ulong(msg, flags, SYSDB_PW_UIDNUM, + (unsigned long)(user_ctx->uid)); + if (ret != LDB_SUCCESS) { + return_error(cbctx, ENOMEM); + return LDB_ERR_OPERATIONS_ERROR; + } + } else { + DEBUG(0, ("Cached users can't have UID == 0\n")); + return_error(cbctx, EINVAL); + return LDB_ERR_OPERATIONS_ERROR; + } + + if (user_ctx->gid) { + ret = add_ulong(msg, flags, SYSDB_PW_GIDNUM, + (unsigned long)(user_ctx->gid)); + if (ret != LDB_SUCCESS) { + return_error(cbctx, ENOMEM); + return LDB_ERR_OPERATIONS_ERROR; + } + } else { + DEBUG(0, ("Cached users can't have GID == 0\n")); + return_error(cbctx, EINVAL); + return LDB_ERR_OPERATIONS_ERROR; + } + + if (user_ctx->gecos && *user_ctx->gecos) { + ret = add_string(msg, flags, SYSDB_PW_FULLNAME, user_ctx->gecos); + } else { + ret = ldb_msg_add_empty(msg, SYSDB_PW_FULLNAME, + LDB_FLAG_MOD_DELETE, NULL); + } + if (ret != LDB_SUCCESS) { + return_error(cbctx, ENOMEM); + return LDB_ERR_OPERATIONS_ERROR; + } + + if (user_ctx->homedir && *user_ctx->homedir) { + ret = add_string(msg, flags, SYSDB_PW_HOMEDIR, user_ctx->homedir); + } else { + ret = ldb_msg_add_empty(msg, SYSDB_PW_HOMEDIR, + LDB_FLAG_MOD_DELETE, NULL); + } + if (ret != LDB_SUCCESS) { + return_error(cbctx, ENOMEM); + return LDB_ERR_OPERATIONS_ERROR; + } + + if (user_ctx->shell && *user_ctx->shell) { + ret = add_string(msg, flags, SYSDB_PW_SHELL, user_ctx->shell); + } else { + ret = ldb_msg_add_empty(msg, SYSDB_PW_SHELL, + LDB_FLAG_MOD_DELETE, NULL); + } + if (ret != LDB_SUCCESS) { + return_error(cbctx, ENOMEM); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* modification time */ + ret = add_ulong(msg, flags, SYSDB_LAST_UPDATE, + (unsigned long)time(NULL)); + if (ret != LDB_SUCCESS) { + return_error(cbctx, ENOMEM); + return LDB_ERR_OPERATIONS_ERROR; + } + + 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) { + return_error(cbctx, sysdb_error_to_errno(ret)); + return LDB_ERR_OPERATIONS_ERROR; + } + break; + + default: + return_error(cbctx, EINVAL); + return LDB_ERR_OPERATIONS_ERROR; + } + + talloc_free(rep); + return LDB_SUCCESS; +} + + + +/* this function does not check that all user members are actually present */ + +struct legacy_group_ctx { + struct sysdb_req *sysreq; + struct sysdb_cb_ctx *cbctx; + + struct ldb_dn *dn; + + const char *domain; + const char *name; + gid_t gid; + const char **members; + + struct ldb_result *res; +}; + +static int legacy_group_callback(struct ldb_request *req, + struct ldb_reply *rep); + +int sysdb_legacy_store_group(struct sysdb_req *sysreq, + const char *domain, + const char *name, gid_t gid, + const char **members, + sysdb_callback_t fn, void *pvt) +{ + static const char *attrs[] = { SYSDB_GR_NAME, NULL }; + struct legacy_group_ctx *group_ctx; + struct sysdb_ctx *ctx; + struct ldb_request *req; + int ret; + + if (!sysdb_req_check_running(sysreq)) { + DEBUG(2, ("Invalid request! Not running at this time.\n")); + return EINVAL; + } + + ctx = sysdb_req_get_ctx(sysreq); + + group_ctx = talloc(sysreq, struct legacy_group_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->dn = sysdb_group_dn(ctx, group_ctx, domain, name); + if (!group_ctx->dn) return ENOMEM; + + group_ctx->sysreq = sysreq; + 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; + + group_ctx->res = talloc_zero(group_ctx, struct ldb_result); + if (!group_ctx->res) return ENOMEM; + + 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); + } + + ret = ldb_request(ctx->ldb, req); + if (ret != LDB_SUCCESS) return sysdb_error_to_errno(ret); + + return EOK; +} + +static int legacy_group_callback(struct ldb_request *req, + struct ldb_reply *rep) +{ + 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; + + group_ctx = talloc_get_type(req->context, struct legacy_group_ctx); + ctx = sysdb_req_get_ctx(group_ctx->sysreq); + cbctx = group_ctx->cbctx; + res = group_ctx->res; + + if (!rep) { + return_error(cbctx, EIO); + return LDB_ERR_OPERATIONS_ERROR; + } + if (rep->error != LDB_SUCCESS) { + return_error(cbctx, sysdb_error_to_errno(rep->error)); + return rep->error; + } + + switch (rep->type) { + case LDB_REPLY_ENTRY: + res->msgs = talloc_realloc(res, res->msgs, + struct ldb_message *, + res->count + 2); + if (!res->msgs) { + ret = LDB_ERR_OPERATIONS_ERROR; + return_error(cbctx, sysdb_error_to_errno(ret)); + return ret; + } + + 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_error(cbctx, ENOMEM); + return 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_error(cbctx, EFAULT); + return LDB_ERR_OPERATIONS_ERROR; + } + + talloc_free(res); + group_ctx->res = res = NULL; + + if (flags == LDB_FLAG_MOD_ADD) { + ret = add_string(msg, flags, "objectClass", SYSDB_GROUP_CLASS); + if (ret != LDB_SUCCESS) { + return_error(cbctx, ENOMEM); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = add_string(msg, flags, SYSDB_GR_NAME, group_ctx->name); + if (ret != LDB_SUCCESS) { + return_error(cbctx, ENOMEM); + return LDB_ERR_OPERATIONS_ERROR; + } + } + + if (group_ctx->gid) { + ret = add_ulong(msg, flags, SYSDB_GR_GIDNUM, + (unsigned long)(group_ctx->gid)); + if (ret != LDB_SUCCESS) { + return_error(cbctx, ENOMEM); + return LDB_ERR_OPERATIONS_ERROR; + } + } else { + DEBUG(0, ("Cached groups can't have GID == 0\n")); + return_error(cbctx, EINVAL); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* 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_error(cbctx, ENOMEM); + return 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_error(cbctx, ENOMEM); + return LDB_ERR_OPERATIONS_ERROR; + } + } + } + + /* modification time */ + ret = add_ulong(msg, flags, SYSDB_LAST_UPDATE, + (unsigned long)time(NULL)); + if (ret != LDB_SUCCESS) { + return_error(cbctx, ENOMEM); + return LDB_ERR_OPERATIONS_ERROR; + } + + 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); + } + if (ret != LDB_SUCCESS) { + return_error(cbctx, sysdb_error_to_errno(ret)); + return LDB_ERR_OPERATIONS_ERROR; + } + break; + + default: + return_error(cbctx, EINVAL); + return LDB_ERR_OPERATIONS_ERROR; + } + + talloc_free(rep); + return LDB_SUCCESS; +} + diff --git a/server/db/sysdb_private.h b/server/db/sysdb_private.h index c649af4aa..35cafb0d7 100644 --- a/server/db/sysdb_private.h +++ b/server/db/sysdb_private.h @@ -78,18 +78,8 @@ struct sysdb_ctx { struct sysdb_req *queue; }; -typedef void (*sysdb_req_fn_t)(struct sysdb_req *, void *pvt); - int sysdb_error_to_errno(int ldberr); -int sysdb_transaction(TALLOC_CTX *mem_ctx, - struct sysdb_ctx *ctx, - sysdb_req_fn_t fn, void *pvt); -void sysdb_transaction_done(struct sysdb_req *req, int status); - -int sysdb_operation(TALLOC_CTX *mem_ctx, - struct sysdb_ctx *ctx, - sysdb_req_fn_t fn, void *pvt); -void sysdb_operation_done(struct sysdb_req *req); +bool sysdb_req_check_running(struct sysdb_req *req); #endif /* __INT_SYS_DB_H__ */ diff --git a/server/db/sysdb_req.c b/server/db/sysdb_req.c index fcbd17b88..161431cc9 100644 --- a/server/db/sysdb_req.c +++ b/server/db/sysdb_req.c @@ -34,6 +34,17 @@ struct sysdb_req { bool transaction_active; }; +bool sysdb_req_check_running(struct sysdb_req *req) +{ + if (req->ctx->queue == req) return true; + return false; +} + +struct sysdb_ctx *sysdb_req_get_ctx(struct sysdb_req *req) +{ + return req->ctx; +} + static void sysdb_req_run(struct tevent_context *ev, struct tevent_timer *te, struct timeval tv, void *ptr) diff --git a/server/db/sysdb_search.c b/server/db/sysdb_search.c index 5a355a0f2..bb71079b8 100644 --- a/server/db/sysdb_search.c +++ b/server/db/sysdb_search.c @@ -102,7 +102,7 @@ static void request_done(struct sysdb_search_ctx *sctx) } static int get_gen_callback(struct ldb_request *req, - struct ldb_reply *ares) + struct ldb_reply *rep) { struct sysdb_search_ctx *sctx; struct ldb_result *res; @@ -111,16 +111,16 @@ static int get_gen_callback(struct ldb_request *req, sctx = talloc_get_type(req->context, struct sysdb_search_ctx); res = sctx->res; - if (!ares) { + if (!rep) { request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR); return LDB_ERR_OPERATIONS_ERROR; } - if (ares->error != LDB_SUCCESS) { - request_ldberror(sctx, ares->error); - return ares->error; + if (rep->error != LDB_SUCCESS) { + request_ldberror(sctx, rep->error); + return rep->error; } - switch (ares->type) { + switch (rep->type) { case LDB_REPLY_ENTRY: res->msgs = talloc_realloc(res, res->msgs, struct ldb_message *, @@ -132,7 +132,7 @@ static int get_gen_callback(struct ldb_request *req, res->msgs[res->count + 1] = NULL; - res->msgs[res->count] = talloc_steal(res->msgs, ares->message); + res->msgs[res->count] = talloc_steal(res->msgs, rep->message); res->count++; break; @@ -149,12 +149,12 @@ static int get_gen_callback(struct ldb_request *req, return LDB_ERR_OPERATIONS_ERROR; } - res->refs[n] = talloc_steal(res->refs, ares->referral); + res->refs[n] = talloc_steal(res->refs, rep->referral); res->refs[n + 1] = NULL; break; case LDB_REPLY_DONE: - res->controls = talloc_steal(res, ares->controls); + res->controls = talloc_steal(res, rep->controls); /* check if we need to call any aux function */ if (sctx->gen_aux_fn) { @@ -166,7 +166,7 @@ static int get_gen_callback(struct ldb_request *req, return LDB_SUCCESS; } - talloc_free(ares); + talloc_free(rep); return LDB_SUCCESS; } @@ -351,7 +351,7 @@ static void get_members(struct sysdb_search_ctx *sctx) } static int get_grp_callback(struct ldb_request *req, - struct ldb_reply *ares) + struct ldb_reply *rep) { struct sysdb_search_ctx *sctx; struct sysdb_ctx *ctx; @@ -362,16 +362,16 @@ static int get_grp_callback(struct ldb_request *req, ctx = sctx->ctx; res = sctx->res; - if (!ares) { + if (!rep) { request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR); return LDB_ERR_OPERATIONS_ERROR; } - if (ares->error != LDB_SUCCESS) { - request_ldberror(sctx, ares->error); - return ares->error; + if (rep->error != LDB_SUCCESS) { + request_ldberror(sctx, rep->error); + return rep->error; } - switch (ares->type) { + switch (rep->type) { case LDB_REPLY_ENTRY: res->msgs = talloc_realloc(res, res->msgs, struct ldb_message *, @@ -383,7 +383,7 @@ static int get_grp_callback(struct ldb_request *req, res->msgs[res->count + 1] = NULL; - res->msgs[res->count] = talloc_steal(res->msgs, ares->message); + res->msgs[res->count] = talloc_steal(res->msgs, rep->message); res->count++; break; @@ -400,12 +400,12 @@ static int get_grp_callback(struct ldb_request *req, return LDB_ERR_OPERATIONS_ERROR; } - res->refs[n] = talloc_steal(res->refs, ares->referral); + res->refs[n] = talloc_steal(res->refs, rep->referral); res->refs[n + 1] = NULL; break; case LDB_REPLY_DONE: - res->controls = talloc_steal(res, ares->controls); + res->controls = talloc_steal(res, rep->controls); /* no results, return */ if (res->count == 0) { @@ -434,7 +434,7 @@ static int get_grp_callback(struct ldb_request *req, return LDB_ERR_OPERATIONS_ERROR; } - talloc_free(ares); + talloc_free(rep); return LDB_SUCCESS; } diff --git a/server/db/sysdb_sync.c b/server/db/sysdb_sync.c deleted file mode 100644 index 1910e9fcf..000000000 --- a/server/db/sysdb_sync.c +++ /dev/null @@ -1,880 +0,0 @@ -/* - SSSD - - System Database - - Copyright (C) Simo Sorce <ssorce@redhat.com> 2008 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "util/util.h" -#include "db/sysdb_private.h" -#include <time.h> - -/* the following are all SYNCHRONOUS calls - * TODO: make these asynchronous */ - -int sysdb_add_group_member(TALLOC_CTX *mem_ctx, - struct sysdb_ctx *sysdb, - struct ldb_dn *member_dn, - struct ldb_dn *group_dn) -{ - TALLOC_CTX *tmp_ctx; - int ret, lret; - struct ldb_message *msg; - - tmp_ctx = talloc_new(mem_ctx); - if (!tmp_ctx) return ENOMEM; - - /* Add the member_dn as a member of the group */ - msg = ldb_msg_new(tmp_ctx); - if(msg == NULL) { - ret = ENOMEM; - goto done; - } - msg->dn = group_dn; - lret = ldb_msg_add_empty(msg, SYSDB_GR_MEMBER, - LDB_FLAG_MOD_ADD, NULL); - if (lret != LDB_SUCCESS) { - ret = ENOMEM; - goto done; - } - lret = ldb_msg_add_fmt(msg, SYSDB_GR_MEMBER, "%s", - ldb_dn_get_linearized(member_dn)); - if (lret != LDB_SUCCESS) { - ret = EINVAL; - goto done; - } - - lret = ldb_modify(sysdb->ldb, msg); - if (lret != LDB_SUCCESS) { - DEBUG(1, ("Failed to make modify request: %s(%d)[%s]\n", - ldb_strerror(lret), lret, ldb_errstring(sysdb->ldb))); - ret = EIO; - goto done; - } - - ret = EOK; - -done: - talloc_free(tmp_ctx); - return ret; -} - -int sysdb_remove_group_member(TALLOC_CTX *mem_ctx, - struct sysdb_ctx *sysdb, - struct ldb_dn *member_dn, - struct ldb_dn *group_dn) -{ - TALLOC_CTX *tmp_ctx; - int ret, lret; - struct ldb_message *msg; - - tmp_ctx = talloc_new(mem_ctx); - if (!tmp_ctx) return ENOMEM; - - /* Add the member_dn as a member of the group */ - msg = ldb_msg_new(tmp_ctx); - if(msg == NULL) { - ret = ENOMEM; - goto done; - } - msg->dn = group_dn; - lret = ldb_msg_add_empty(msg, SYSDB_GR_MEMBER, - LDB_FLAG_MOD_DELETE, NULL); - if (lret != LDB_SUCCESS) { - ret = ENOMEM; - goto done; - } - lret = ldb_msg_add_fmt(msg, SYSDB_GR_MEMBER, "%s", - ldb_dn_get_linearized(member_dn)); - if (lret != LDB_SUCCESS) { - ret = EINVAL; - goto done; - } - - lret = ldb_modify(sysdb->ldb, msg); - if (lret != LDB_SUCCESS) { - DEBUG(1, ("Failed to make modify request: %s(%d)[%s]\n", - ldb_strerror(lret), lret, ldb_errstring(sysdb->ldb))); - ret = EIO; - goto done; - } - - ret = EOK; - -done: - talloc_free(tmp_ctx); - return ret; -} - -/* "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 */ - -int sysdb_legacy_store_user(TALLOC_CTX *memctx, - struct sysdb_ctx *sysdb, - const char *domain, - const char *name, const char *pwd, - uid_t uid, gid_t gid, const char *gecos, - const char *homedir, const char *shell) -{ - TALLOC_CTX *tmp_ctx; - const char *attrs[] = { SYSDB_PW_NAME, NULL }; - struct ldb_dn *user_dn; - struct ldb_message *msg; - struct ldb_request *req; - struct ldb_result *res; - int lret, ret; - int flags; - - tmp_ctx = talloc_new(memctx); - if (!tmp_ctx) { - return ENOMEM; - } - - user_dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, - SYSDB_PW_NAME"=%s,"SYSDB_TMPL_USER_BASE, - name, domain); - if (!user_dn) { - talloc_free(tmp_ctx); - return ENOMEM; - } - - lret = ldb_transaction_start(sysdb->ldb); - if (lret != LDB_SUCCESS) { - DEBUG(1, ("Failed ldb transaction start !? (%d)\n", lret)); - ret = EIO; - goto done; - } - - lret = ldb_search(sysdb->ldb, tmp_ctx, &res, user_dn, - LDB_SCOPE_BASE, attrs, SYSDB_PWENT_FILTER); - if (lret != LDB_SUCCESS) { - DEBUG(1, ("Failed to make search request: %s(%d)[%s]\n", - ldb_strerror(lret), lret, ldb_errstring(sysdb->ldb))); - ret = EIO; - goto done; - } - - req = NULL; - - msg = ldb_msg_new(tmp_ctx); - if (!msg) { - ret = ENOMEM; - goto done; - } - msg->dn = user_dn; - - switch (res->count) { - case 0: - flags = LDB_FLAG_MOD_ADD; - break; - case 1: - flags = LDB_FLAG_MOD_REPLACE; - break; - default: - DEBUG(0, ("Cache DB corrupted, base search returned %d results\n", - res->count)); - ret = EIO; - goto done; - } - - talloc_free(res); - res = NULL; - - if (flags == LDB_FLAG_MOD_ADD) { - /* TODO: retrieve user objectclass list from configuration */ - lret = ldb_msg_add_empty(msg, "objectClass", flags, NULL); - if (lret == LDB_SUCCESS) { - lret = ldb_msg_add_string(msg, "objectClass", "user"); - } - if (lret != LDB_SUCCESS) { - ret = ENOMEM; - goto done; - } - - /* TODO: retrieve user name attribute from configuration */ - lret = ldb_msg_add_empty(msg, SYSDB_PW_NAME, flags, NULL); - if (lret == LDB_SUCCESS) { - lret = ldb_msg_add_string(msg, SYSDB_PW_NAME, name); - } - if (lret != LDB_SUCCESS) { - ret = ENOMEM; - goto done; - } - } - - /* TODO: retrieve attribute name mappings from configuration */ - - /* pwd */ - if (pwd && *pwd) { - lret = ldb_msg_add_empty(msg, SYSDB_PW_PWD, flags, NULL); - if (lret == LDB_SUCCESS) { - lret = ldb_msg_add_string(msg, SYSDB_PW_PWD, pwd); - } - } else { - lret = ldb_msg_add_empty(msg, SYSDB_PW_PWD, - LDB_FLAG_MOD_DELETE, NULL); - } - if (lret != LDB_SUCCESS) { - ret = ENOMEM; - goto done; - } - - /* uid */ - if (uid) { - lret = ldb_msg_add_empty(msg, SYSDB_PW_UIDNUM, flags, NULL); - if (lret == LDB_SUCCESS) { - lret = ldb_msg_add_fmt(msg, SYSDB_PW_UIDNUM, - "%lu", (unsigned long)uid); - } - if (lret != LDB_SUCCESS) { - ret = ENOMEM; - goto done; - } - } else { - DEBUG(0, ("Cached users can't have UID == 0\n")); - ret = EINVAL; - goto done; - } - - /* gid */ - if (gid) { - lret = ldb_msg_add_empty(msg, SYSDB_PW_GIDNUM, flags, NULL); - if (lret == LDB_SUCCESS) { - lret = ldb_msg_add_fmt(msg, SYSDB_PW_GIDNUM, - "%lu", (unsigned long)gid); - } - if (lret != LDB_SUCCESS) { - ret = ENOMEM; - goto done; - } - } else { - DEBUG(0, ("Cached users can't have GID == 0\n")); - ret = EINVAL; - goto done; - } - - /* gecos */ - if (gecos && *gecos) { - lret = ldb_msg_add_empty(msg, SYSDB_PW_FULLNAME, flags, NULL); - if (lret == LDB_SUCCESS) { - lret = ldb_msg_add_string(msg, SYSDB_PW_FULLNAME, gecos); - } - } else { - lret = ldb_msg_add_empty(msg, SYSDB_PW_FULLNAME, - LDB_FLAG_MOD_DELETE, NULL); - } - if (lret != LDB_SUCCESS) { - ret = ENOMEM; - goto done; - } - - /* homedir */ - if (homedir && *homedir) { - lret = ldb_msg_add_empty(msg, SYSDB_PW_HOMEDIR, flags, NULL); - if (lret == LDB_SUCCESS) { - lret = ldb_msg_add_string(msg, SYSDB_PW_HOMEDIR, homedir); - } - } else { - lret = ldb_msg_add_empty(msg, SYSDB_PW_HOMEDIR, - LDB_FLAG_MOD_DELETE, NULL); - } - if (lret != LDB_SUCCESS) { - ret = ENOMEM; - goto done; - } - - /* shell */ - if (shell && *shell) { - lret = ldb_msg_add_empty(msg, SYSDB_PW_SHELL, flags, NULL); - if (lret == LDB_SUCCESS) { - lret = ldb_msg_add_string(msg, SYSDB_PW_SHELL, shell); - } - } else { - lret = ldb_msg_add_empty(msg, SYSDB_PW_SHELL, - LDB_FLAG_MOD_DELETE, NULL); - } - if (lret != LDB_SUCCESS) { - ret = ENOMEM; - goto done; - } - - /* modification time */ - lret = ldb_msg_add_empty(msg, SYSDB_LAST_UPDATE, flags, NULL); - if (lret == LDB_SUCCESS) { - lret = ldb_msg_add_fmt(msg, SYSDB_LAST_UPDATE, - "%ld", (long int)time(NULL)); - } - if (lret != LDB_SUCCESS) { - ret = ENOMEM; - goto done; - } - - if (flags == LDB_FLAG_MOD_ADD) { - lret = ldb_build_add_req(&req, sysdb->ldb, tmp_ctx, msg, NULL, - NULL, ldb_op_default_callback, NULL); - } else { - lret = ldb_build_mod_req(&req, sysdb->ldb, tmp_ctx, msg, NULL, - NULL, ldb_op_default_callback, NULL); - } - if (lret == LDB_SUCCESS) { - lret = ldb_request(sysdb->ldb, req); - if (lret == LDB_SUCCESS) { - lret = ldb_wait(req->handle, LDB_WAIT_ALL); - } - } - if (lret != LDB_SUCCESS) { - DEBUG(1, ("Failed to make modify request: %s(%d)[%s]\n", - ldb_strerror(lret), lret, ldb_errstring(sysdb->ldb))); - ret = EIO; - goto done; - } - - ret = EOK; - -done: - if (ret == EOK) { - lret = ldb_transaction_commit(sysdb->ldb); - if (lret != LDB_SUCCESS) { - DEBUG(1, ("Failed ldb transaction start !? (%d)\n", lret)); - ret = EIO; - } - } else { - lret = ldb_transaction_cancel(sysdb->ldb); - if (lret != LDB_SUCCESS) { - DEBUG(1, ("Failed to cancel ldb transaction (%d)\n", lret)); - ret = EIO; - } - } - - talloc_free(tmp_ctx); - return ret; -} - -int sysdb_delete_user(TALLOC_CTX *memctx, - struct sysdb_ctx *sysdb, - const char *domain, const char *name) -{ - TALLOC_CTX *tmp_ctx; - struct ldb_dn *user_dn; - int lret, ret = EOK; - - tmp_ctx = talloc_new(memctx); - if (!tmp_ctx) { - return ENOMEM; - } - - user_dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, - SYSDB_PW_NAME"=%s,"SYSDB_TMPL_USER_BASE, - name, domain); - if (!user_dn) { - talloc_free(tmp_ctx); - return ENOMEM; - } - - lret = ldb_delete(sysdb->ldb, user_dn); - - if (lret != LDB_SUCCESS && lret != LDB_ERR_NO_SUCH_OBJECT) { - DEBUG(2, ("LDB Error: %s(%d)\nError Message: [%s]\n", - ldb_strerror(ret), ret, ldb_errstring(sysdb->ldb))); - ret = EIO; - } - - talloc_free(tmp_ctx); - return ret; -} - -int sysdb_delete_user_by_uid(TALLOC_CTX *memctx, - struct sysdb_ctx *sysdb, - const char *domain, uid_t uid) -{ - TALLOC_CTX *tmp_ctx; - const char *attrs[] = { SYSDB_PW_NAME, SYSDB_PW_UIDNUM, NULL }; - struct ldb_dn *base_dn; - struct ldb_dn *user_dn; - struct ldb_result *res; - int lret, ret; - - tmp_ctx = talloc_new(memctx); - if (!tmp_ctx) { - return ENOMEM; - } - - base_dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, - SYSDB_TMPL_USER_BASE, domain); - if (!base_dn) { - talloc_free(tmp_ctx); - return ENOMEM; - } - - lret = ldb_transaction_start(sysdb->ldb); - if (lret != LDB_SUCCESS) { - DEBUG(1, ("Failed ldb transaction start !? (%d)\n", lret)); - ret = EIO; - goto done; - } - - lret = ldb_search(sysdb->ldb, tmp_ctx, &res, base_dn, - LDB_SCOPE_ONELEVEL, attrs, - SYSDB_PWUID_FILTER, - (unsigned long)uid); - if (lret != LDB_SUCCESS) { - DEBUG(1, ("Failed to make search request: %s(%d)[%s]\n", - ldb_strerror(lret), lret, ldb_errstring(sysdb->ldb))); - ret = EIO; - goto done; - } - - if (res->count == 0) { - DEBUG(7, ("Base search returned no results\n")); - ret = EOK; - goto done; - } - if (res->count > 1) { - DEBUG(0, ("Cache DB corrupted, base search returned %d results\n", - res->count)); - ret = EIO; - goto done; - } - - user_dn = ldb_dn_copy(tmp_ctx, res->msgs[0]->dn); - if (!user_dn) { - ret = ENOMEM; - goto done; - } - - talloc_free(res); - res = NULL; - - lret = ldb_delete(sysdb->ldb, user_dn); - - if (lret != LDB_SUCCESS && lret != LDB_ERR_NO_SUCH_OBJECT) { - DEBUG(2, ("LDB Error: %s(%d)\nError Message: [%s]\n", - ldb_strerror(ret), ret, ldb_errstring(sysdb->ldb))); - ret = EIO; - goto done; - } - - ret = EOK; - -done: - if (ret == EOK) { - lret = ldb_transaction_commit(sysdb->ldb); - if (lret != LDB_SUCCESS) { - DEBUG(1, ("Failed ldb transaction commit !! (%d)\n", lret)); - ret = EIO; - } - } else { - lret = ldb_transaction_cancel(sysdb->ldb); - if (lret != LDB_SUCCESS) { - DEBUG(1, ("Failed to cancel ldb transaction (%d)\n", lret)); - ret = EIO; - } - } - - talloc_free(tmp_ctx); - return ret; -} - -/* this function does not check that all user members are actually present */ - -int sysdb_legacy_store_group(TALLOC_CTX *memctx, - struct sysdb_ctx *sysdb, - const char *domain, - const char *name, gid_t gid, - char **members) -{ - TALLOC_CTX *tmp_ctx; - const char *attrs[] = { SYSDB_GR_NAME, NULL }; - struct ldb_dn *group_dn; - struct ldb_result *res; - struct ldb_message *msg; - int i, ret, lret; - int flags; - - tmp_ctx = talloc_new(memctx); - if (tmp_ctx == NULL) { - return ENOMEM; - } - - group_dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, - SYSDB_GR_NAME"=%s,"SYSDB_TMPL_GROUP_BASE, - name, domain); - if (group_dn == NULL) { - talloc_free(tmp_ctx); - return ENOMEM; - } - - /* Start a transaction to ensure that nothing changes - * underneath us while we're working - */ - lret = ldb_transaction_start(sysdb->ldb); - if (lret != LDB_SUCCESS) { - DEBUG(1, ("Failed ldb transaction start !? (%d)\n", lret)); - talloc_free(tmp_ctx); - return EIO; - } - - /* Determine if the group already exists */ - lret = ldb_search(sysdb->ldb, tmp_ctx, &res, group_dn, - LDB_SCOPE_BASE, attrs, SYSDB_GRENT_FILTER); - if (lret != LDB_SUCCESS) { - DEBUG(1, ("Failed to make search request: %s(%d)[%s]\b", - ldb_strerror(lret), lret, ldb_errstring(sysdb->ldb))); - ret = EIO; - goto done; - } - - switch(res->count) { - case 0: - flags = LDB_FLAG_MOD_ADD; - DEBUG(7, ("Adding new entry\n")); - break; - case 1: - flags = LDB_FLAG_MOD_REPLACE; - DEBUG(7, ("Replacing existing entry\n")); - break; - default: - DEBUG(0, ("Cache DB corrupted, base search returned %d results\n", - res->count)); - ret = EIO; - goto done; - } - talloc_free(res); - res = NULL; - - /* Set up the add/replace request */ - msg = ldb_msg_new(tmp_ctx); - if (msg == NULL) { - ret = ENOMEM; - goto done; - } - msg->dn = group_dn; - - if (flags == LDB_FLAG_MOD_ADD) { - lret = ldb_msg_add_empty(msg, "objectClass", flags, NULL); - if (lret == LDB_SUCCESS) { - lret = ldb_msg_add_string(msg, "objectClass", "group"); - } - if (lret != LDB_SUCCESS) { - ret = ENOMEM; - goto done; - } - - lret = ldb_msg_add_empty(msg, SYSDB_GR_NAME, flags, NULL); - if (lret == LDB_SUCCESS) { - lret = ldb_msg_add_string(msg, SYSDB_GR_NAME, name); - } - if (lret != LDB_SUCCESS) { - ret = ENOMEM; - goto done; - } - } - - /* gid */ - if (gid) { - lret = ldb_msg_add_empty(msg, SYSDB_GR_GIDNUM, flags, NULL); - if (lret == LDB_SUCCESS) { - lret = ldb_msg_add_fmt(msg, SYSDB_GR_GIDNUM, - "%lu", (unsigned long)gid); - } - if (lret != LDB_SUCCESS) { - ret = ENOMEM; - goto done; - } - } else { - DEBUG(0, ("Cached groups can't have GID == 0\n")); - ret = EINVAL; - goto done; - } - - /* modification time */ - lret = ldb_msg_add_empty(msg, SYSDB_LAST_UPDATE, flags, NULL); - if (lret == LDB_SUCCESS) { - lret = ldb_msg_add_fmt(msg, SYSDB_LAST_UPDATE, - "%ld", (long int)time(NULL)); - } - if (lret != LDB_SUCCESS) { - ret = ENOMEM; - goto done; - } - - /* members */ - if (members && members[0]) { - lret = ldb_msg_add_empty(msg, SYSDB_LEGACY_MEMBER, flags, NULL); - if (lret != LDB_SUCCESS) { - ret = ENOMEM; - goto done; - } - for (i = 0; members[i]; i++) { - lret = ldb_msg_add_string(msg, SYSDB_LEGACY_MEMBER, members[i]); - if (lret != LDB_SUCCESS) { - ret = ENOMEM; - goto done; - } - } - } - - if (flags == LDB_FLAG_MOD_ADD) { - lret = ldb_add(sysdb->ldb, msg); - } else { - lret = ldb_modify(sysdb->ldb, msg); - } - if (lret != LDB_SUCCESS) { - DEBUG(1, ("Failed to make modify request: %s(%d)[%s]\n", - ldb_strerror(lret), lret, ldb_errstring(sysdb->ldb))); - ret = EIO; - goto done; - } - - ret = EOK; - -done: - if (ret == EOK) { - lret = ldb_transaction_commit(sysdb->ldb); - if (lret != LDB_SUCCESS) { - DEBUG(1, ("Failed ldb transaction start !? (%d)\n", lret)); - ret = EIO; - } - } else { - lret = ldb_transaction_cancel(sysdb->ldb); - if (lret != LDB_SUCCESS) { - DEBUG(1, ("Failed to cancel ldb transaction (%d)\n", lret)); - ret = EIO; - } - } - talloc_free(tmp_ctx); - return ret; -} - -/* Wrapper around adding a user to a POSIX group */ -int sysdb_add_user_to_group(TALLOC_CTX *mem_ctx, - struct sysdb_ctx *sysdb, - const char *domain, - const char *group, - const char *username) -{ - TALLOC_CTX *tmp_ctx; - int ret; - struct ldb_dn *user_dn; - struct ldb_dn *group_dn; - - - if (!sysdb || !domain || !group || !username) { - return EINVAL; - } - - tmp_ctx = talloc_new(mem_ctx); - if (tmp_ctx == NULL) { - return ENOMEM; - } - - user_dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, - SYSDB_PW_NAME"=%s,"SYSDB_TMPL_USER_BASE, - username, domain); - if (!user_dn) { - ret = ENOMEM; - goto done; - } - - group_dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, - SYSDB_GR_NAME"=%s,"SYSDB_TMPL_GROUP_BASE, - group, domain); - if (group_dn == NULL) { - ret = ENOMEM; - goto done; - } - - ret = sysdb_add_group_member(tmp_ctx, sysdb, user_dn, group_dn); - -done: - talloc_free(tmp_ctx); - return ret; -} - -/* Wrapper around adding a user to a POSIX group */ -int sysdb_remove_user_from_group(TALLOC_CTX *mem_ctx, - struct sysdb_ctx *sysdb, - const char *domain, - const char *group, - const char *username) -{ - TALLOC_CTX *tmp_ctx; - int ret; - struct ldb_dn *user_dn; - struct ldb_dn *group_dn; - - - if (!sysdb || !domain || !group || !username) { - return EINVAL; - } - - tmp_ctx = talloc_new(mem_ctx); - if (tmp_ctx == NULL) { - return ENOMEM; - } - - user_dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, - SYSDB_PW_NAME"=%s,"SYSDB_TMPL_USER_BASE, - username, domain); - if (!user_dn) { - ret = ENOMEM; - goto done; - } - - group_dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, - SYSDB_GR_NAME"=%s,"SYSDB_TMPL_GROUP_BASE, - group, domain); - if (group_dn == NULL) { - ret = ENOMEM; - goto done; - } - - ret = sysdb_remove_group_member(tmp_ctx, sysdb, user_dn, group_dn); - -done: - talloc_free(tmp_ctx); - return ret; -} - -int sysdb_delete_group(TALLOC_CTX *memctx, - struct sysdb_ctx *sysdb, - const char *domain, const char *name) -{ - TALLOC_CTX *tmp_ctx; - struct ldb_dn *group_dn; - int lret, ret = EOK; - - tmp_ctx = talloc_new(memctx); - if (!tmp_ctx) { - return ENOMEM; - } - - group_dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, - SYSDB_GR_NAME"=%s,"SYSDB_TMPL_GROUP_BASE, - name, domain); - if (!group_dn) { - talloc_free(tmp_ctx); - return ENOMEM; - } - - lret = ldb_delete(sysdb->ldb, group_dn); - - if (lret != LDB_SUCCESS && lret != LDB_ERR_NO_SUCH_OBJECT) { - DEBUG(2, ("LDB Error: %s(%d)\nError Message: [%s]\n", - ldb_strerror(ret), ret, ldb_errstring(sysdb->ldb))); - ret = EIO; - } - - talloc_free(tmp_ctx); - return ret; -} - -int sysdb_delete_group_by_gid(TALLOC_CTX *memctx, - struct sysdb_ctx *sysdb, - const char *domain, gid_t gid) -{ - TALLOC_CTX *tmp_ctx; - const char *attrs[] = { SYSDB_GR_NAME, SYSDB_GR_GIDNUM, NULL }; - struct ldb_dn *base_dn; - struct ldb_dn *group_dn; - struct ldb_result *res; - int lret, ret; - - tmp_ctx = talloc_new(memctx); - if (!tmp_ctx) { - return ENOMEM; - } - - base_dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, - SYSDB_TMPL_GROUP_BASE, domain); - if (!base_dn) { - talloc_free(tmp_ctx); - return ENOMEM; - } - - lret = ldb_transaction_start(sysdb->ldb); - if (lret != LDB_SUCCESS) { - DEBUG(1, ("Failed ldb transaction start !? (%d)\n", lret)); - ret = EIO; - goto done; - } - - lret = ldb_search(sysdb->ldb, tmp_ctx, &res, base_dn, - LDB_SCOPE_ONELEVEL, attrs, - SYSDB_GRGID_FILTER, - (unsigned long)gid); - if (lret != LDB_SUCCESS) { - DEBUG(1, ("Failed to make search request: %s(%d)[%s]\n", - ldb_strerror(lret), lret, ldb_errstring(sysdb->ldb))); - ret = EIO; - goto done; - } - - if (res->count == 0) { - DEBUG(7, ("Base search returned no results\n")); - ret = EOK; - goto done; - } - if (res->count > 1) { - DEBUG(0, ("Cache DB corrupted, base search returned %d results\n", - res->count)); - ret = EIO; - goto done; - } - - group_dn = ldb_dn_copy(tmp_ctx, res->msgs[0]->dn); - if (!group_dn) { - ret = ENOMEM; - goto done; - } - - talloc_free(res); - res = NULL; - - lret = ldb_delete(sysdb->ldb, group_dn); - - if (lret != LDB_SUCCESS && lret != LDB_ERR_NO_SUCH_OBJECT) { - DEBUG(2, ("LDB Error: %s(%d)\nError Message: [%s]\n", - ldb_strerror(ret), ret, ldb_errstring(sysdb->ldb))); - ret = EIO; - goto done; - } - - ret = EOK; - -done: - if (ret == EOK) { - lret = ldb_transaction_commit(sysdb->ldb); - if (lret != LDB_SUCCESS) { - DEBUG(1, ("Failed ldb transaction commit !! (%d)\n", lret)); - ret = EIO; - } - } else { - lret = ldb_transaction_cancel(sysdb->ldb); - if (lret != LDB_SUCCESS) { - DEBUG(1, ("Failed to cancel ldb transaction (%d)\n", lret)); - ret = EIO; - } - } - - talloc_free(tmp_ctx); - return ret; -} - diff --git a/server/providers/proxy.c b/server/providers/proxy.c index 3c39c8f87..30f5f5c19 100644 --- a/server/providers/proxy.c +++ b/server/providers/proxy.c @@ -61,105 +61,6 @@ struct proxy_ctx { struct proxy_nss_ops ops; }; -static void proxy_reply(struct be_req *req, int error, const char *errstr) -{ - return req->fn(req, error, errstr); -} - -static void get_pw_name(struct be_req *req, char *name) -{ - struct proxy_ctx *ctx; - enum nss_status status; - struct passwd result; - char *buffer; - int ret; - - ctx = talloc_get_type(req->be_ctx->pvt_data, struct proxy_ctx); - - buffer = talloc_size(req, 4096); - if (!buffer) - return proxy_reply(req, ENOMEM, "Out of memory"); - - status = ctx->ops.getpwnam_r(name, &result, buffer, 4096, &ret); - - switch (status) { - case NSS_STATUS_NOTFOUND: - ret = sysdb_delete_user(req, req->be_ctx->sysdb, - req->be_ctx->domain, name); - break; - case NSS_STATUS_SUCCESS: - ret = sysdb_legacy_store_user(req, req->be_ctx->sysdb, - req->be_ctx->domain, - result.pw_name, result.pw_passwd, - result.pw_uid, result.pw_gid, - result.pw_gecos, result.pw_dir, - result.pw_shell); - break; - default: - DEBUG(2, ("proxy -> getpwnam_r failed for '%s' (%d)[%s]\n", - name, ret, strerror(ret))); - talloc_free(buffer); - return proxy_reply(req, ret, "Operation failed"); - } - - if (ret != EOK) { - DEBUG(1, ("Failed to update LDB Cache for '%s' (%d) !?\n", - name, ret)); - talloc_free(buffer); - return proxy_reply(req, ret, "Operation failed"); - } - - talloc_free(buffer); - return proxy_reply(req, EOK, NULL); -} - -static void get_pw_uid(struct be_req *req, uid_t uid) -{ - struct proxy_ctx *ctx; - enum nss_status status; - struct passwd result; - char *buffer; - int ret; - - ctx = talloc_get_type(req->be_ctx->pvt_data, struct proxy_ctx); - - buffer = talloc_size(req, 4096); - if (!buffer) - return proxy_reply(req, ENOMEM, "Out of memory"); - - status = ctx->ops.getpwuid_r(uid, &result, buffer, 4096, &ret); - - switch (status) { - case NSS_STATUS_NOTFOUND: - ret = sysdb_delete_user_by_uid(req, req->be_ctx->sysdb, - req->be_ctx->domain,uid); - break; - case NSS_STATUS_SUCCESS: - ret = sysdb_legacy_store_user(req, req->be_ctx->sysdb, - req->be_ctx->domain, - result.pw_name, result.pw_passwd, - result.pw_uid, result.pw_gid, - result.pw_gecos, result.pw_dir, - result.pw_shell); - break; - default: - DEBUG(2, ("proxy -> getpwuid_r failed for '%lu' (%d)[%s]\n", - (unsigned long)uid, ret, strerror(ret))); - talloc_free(buffer); - return proxy_reply(req, ret, "Operation failed"); - } - - if (ret != EOK) { - DEBUG(1, ("Failed to update LDB Cache for '%lu' (%d) !?\n", - (unsigned long)uid, ret)); - talloc_free(buffer); - return proxy_reply(req, ret, "Operation failed"); - } - - talloc_free(buffer); - return proxy_reply(req, EOK, NULL); -} - struct authtok_conv { char *authtok; char *oldauthtok; @@ -284,395 +185,754 @@ static void proxy_pam_handler(struct be_req *req) { req->fn(req, EOK, NULL); } +static void proxy_reply(struct be_req *req, int error, const char *errstr) +{ + return req->fn(req, error, errstr); +} + +struct proxy_data { + struct sysdb_req *sysreq; + struct proxy_ctx *ctx; + struct be_req *req; + + char *buffer; + size_t buflen; + + struct passwd *pwd; + struct group *grp; + + gid_t *groups; + long int num; + long int cur; + + struct ldb_dn *dn; + + sysdb_callback_t next_fn; +}; + +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"; + + if (error != EOK) err = "Operation failed"; + + sysdb_transaction_done(data->sysreq, error); + return proxy_reply(data->req, error, err); +} + +static void del_db_entry(struct sysdb_req *req, void *pvt) +{ + struct proxy_data *data = talloc_get_type(pvt, struct proxy_data); + struct sysdb_ctx *ctx; + int ret; + + data->sysreq = req; + ctx = sysdb_req_get_ctx(req); + + ret = sysdb_delete_entry(req, data->dn, data->next_fn, data); + if (ret != EOK) { + proxy_return(data, ret, NULL); + } +} + +static void del_pw_uid(struct sysdb_req *req, void *pvt) +{ + struct proxy_data *data = talloc_get_type(pvt, struct proxy_data); + struct sysdb_ctx *ctx; + int ret; + + data->sysreq = req; + ctx = sysdb_req_get_ctx(req); + + ret = sysdb_delete_user_by_uid(req, + data->req->be_ctx->domain, + data->pwd->pw_uid, + data->next_fn, data); + if (ret != EOK) { + proxy_return(data, ret, NULL); + } +} + +static void set_pw_name(struct sysdb_req *req, void *pvt) +{ + struct proxy_data *data = talloc_get_type(pvt, struct proxy_data); + struct sysdb_ctx *ctx; + int ret; + + data->sysreq = req; + ctx = sysdb_req_get_ctx(req); + + ret = sysdb_legacy_store_user(req, 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) { + proxy_return(data, ret, NULL); + } +} + +static void get_pw_name(struct be_req *req, char *name) +{ + struct proxy_ctx *ctx; + enum nss_status status; + struct proxy_data *data; + int ret; + + ctx = talloc_get_type(req->be_ctx->pvt_data, struct proxy_ctx); + + data = talloc_zero(req, struct proxy_data); + if (!data) + return proxy_reply(req, ENOMEM, "Out of memory"); + data->req = req; + data->ctx = ctx; + data->next_fn = proxy_return; + data->pwd = talloc(data, struct passwd); + if (!data->pwd) + return proxy_reply(req, ENOMEM, "Out of memory"); + + data->buflen = 4096; + data->buffer = talloc_size(data, data->buflen); + if (!data->buffer) + return proxy_reply(req, ENOMEM, "Out of memory"); + + status = ctx->ops.getpwnam_r(name, data->pwd, + data->buffer, data->buflen, &ret); + + switch (status) { + case NSS_STATUS_NOTFOUND: + data->dn = sysdb_user_dn(req->be_ctx->sysdb, data, + req->be_ctx->domain, name); + if (!data->dn) + return proxy_reply(req, ENOMEM, "Out of memory"); + + ret = sysdb_transaction(data, req->be_ctx->sysdb, del_db_entry, data); + break; + + case NSS_STATUS_SUCCESS: + ret = sysdb_transaction(data, req->be_ctx->sysdb, set_pw_name, data); + break; + + default: + DEBUG(2, ("proxy -> getpwnam_r failed for '%s' (%d)[%s]\n", + 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_pw_uid(struct be_req *req, uid_t uid) +{ + struct proxy_ctx *ctx; + enum nss_status status; + struct proxy_data *data; + int ret; + + ctx = talloc_get_type(req->be_ctx->pvt_data, struct proxy_ctx); + + data = talloc_zero(req, struct proxy_data); + if (!data) + return proxy_reply(req, ENOMEM, "Out of memory"); + data->req = req; + data->ctx = ctx; + data->next_fn = proxy_return; + data->pwd = talloc(data, struct passwd); + if (!data->pwd) + return proxy_reply(req, ENOMEM, "Out of memory"); + + data->buflen = 4096; + data->buffer = talloc_size(data, data->buflen); + if (!data->buffer) + return proxy_reply(req, ENOMEM, "Out of memory"); + + status = ctx->ops.getpwuid_r(uid, data->pwd, + data->buffer, data->buflen, &ret); + + switch (status) { + case NSS_STATUS_NOTFOUND: + data->pwd->pw_uid = uid; + ret = sysdb_transaction(data, req->be_ctx->sysdb, del_pw_uid, data); + break; + + case NSS_STATUS_SUCCESS: + ret = sysdb_transaction(data, req->be_ctx->sysdb, set_pw_name, data); + break; + + default: + DEBUG(2, ("proxy -> getpwuid_r failed for '%lu' (%d)[%s]\n", + (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_req *req, void *pvt); + +static void get_next_pw_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_pw_entry(data->sysreq, data); +} + +static void get_pw_entry(struct sysdb_req *req, void *pvt) +{ + struct proxy_data *data = talloc_get_type(pvt, struct proxy_data); + enum nss_status status; + struct sysdb_ctx *ctx; + char *newb; + int ret; + + data->sysreq = req; + ctx = sysdb_req_get_ctx(req); + +retry: + status = data->ctx->ops.getpwent_r(data->pwd, + data->buffer, data->buflen, &ret); + + switch (status) { + case NSS_STATUS_TRYAGAIN: + /* buffer too small ? */ + if (data->buflen < MAX_BUF_SIZE) { + data->buflen *= 2; + } + if (data->buflen > MAX_BUF_SIZE) { + data->buflen = MAX_BUF_SIZE; + } + newb = talloc_realloc_size(data, data->buffer, data->buflen); + if (!newb) { + return proxy_return(data, ENOMEM, NULL); + } + data->buffer = newb; + goto retry; + + case NSS_STATUS_NOTFOUND: + + data->ctx->ops.endpwent(); + data->next_fn(data, EOK, NULL); + break; + + case NSS_STATUS_SUCCESS: + ret = sysdb_legacy_store_user(req, 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); + } + break; + + default: + DEBUG(2, ("proxy -> getpwent_r failed (%d)[%s]\n", + ret, strerror(ret))); + proxy_return(data, ret, NULL); + } +} + static void enum_users(struct be_req *req) { struct proxy_ctx *ctx; enum nss_status status; - struct passwd result; - char *buffer, *newb; - size_t buflen; - const char *errstr; + struct proxy_data *data; int ret; ctx = talloc_get_type(req->be_ctx->pvt_data, struct proxy_ctx); - buflen = 4096; - buffer = talloc_size(req, buflen); - if (!buffer) + data = talloc_zero(req, struct proxy_data); + if (!data) + return proxy_reply(req, ENOMEM, "Out of memory"); + data->req = req; + data->ctx = ctx; + data->next_fn = proxy_return; + data->pwd = talloc(data, struct passwd); + if (!data->pwd) + return proxy_reply(req, ENOMEM, "Out of memory"); + + data->buflen = 4096; + data->buffer = talloc_size(data, data->buflen); + if (!data->buffer) return proxy_reply(req, ENOMEM, "Out of memory"); status = ctx->ops.setpwent(); if (status != NSS_STATUS_SUCCESS) return proxy_reply(req, EIO, "Operation failed"); - while (status == NSS_STATUS_SUCCESS) { - - status = ctx->ops.getpwent_r(&result, buffer, buflen, &ret); - - switch (status) { - case NSS_STATUS_TRYAGAIN: - /* buffer too small ? */ - if (buflen < MAX_BUF_SIZE) { - buflen *= 2; - } - if (buflen > MAX_BUF_SIZE) { - buflen = MAX_BUF_SIZE; - } - newb = talloc_realloc_size(NULL, buffer, buflen); - if (!newb) { - errstr = "Out of memory"; - ret = ENOMEM; - goto done; - } - buffer = newb; - status = NSS_STATUS_SUCCESS; - break; + 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"); + } +} - case NSS_STATUS_NOTFOUND: - /* we got last one */ - break; +static void del_gr_uid(struct sysdb_req *req, void *pvt) +{ + struct proxy_data *data = talloc_get_type(pvt, struct proxy_data); + struct sysdb_ctx *ctx; + int ret; - case NSS_STATUS_SUCCESS: - ret = sysdb_legacy_store_user(req, req->be_ctx->sysdb, - req->be_ctx->domain, - result.pw_name, result.pw_passwd, - result.pw_uid, result.pw_gid, - result.pw_gecos, result.pw_dir, - result.pw_shell); - if (ret != EOK) { - DEBUG(1, ("Failed to update LDB Cache for '%s' (%d)[%s] !?\n", - (unsigned long)result.pw_name, ret, strerror(ret))); - } - break; + data->sysreq = req; + ctx = sysdb_req_get_ctx(req); - default: - DEBUG(2, ("proxy -> getpwent_r failed (%d)[%s]\n", - ret, strerror(ret))); - errstr = "Operation failed"; - goto done; - } + ret = sysdb_delete_group_by_gid(req, + data->req->be_ctx->domain, + data->grp->gr_gid, + data->next_fn, data); + if (ret != EOK) { + proxy_return(data, ret, NULL); } +} - errstr = NULL; - ret = EOK; +static void set_gr_name(struct sysdb_req *req, void *pvt) +{ + struct proxy_data *data = talloc_get_type(pvt, struct proxy_data); + struct sysdb_ctx *ctx; + int ret; -done: - talloc_free(buffer); - ctx->ops.endpwent(); - return proxy_reply(req, ret, errstr); + data->sysreq = req; + ctx = sysdb_req_get_ctx(req); + + ret = sysdb_legacy_store_group(req, 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) { + proxy_return(data, ret, NULL); + } } static void get_gr_name(struct be_req *req, char *name) { struct proxy_ctx *ctx; enum nss_status status; - struct group result; - char *buffer; + struct proxy_data *data; int ret; ctx = talloc_get_type(req->be_ctx->pvt_data, struct proxy_ctx); - buffer = talloc_size(NULL, 4096); - if (!buffer) + data = talloc_zero(req, struct proxy_data); + if (!data) + return proxy_reply(req, ENOMEM, "Out of memory"); + data->req = req; + data->ctx = ctx; + data->next_fn = proxy_return; + data->grp = talloc(data, struct group); + if (!data->grp) + return proxy_reply(req, ENOMEM, "Out of memory"); + + data->buflen = 4096; + data->buffer = talloc_size(data, data->buflen); + if (!data->buffer) return proxy_reply(req, ENOMEM, "Out of memory"); - status = ctx->ops.getgrnam_r(name, &result, buffer, 4096, &ret); + status = ctx->ops.getgrnam_r(name, data->grp, + data->buffer, data->buflen, &ret); switch (status) { case NSS_STATUS_NOTFOUND: - ret = sysdb_delete_group(req, req->be_ctx->sysdb, - req->be_ctx->domain, name); + data->dn = sysdb_group_dn(req->be_ctx->sysdb, data, + req->be_ctx->domain, name); + if (!data->dn) + return proxy_reply(req, ENOMEM, "Out of memory"); + + ret = sysdb_transaction(data, req->be_ctx->sysdb, del_db_entry, data); break; + case NSS_STATUS_SUCCESS: - ret = sysdb_legacy_store_group(req, req->be_ctx->sysdb, - req->be_ctx->domain, result.gr_name, - result.gr_gid, result.gr_mem); + ret = sysdb_transaction(data, req->be_ctx->sysdb, set_gr_name, data); break; + default: DEBUG(2, ("proxy -> getgrnam_r failed for '%s' (%d)[%s]\n", name, ret, strerror(ret))); - talloc_free(buffer); return proxy_reply(req, ret, "Operation failed"); } if (ret != EOK) { - DEBUG(1, ("Failed to update LDB Cache for '%s' (%d) !?\n", - name, ret)); - talloc_free(buffer); + DEBUG(1, ("Failed to start transaction (%d)[%s]!?\n", + ret, strerror(ret))); return proxy_reply(req, ret, "Operation failed"); } - - talloc_free(buffer); - return proxy_reply(req, EOK, NULL); } static void get_gr_gid(struct be_req *req, gid_t gid) { struct proxy_ctx *ctx; enum nss_status status; - struct group result; - char *buffer; + struct proxy_data *data; int ret; ctx = talloc_get_type(req->be_ctx->pvt_data, struct proxy_ctx); - buffer = talloc_size(req, 4096); - if (!buffer) + data = talloc_zero(req, struct proxy_data); + if (!data) + return proxy_reply(req, ENOMEM, "Out of memory"); + data->req = req; + data->ctx = ctx; + data->next_fn = proxy_return; + data->grp = talloc(data, struct group); + if (!data->grp) return proxy_reply(req, ENOMEM, "Out of memory"); - status = ctx->ops.getgrgid_r(gid, &result, buffer, 4096, &ret); + data->buflen = 4096; + data->buffer = talloc_size(data, data->buflen); + if (!data->buffer) + return proxy_reply(req, ENOMEM, "Out of memory"); + + status = ctx->ops.getgrgid_r(gid, data->grp, + data->buffer, data->buflen, &ret); switch (status) { case NSS_STATUS_NOTFOUND: - ret = sysdb_delete_group_by_gid(req, req->be_ctx->sysdb, - req->be_ctx->domain, gid); + data->grp->gr_gid = gid; + ret = sysdb_transaction(data, req->be_ctx->sysdb, del_gr_uid, data); break; + case NSS_STATUS_SUCCESS: - ret = sysdb_legacy_store_group(req, req->be_ctx->sysdb, - req->be_ctx->domain, result.gr_name, - result.gr_gid, result.gr_mem); + ret = sysdb_transaction(data, req->be_ctx->sysdb, set_gr_name, data); break; + default: DEBUG(2, ("proxy -> getgrgid_r failed for '%lu' (%d)[%s]\n", (unsigned long)gid, ret, strerror(ret))); - talloc_free(buffer); return proxy_reply(req, ret, "Operation failed"); } if (ret != EOK) { - DEBUG(1, ("Failed to update LDB Cache for '%lu' (%d) !?\n", - (unsigned long)gid, ret)); - talloc_free(buffer); + DEBUG(1, ("Failed to start transaction (%d)[%s]!?\n", + ret, strerror(ret))); return proxy_reply(req, ret, "Operation failed"); } +} - talloc_free(buffer); - return proxy_reply(req, EOK, NULL); +static void get_gr_entry(struct sysdb_req *req, void *pvt); + +static void get_next_gr_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_gr_entry(data->sysreq, data); +} + +static void get_gr_entry(struct sysdb_req *req, void *pvt) +{ + struct proxy_data *data = talloc_get_type(pvt, struct proxy_data); + enum nss_status status; + struct sysdb_ctx *ctx; + char *newb; + int ret; + + data->sysreq = req; + ctx = sysdb_req_get_ctx(req); + +retry: + status = data->ctx->ops.getgrent_r(data->grp, + data->buffer, data->buflen, &ret); + + switch (status) { + case NSS_STATUS_TRYAGAIN: + /* buffer too small ? */ + if (data->buflen < MAX_BUF_SIZE) { + data->buflen *= 2; + } + if (data->buflen > MAX_BUF_SIZE) { + data->buflen = MAX_BUF_SIZE; + } + newb = talloc_realloc_size(data, data->buffer, data->buflen); + if (!newb) { + return proxy_return(data, ENOMEM, NULL); + } + data->buffer = newb; + goto retry; + + case NSS_STATUS_NOTFOUND: + + data->ctx->ops.endgrent(); + data->next_fn(data, EOK, NULL); + break; + + case NSS_STATUS_SUCCESS: + ret = sysdb_legacy_store_group(req, 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); + } + break; + + default: + DEBUG(2, ("proxy -> getgrent_r failed (%d)[%s]\n", + ret, strerror(ret))); + proxy_return(data, ret, NULL); + } } static void enum_groups(struct be_req *req) { struct proxy_ctx *ctx; enum nss_status status; - struct group result; - char *buffer, *newb; - size_t buflen; - const char * errstr; - int ret, c; + struct proxy_data *data; + int ret; ctx = talloc_get_type(req->be_ctx->pvt_data, struct proxy_ctx); - buflen = 4096; - buffer = talloc_size(req, buflen); - if (!buffer) + data = talloc_zero(req, struct proxy_data); + if (!data) + return proxy_reply(req, ENOMEM, "Out of memory"); + data->req = req; + data->ctx = ctx; + data->next_fn = proxy_return; + data->grp = talloc(data, struct group); + if (!data->grp) + return proxy_reply(req, ENOMEM, "Out of memory"); + + data->buflen = 4096; + data->buffer = talloc_size(data, data->buflen); + if (!data->buffer) return proxy_reply(req, ENOMEM, "Out of memory"); status = ctx->ops.setgrent(); if (status != NSS_STATUS_SUCCESS) return proxy_reply(req, EIO, "Operation failed"); - c = 0; - while (status == NSS_STATUS_SUCCESS) { - - status = ctx->ops.getgrent_r(&result, buffer, buflen, &ret); - - switch (status) { - case NSS_STATUS_TRYAGAIN: - DEBUG(20, ("Try Again\n")); - - if (ret != ERANGE) { - DEBUG(2, ("getgrent_r failed (TRYAGAIN)(%d)[%s]\n", - ret, strerror(ret))); - errstr = "Operation failed"; - goto done; - } - /* buffer too small ? */ - if (buflen < MAX_BUF_SIZE) { - buflen *= 2; - } - if (buflen > MAX_BUF_SIZE) { - buflen = MAX_BUF_SIZE; - } - newb = talloc_realloc_size(req, buffer, buflen); - if (!newb) { - DEBUG(4, ("Out of memory\n")); - errstr = "Out of memory"; - ret = ENOMEM; - goto done; - } - buffer = newb; - status = NSS_STATUS_SUCCESS; - break; - - case NSS_STATUS_NOTFOUND: - DEBUG(6, ("No more entries\n")); - /* we got last one */ - break; + 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"); + } +} - case NSS_STATUS_SUCCESS: - c++; - DEBUG(20, ("Storing group [%s](%d)\n", result.gr_name, c)); - ret = sysdb_legacy_store_group(req, req->be_ctx->sysdb, - req->be_ctx->domain, result.gr_name, - result.gr_gid, result.gr_mem); - if (ret != EOK) { - DEBUG(1, ("Failed to update LDB Cache for '%s' (%d)[%s] !?\n", - (unsigned long)result.gr_name, ret, strerror(ret))); - } - break; +static void get_gid_entry(struct sysdb_req *req, void *pvt); - default: - DEBUG(2, ("getgrent_r failed (%d)[%s]\n", ret, strerror(ret))); - errstr = "Operation failed"; - goto done; - } - } +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); - errstr = NULL; - ret = EOK; + if (error != EOK) proxy_return(data, error, NULL); -done: - talloc_free(buffer); - ctx->ops.endgrent(); - return proxy_reply(req, ret, errstr); + get_gid_entry(data->sysreq, data); } -static int save_initgroups(struct be_req *req, gid_t *gids, long int num) +static void get_gid_entry(struct sysdb_req *req, void *pvt) { - struct proxy_ctx *ctx; - struct sysdb_ctx *sysdb; + struct proxy_data *data = talloc_get_type(pvt, struct proxy_data); enum nss_status status; - struct group result; - char *buffer; - int i, ret; - - ctx = talloc_get_type(req->be_ctx->pvt_data, struct proxy_ctx); - sysdb = req->be_ctx->sysdb; + struct sysdb_ctx *ctx; + char *newb; + int ret; - buffer = talloc_size(req, 4096); - if (!buffer) { - return ENOMEM; - } + ctx = sysdb_req_get_ctx(req); - for (i = 0; i < num; i++) { + /* all done */ + if (data->cur == data->num) + return data->next_fn(data, EOK, NULL); - status = ctx->ops.getgrgid_r(gids[i], &result, buffer, 4096, &ret); +retry: + status = data->ctx->ops.getgrgid_r(data->groups[data->cur], data->grp, + data->buffer, data->buflen, &ret); - switch (status) { - case NSS_STATUS_NOTFOUND: - DEBUG(4, ("gid [%lu] not found, removing group\n")); - ret = sysdb_delete_group_by_gid(req, sysdb, - req->be_ctx->domain, - gids[i]); - break; + switch (status) { + case NSS_STATUS_TRYAGAIN: + /* buffer too small ? */ + if (data->buflen < MAX_BUF_SIZE) { + data->buflen *= 2; + } + if (data->buflen > MAX_BUF_SIZE) { + data->buflen = MAX_BUF_SIZE; + } + newb = talloc_realloc_size(data, data->buffer, data->buflen); + if (!newb) { + return proxy_return(data, ENOMEM, NULL); + } + data->buffer = newb; + goto retry; - case NSS_STATUS_SUCCESS: - ret = sysdb_legacy_store_group(req, sysdb, - req->be_ctx->domain, - result.gr_name, - result.gr_gid, - result.gr_mem); - break; + 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(req, 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); + } + break; - default: - DEBUG(2, ("proxy -> getgrgid_r failed for '%lu' (%d)[%s]\n", - (unsigned long)(gids[i]), ret, strerror(ret))); - break; + case NSS_STATUS_SUCCESS: + data->cur++; + ret = sysdb_legacy_store_group(req, 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); } - } + break; - talloc_free(buffer); - return EOK; + default: + DEBUG(2, ("proxy -> getgrgid_r failed (%d)[%s]\n", + ret, strerror(ret))); + proxy_return(data, ret, NULL); + } } -static void get_user_groups(struct be_req *req, char *name) +static void get_user_groups(void *pvt, int error, struct ldb_result *ignore) { - struct proxy_ctx *ctx; + struct proxy_data *data = talloc_get_type(pvt, struct proxy_data); enum nss_status status; - struct passwd result; - char *buffer; - gid_t *groups; long int limit; long int start; long int size; long int num; + char *name; + gid_t gid; + int ret; + + if (error != EOK) proxy_return(data, error, NULL); + data->next_fn = proxy_return; + + start = 0; + limit = 4096; + num = 4096; + size = num*sizeof(gid_t); + data->groups = talloc_size(data, size); + if (!data->groups) + return proxy_return(data, ENOMEM, NULL); + + gid = data->pwd->pw_gid; + name = talloc_strdup(data, data->pwd->pw_name); + if (!name) + return proxy_return(data, ENOMEM, NULL); + +retry: + status = data->ctx->ops.initgroups_dyn(name, gid, + &start, &num, + &data->groups, limit, &ret); + switch (status) { + case NSS_STATUS_TRYAGAIN: + /* buffer too small ? */ + if (size < MAX_BUF_SIZE) { + num *= 2; + size = num*sizeof(gid_t); + } + if (size > MAX_BUF_SIZE) { + size = MAX_BUF_SIZE; + num = size/sizeof(gid_t); + } + limit = num; + data->groups = talloc_realloc_size(data, data->groups, size); + if (!data->groups) { + return proxy_return(data, ENOMEM, NULL); + } + goto retry; + + case NSS_STATUS_SUCCESS: + data->num = start; + DEBUG(4, ("User [%s] appears to be member of %lu groups\n", + name, data->num)); + get_gid_entry(data->sysreq, data); + break; + + default: + DEBUG(2, ("proxy -> getgrent_r failed (%d)[%s]\n", + ret, strerror(ret))); + proxy_return(data, ret, NULL); + } +} + +static void get_initgr_user(struct be_req *req, char *name) +{ + struct proxy_ctx *ctx; + enum nss_status status; + struct proxy_data *data; int ret; ctx = talloc_get_type(req->be_ctx->pvt_data, struct proxy_ctx); - buffer = talloc_size(req, 4096); - if (!buffer) + data = talloc_zero(req, struct proxy_data); + if (!data) + return proxy_reply(req, ENOMEM, "Out of memory"); + data->req = req; + data->ctx = ctx; + data->next_fn = proxy_return; + data->pwd = talloc(data, struct passwd); + if (!data->pwd) + return proxy_reply(req, ENOMEM, "Out of memory"); + data->grp = talloc(data, struct group); + if (!data->grp) return proxy_reply(req, ENOMEM, "Out of memory"); - status = ctx->ops.getpwnam_r(name, &result, buffer, 4096, &ret); + data->buflen = 4096; + data->buffer = talloc_size(data, data->buflen); + if (!data->buffer) + return proxy_reply(req, ENOMEM, "Out of memory"); + + status = ctx->ops.getpwnam_r(name, data->pwd, + data->buffer, data->buflen, &ret); switch (status) { case NSS_STATUS_NOTFOUND: - ret = sysdb_delete_user(req, req->be_ctx->sysdb, - req->be_ctx->domain, name); - break; - case NSS_STATUS_SUCCESS: - ret = sysdb_legacy_store_user(req, req->be_ctx->sysdb, - req->be_ctx->domain, - result.pw_name, result.pw_passwd, - result.pw_uid, result.pw_gid, - result.pw_gecos, result.pw_dir, - result.pw_shell); - if (ret != EOK) break; - - /* FIXME: let's start with 4k entries */ - start = 0; - limit = 4096; - num = 4096; - - size = num*sizeof(gid_t); - groups = talloc_size(req, size); - if (!groups) { - talloc_free(buffer); + data->dn = sysdb_user_dn(req->be_ctx->sysdb, data, + req->be_ctx->domain, name); + if (!data->dn) return proxy_reply(req, ENOMEM, "Out of memory"); - } - status = ctx->ops.initgroups_dyn(result.pw_name, result.pw_gid, - &start, &num, &groups, limit, &ret); - switch (status) { - case NSS_STATUS_SUCCESS: - - if (ret == EOK) { - DEBUG(4, ("User [%s] appears to be member of %lu groups\n", - result.pw_name, start)); - /* start is moved up by the number of groups retrieved, - * therefore represents the number of users to pass on */ - ret = save_initgroups(req, groups, start); - } - - break; + ret = sysdb_transaction(data, req->be_ctx->sysdb, del_db_entry, data); + break; - default: - DEBUG(2, ("proxy -> initgroups_dyn failed for '%s' (%d)[%s]\n", - name, ret, strerror(ret))); - talloc_free(buffer); - return proxy_reply(req, ret, "Operation failed"); - } + case NSS_STATUS_SUCCESS: + data->next_fn = get_user_groups; + ret = sysdb_transaction(data, req->be_ctx->sysdb, set_pw_name, data); break; default: DEBUG(2, ("proxy -> getpwnam_r failed for '%s' (%d)[%s]\n", name, ret, strerror(ret))); - talloc_free(buffer); return proxy_reply(req, ret, "Operation failed"); } if (ret != EOK) { - DEBUG(1, ("Failed to update LDB Cache for '%s' (%d) !?\n", - name, ret)); - talloc_free(buffer); + DEBUG(1, ("Failed to start transaction (%d)[%s]!?\n", + ret, strerror(ret))); return proxy_reply(req, ret, "Operation failed"); } - - talloc_free(buffer); - return proxy_reply(req, EOK, NULL); } /* TODO: actually do check something */ @@ -785,7 +1045,7 @@ static void proxy_get_account_info(struct be_req *req) if (strchr(ar->filter_value, '*')) { return proxy_reply(req, EINVAL, "Invalid filter value"); } - return get_user_groups(req, ar->filter_value); + return get_initgr_user(req, ar->filter_value); default: /*fail*/ return proxy_reply(req, EINVAL, "Invalid request type"); diff --git a/server/server.mk b/server/server.mk index e029d4a57..77f805ca5 100644 --- a/server/server.mk +++ b/server/server.mk @@ -15,7 +15,7 @@ UTIL_OBJ = \ db/sysdb.o \ db/sysdb_req.o \ db/sysdb_search.o \ - db/sysdb_sync.o + db/sysdb_ops.o RESPONDER_UTIL_OBJ = \ responder/common/responder_dp.o \ |