From 92bb11b3570c0ce1de84824d9697fa45422feb0b Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mon, 9 Mar 2009 20:34:44 -0400 Subject: Move MPG checks within sysdb. This allows to perform checks and modifications in one transaction. Uses configuration stored in confdb to determins if a domain uses MPGs. --- server/db/sysdb.h | 25 +++--- server/db/sysdb_ops.c | 196 +++++++++++++++++++++++++++++++++++++++++--- server/tools/sss_groupadd.c | 8 -- server/tools/sss_useradd.c | 8 -- server/tools/tools_util.c | 98 ---------------------- server/tools/tools_util.h | 2 - 6 files changed, 199 insertions(+), 138 deletions(-) (limited to 'server') diff --git a/server/db/sysdb.h b/server/db/sysdb.h index c278e64cb..e7da90b0e 100644 --- a/server/db/sysdb.h +++ b/server/db/sysdb.h @@ -65,20 +65,25 @@ #define SYSDB_NEXTID_FILTER "("SYSDB_NEXTID"=*)" -#define SYSDB_PWNAM_FILTER "(&(objectclass="SYSDB_USER_CLASS")("SYSDB_NAME"=%s))" -#define SYSDB_PWUID_FILTER "(&(objectclass="SYSDB_USER_CLASS")("SYSDB_UIDNUM"=%lu))" -#define SYSDB_PWENT_FILTER "(objectclass="SYSDB_USER_CLASS")" +#define SYSDB_UC "objectclass="SYSDB_USER_CLASS +#define SYSDB_GC "objectclass="SYSDB_GROUP_CLASS -#define SYSDB_GRNAM_FILTER "(&(objectclass="SYSDB_GROUP_CLASS")("SYSDB_NAME"=%s))" -#define SYSDB_GRNA2_FILTER "(&(objectclass="SYSDB_USER_CLASS")("SYSDB_MEMBEROF"=%s))" -#define SYSDB_GRGID_FILTER "(&(objectclass="SYSDB_GROUP_CLASS")("SYSDB_GIDNUM"=%lu))" -#define SYSDB_GRENT_FILTER "(objectclass="SYSDB_GROUP_CLASS")" +#define SYSDB_PWNAM_FILTER "(&("SYSDB_UC")("SYSDB_NAME"=%s))" +#define SYSDB_PWUID_FILTER "(&("SYSDB_UC")("SYSDB_UIDNUM"=%lu))" +#define SYSDB_PWENT_FILTER "("SYSDB_UC")" -#define SYSDB_INITGR_FILTER "(&(objectclass="SYSDB_GROUP_CLASS")("SYSDB_GIDNUM"=*))" +#define SYSDB_GRNAM_FILTER "(&("SYSDB_GC")("SYSDB_NAME"=%s))" +#define SYSDB_GRNA2_FILTER "(&("SYSDB_UC")("SYSDB_MEMBEROF"=%s))" +#define SYSDB_GRGID_FILTER "(&("SYSDB_GC")("SYSDB_GIDNUM"=%lu))" +#define SYSDB_GRENT_FILTER "("SYSDB_GC")" -#define SYSDB_INITGR_LEGACY_FILTER "(&(objectclass="SYSDB_GROUP_CLASS")("SYSDB_LEGACY_MEMBER"=%s))" +#define SYSDB_INITGR_FILTER "(&("SYSDB_GC")("SYSDB_GIDNUM"=*))" -#define SYSDB_GETCACHED_FILTER "(&(objectclass="SYSDB_USER_CLASS")("SYSDB_LAST_LOGIN">=%lu))" +#define SYSDB_INITGR_LEGACY_FILTER "(&("SYSDB_GC")("SYSDB_LEGACY_MEMBER"=%s))" + +#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_FULLNAME, \ diff --git a/server/db/sysdb_ops.c b/server/db/sysdb_ops.c index 9ea2a0aa5..0d20d7b32 100644 --- a/server/db/sysdb_ops.c +++ b/server/db/sysdb_ops.c @@ -753,6 +753,108 @@ static int nextid_callback(struct ldb_request *req, struct ldb_reply *rep) return LDB_SUCCESS; } +struct check_name_ctx { + struct sysdb_req *sysreq; + + sysdb_callback_t fn; + void *pvt; + + struct ldb_result *res; +}; + +static int check_name_callback(struct ldb_request *req, struct ldb_reply *rep); + +int sysdb_check_name_unique(struct sysdb_req *sysreq, + struct sss_domain_info *domain, + TALLOC_CTX *mem_ctx, const char *name, + sysdb_callback_t fn, void *pvt) +{ + static const char *attrs[] = { SYSDB_NAME, NULL }; + struct check_name_ctx *cnctx; + 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); + + cnctx = talloc_zero(mem_ctx, struct check_name_ctx); + if (!cnctx) return ENOMEM; + + cnctx->sysreq = sysreq; + cnctx->fn = fn; + cnctx->pvt = pvt; + + base_dn = sysdb_domain_dn(ctx, cnctx, domain->name); + if (!base_dn) return ENOMEM; + + filter = talloc_asprintf(cnctx, SYSDB_CHECK_FILTER, name); + if (!filter) return ENOMEM; + + cnctx->res = talloc_zero(cnctx, struct ldb_result); + if (!cnctx->res) return ENOMEM; + + ret = ldb_build_search_req(&req, ctx->ldb, mem_ctx, + base_dn, LDB_SCOPE_SUBTREE, + filter, attrs, NULL, + cnctx, check_name_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 check_name_callback(struct ldb_request *req, struct ldb_reply *rep) +{ + struct check_name_ctx *cnctx; + struct sysdb_ctx *ctx; + + cnctx = talloc_get_type(req->context, struct check_name_ctx); + ctx = sysdb_req_get_ctx(cnctx->sysreq); + + if (!rep) { + return_error(cnctx, EIO); + return LDB_ERR_OPERATIONS_ERROR; + } + if (rep->error != LDB_SUCCESS) { + return_error(cnctx, sysdb_error_to_errno(rep->error)); + return rep->error; + } + + switch (rep->type) { + case LDB_REPLY_ENTRY: + + /* one found, that means name is not available */ + /* return EEXIST */ + return_error(cnctx, EEXIST); + return LDB_ERR_ENTRY_ALREADY_EXISTS; + break; + + case LDB_REPLY_DONE: + + return_done(cnctx); + break; + + default: + return_error(cnctx, EINVAL); + return LDB_ERR_OPERATIONS_ERROR; + } + + return LDB_SUCCESS; +} + struct user_add_ctx { struct sysdb_req *sysreq; @@ -769,6 +871,8 @@ struct user_add_ctx { struct next_id id; }; +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); @@ -786,6 +890,13 @@ int sysdb_add_user(struct sysdb_req *sysreq, return EINVAL; } + if ((uid == 0 || gid == 0) && (uid != 0 || gid != 0)) { + /* you either set both or neither, we will not guess only one */ + DEBUG(1, ("You have to either specify both uid and gid or neither" + " (preferred) [passed in uid=%u, gid =%u]\n", uid, gid)); + return EINVAL; + } + user_ctx = talloc(sysreq, struct user_add_ctx); if (!user_ctx) return ENOMEM; @@ -803,17 +914,42 @@ int sysdb_add_user(struct sysdb_req *sysreq, user_ctx->homedir = homedir; user_ctx->shell = shell; - if (uid == 0 && gid == 0) { - /* Must generate uid/gid pair */ - return sysdb_get_next_available_id(sysreq, domain, &(user_ctx->id), - user_add_id_callback, user_ctx); + if (domain->mpg) { + /* if the domain is mpg we need to check we do not have there are no + * name conflicts */ + + return sysdb_check_name_unique(sysreq, domain, user_ctx, name, + user_check_callback, user_ctx); } - if (uid == 0 || gid == 0) { - /* you either set both or neither, we will not guess only one */ - DEBUG(1, ("You have to either specify both uid and gid or neither" - " (preferred) [passed in uid=%u, gid =%u]\n", uid, gid)); - return EINVAL; + return user_add_id(user_ctx); +} + +static void user_check_callback(void *pvt, int error, struct ldb_result *res) +{ + struct user_add_ctx *user_ctx; + int ret; + + user_ctx = talloc_get_type(pvt, struct user_add_ctx); + if (error != EOK) { + return_error(user_ctx->cbctx, error); + return; + } + + ret = user_add_id(user_ctx); + if (ret != EOK) { + return_error(user_ctx->cbctx, ret); + } +} + +static int user_add_id(struct user_add_ctx *user_ctx) +{ + if (user_ctx->uid == 0 && user_ctx->gid == 0) { + /* Must generate uid/gid pair */ + return sysdb_get_next_available_id(user_ctx->sysreq, + user_ctx->domain, + &(user_ctx->id), + user_add_id_callback, user_ctx); } return user_add_call(user_ctx); @@ -835,7 +971,9 @@ static void user_add_id_callback(void *pvt, int error, struct ldb_result *res) user_ctx->gid = user_ctx->id.id; ret = user_add_call(user_ctx); - if (ret != EOK) return_error(user_ctx->cbctx, ret); + if (ret != EOK) { + return_error(user_ctx->cbctx, ret); + } } static int user_add_call(struct user_add_ctx *user_ctx) @@ -920,6 +1058,8 @@ struct group_add_ctx { struct next_id id; }; +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); @@ -948,9 +1088,41 @@ int sysdb_add_group(struct sysdb_req *sysreq, group_ctx->name = name; group_ctx->gid = gid; - if (gid == 0) { + if (domain->mpg) { + /* if the domain is mpg we need to check we do not have there are no + * name conflicts */ + + return sysdb_check_name_unique(sysreq, domain, group_ctx, name, + group_check_callback, group_ctx); + } + + return group_add_id(group_ctx); +} + +static void group_check_callback(void *pvt, int error, struct ldb_result *res) +{ + struct group_add_ctx *group_ctx; + int ret; + + group_ctx = talloc_get_type(pvt, struct group_add_ctx); + if (error != EOK) { + return_error(group_ctx->cbctx, error); + return; + } + + ret = group_add_id(group_ctx); + if (ret != EOK) { + return_error(group_ctx->cbctx, ret); + } +} + +static int group_add_id(struct group_add_ctx *group_ctx) +{ + if (group_ctx->gid == 0) { /* Must generate uid/gid pair */ - return sysdb_get_next_available_id(sysreq, domain, &(group_ctx->id), + return sysdb_get_next_available_id(group_ctx->sysreq, + group_ctx->domain, + &(group_ctx->id), group_add_id_callback, group_ctx); } diff --git a/server/tools/sss_groupadd.c b/server/tools/sss_groupadd.c index e36e220fe..5363dbbaf 100644 --- a/server/tools/sss_groupadd.c +++ b/server/tools/sss_groupadd.c @@ -135,14 +135,6 @@ int main(int argc, const char **argv) goto fini; } - /* Check MPG constraints */ - ret = check_group_name_unique(ctx, group_ctx->groupname); - if(ret != EOK) { - DEBUG(1, ("Could not add group - name not unique\n")); - ret = EXIT_FAILURE; - goto fini; - } - /* add_group */ ret = sysdb_transaction(ctx, ctx->sysdb, add_group, group_ctx); if(ret != EOK) { diff --git a/server/tools/sss_useradd.c b/server/tools/sss_useradd.c index 710ed207f..7bad83786 100644 --- a/server/tools/sss_useradd.c +++ b/server/tools/sss_useradd.c @@ -338,14 +338,6 @@ int main(int argc, const char **argv) goto fini; } - /* Check MPG constraints */ - ret = check_user_name_unique(ctx, user_ctx->username); - if (ret != EOK) { - DEBUG(0, ("Could not add user - name not unique\n")); - ret = EXIT_FAILURE; - goto fini; - } - /* useradd */ ret = sysdb_transaction(ctx, ctx->sysdb, add_user, user_ctx); if (ret != EOK) { diff --git a/server/tools/tools_util.c b/server/tools/tools_util.c index daf9b41f4..a3669001f 100644 --- a/server/tools/tools_util.c +++ b/server/tools/tools_util.c @@ -28,104 +28,6 @@ #include "db/sysdb.h" #include "tools/tools_util.h" -/* Even in LOCAL database, we must enforce MPG. That means enforcing the following rules: - * - * 1. Users and groups must share the same name space. There can never be - * a real group that has the same name of a real user. - * 2. Users and Groups must share the same ID space a group can never have - * a gidNumber that is numerically equal to a uidNumber Otherwise the - * user MPG will conflict with said group. - */ - -struct ucheck { - bool done; - bool dup; - int error; -}; - -void check_unique_callback(void *ptr, int error, struct ldb_result *res) -{ - struct ucheck *data = talloc_get_type(ptr, struct ucheck); - - data->done = true; - - if (error) { - data->error = error; - } - - if (res->count != 0) { - data->dup = true; - } -} - -int check_user_name_unique(struct tools_ctx *ctx, const char *name) -{ - struct ucheck *data; - int ret = EOK; - - data = talloc_zero(NULL, struct ucheck); - if (!data) return ENOMEM; - - ret = sysdb_getgrnam(data, ctx->sysdb, - "LOCAL", name, false, - check_unique_callback, data); - if (ret != EOK) { - DEBUG(1, ("sysdb_getgrnam failed: %d\n", ret)); - goto done; - } - - while (!data->done) { - tevent_loop_once(ctx->ev); - } - - if (data->error) { - ret = data->error; - goto done; - } - - if (data->dup) { - ret = EEXIST; - } - -done: - talloc_free(data); - return ret; -} - -int check_group_name_unique(struct tools_ctx *ctx, const char *name) -{ - struct ucheck *data; - int ret; - - data = talloc_zero(NULL, struct ucheck); - if (!data) return ENOMEM; - - ret = sysdb_getpwnam(data, ctx->sysdb, - "LOCAL", name, false, - check_unique_callback, data); - if (ret != EOK) { - DEBUG(1, ("sysdb_getgrnam failed: %d\n", ret)); - goto done; - } - - while (!data->done) { - tevent_loop_once(ctx->ev); - } - - if (data->error) { - ret = data->error; - goto done; - } - - if (data->dup) { - ret = EEXIST; - } - -done: - talloc_free(data); - return ret; -} - int setup_db(struct tools_ctx **tools_ctx) { TALLOC_CTX *tmp_ctx; diff --git a/server/tools/tools_util.h b/server/tools/tools_util.h index d8edd4930..4a32e9c73 100644 --- a/server/tools/tools_util.h +++ b/server/tools/tools_util.h @@ -12,8 +12,6 @@ struct tools_ctx { struct btreemap *domains; }; -int check_user_name_unique(struct tools_ctx *ctx, const char *name); -int check_group_name_unique(struct tools_ctx *ctx, const char *name); int setup_db(struct tools_ctx **ctx); void usage(poptContext pc, const char *error); -- cgit