From 41edee286a924ec00ed9b9fc8a9cb37539fc6237 Mon Sep 17 00:00:00 2001 From: Stephen Gallagher Date: Wed, 28 Jul 2010 12:24:39 -0400 Subject: Add sysdb_update_members function This function will take a user, a list of groups that this user should be added to and a list of groups the user should be removed from and will recursively call sysdb_[add|remove]_group_member Includes a unit test --- src/db/sysdb.h | 10 +++ src/db/sysdb_ops.c | 191 ++++++++++++++++++++++++++++++++++++++++++++++++ src/tests/sysdb-tests.c | 168 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 369 insertions(+) diff --git a/src/db/sysdb.h b/src/db/sysdb.h index 2de2a648..04ce49e6 100644 --- a/src/db/sysdb.h +++ b/src/db/sysdb.h @@ -537,6 +537,16 @@ struct tevent_req *sysdb_remove_group_member_send(TALLOC_CTX *mem_ctx, const char *member); int sysdb_remove_group_member_recv(struct tevent_req *req); + +struct tevent_req * sysdb_update_members_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + char *user, + char **add_groups, + char **del_groups); +errno_t sysdb_update_members_recv(struct tevent_req *req); + /* Password caching function. * If you are in a transaction ignore sysdb and pass in the handle. * If you are not in a transaction pass NULL in handle and provide sysdb, diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c index 6fcc95b1..52102706 100644 --- a/src/db/sysdb_ops.c +++ b/src/db/sysdb_ops.c @@ -5065,3 +5065,194 @@ int sysdb_cache_auth_recv(struct tevent_req *req, time_t *expire_date, return (state->authentication_successful ? EOK : EINVAL); } + +struct sysdb_update_members_ctx { + char *user; + struct sss_domain_info *domain; + struct tevent_context *ev; + struct sysdb_handle *handle; + + char **add_groups; + int add_group_iter; + + char **del_groups; + int del_group_iter; +}; + +static char **empty_string_list(TALLOC_CTX *mem_ctx) +{ + char **empty; + empty = talloc_array(mem_ctx, char *, 1); + if (!empty) { + return NULL; + } + + empty[0] = NULL; + + return empty; +} + +static errno_t +sysdb_update_members_step(struct tevent_req *req); + +struct tevent_req *sysdb_update_members_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + char *user, + char **add_groups, + char **del_groups) +{ + errno_t ret; + struct tevent_req *req; + struct sysdb_update_members_ctx *state; + + req = tevent_req_create(mem_ctx, &state, struct sysdb_update_members_ctx); + if (!req) { + return NULL; + } + + state->user = talloc_strdup(state, user); + if (!state->user) { + goto error; + } + + state->domain = domain; + state->ev = ev; + state->handle = handle; + + if (add_groups) { + state->add_groups = dup_string_list(state, (const char**)add_groups); + } + else { + state->add_groups = empty_string_list(state); + } + if (!state->add_groups) { + goto error; + } + state->add_group_iter = 0; + + if (del_groups) { + state->del_groups = dup_string_list(state, (const char **)del_groups); + } + else { + state->del_groups = empty_string_list(state); + } + if (!state->del_groups) { + goto error; + } + state->del_group_iter = 0; + + ret = sysdb_update_members_step(req); + if (ret != EOK) { + /* Nothing to do. Finish up */ + tevent_req_error(req, ret); + tevent_req_post(req, state->ev); + } + + return req; + +error: + talloc_free(req); + return NULL; +} + +static void +sysdb_update_members_add_done(struct tevent_req *subreq); +static void +sysdb_update_members_del_done(struct tevent_req *subreq); + +static errno_t +sysdb_update_members_step(struct tevent_req *req) +{ + struct tevent_req *subreq; + struct sysdb_update_members_ctx *state; + + state = tevent_req_data(req, struct sysdb_update_members_ctx); + + if (state->add_groups[state->add_group_iter]) { + subreq = sysdb_add_group_member_send( + state, state->ev, state->handle, + state->domain, + state->add_groups[state->add_group_iter], + state->user); + if (!subreq) { + return EIO; + } + + tevent_req_set_callback(subreq, sysdb_update_members_add_done, req); + return EOK; + } + + if (state->del_groups[state->del_group_iter]) { + subreq = sysdb_remove_group_member_send( + state, state->ev, + state->handle, state->domain, + state->del_groups[state->del_group_iter], + state->user); + if (!subreq) { + return EIO; + } + + tevent_req_set_callback(subreq, sysdb_update_members_del_done, req); + return EOK; + } + + /* No more members to handle */ + tevent_req_done(req); + return EOK; +} + +static void +sysdb_update_members_add_done(struct tevent_req *subreq) +{ + errno_t ret; + struct tevent_req *req = + tevent_req_callback_data(subreq, struct tevent_req); + struct sysdb_update_members_ctx *state = + tevent_req_data(req, struct sysdb_update_members_ctx); + + ret = sysdb_add_group_member_recv(subreq); + talloc_zfree(subreq); + if(ret != EOK) { + tevent_req_error(req, ret); + return; + } + + state->add_group_iter++; + ret = sysdb_update_members_step(req); + if (ret != EOK) { + tevent_req_error(req, ret); + return; + } +} + +static void +sysdb_update_members_del_done(struct tevent_req *subreq) +{ + errno_t ret; + struct tevent_req *req = + tevent_req_callback_data(subreq, struct tevent_req); + struct sysdb_update_members_ctx *state = + tevent_req_data(req, struct sysdb_update_members_ctx); + + ret = sysdb_remove_group_member_recv(subreq); + talloc_zfree(subreq); + if(ret != EOK) { + tevent_req_error(req, ret); + return; + } + + state->del_group_iter++; + ret = sysdb_update_members_step(req); + if (ret != EOK) { + tevent_req_error(req, ret); + return; + } +} + +errno_t +sysdb_update_members_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); +} diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c index 584335ed..5bdc0054 100644 --- a/src/tests/sysdb-tests.c +++ b/src/tests/sysdb-tests.c @@ -3153,6 +3153,171 @@ START_TEST (test_sysdb_attrs_to_list) } END_TEST +static void test_sysdb_update_members_add(struct tevent_req *req); +START_TEST (test_sysdb_update_members) +{ + struct sysdb_test_ctx *test_ctx; + struct test_data *data; + struct tevent_req *req; + int ret; + + /* Setup */ + ret = setup_sysdb_tests(&test_ctx); + if (ret != EOK) { + fail("Could not set up the test"); + return; + } + + data = talloc_zero(test_ctx, struct test_data); + data->ctx = test_ctx; + data->ev = test_ctx->ev; + + /* Start the transaction */ + req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb); + if (!req) { + ret = ENOMEM; + } + + if (ret == EOK) { + tevent_req_set_callback(req, test_sysdb_update_members_add, data); + + ret = test_loop(data); + } + + fail_if(ret != EOK, "Could not test sysdb_update_members"); + talloc_free(test_ctx); +} +END_TEST + +static void test_sysdb_update_members_add_del(struct tevent_req *req); +static void test_sysdb_update_members_add(struct tevent_req *req) +{ + struct test_data *data = tevent_req_callback_data(req, struct test_data); + char **add_groups; + char *user; + errno_t ret; + + ret = sysdb_transaction_recv(req, data, &data->handle); + talloc_zfree(req); + if (ret != EOK) { + DEBUG(0, ("Could not start transaction\n")); + test_return(data, ret); + return; + } + + /* Add a user to two groups */ + data->username = talloc_strdup(data, "testuser27000"); + user = talloc_strdup(data, data->username); + add_groups = talloc_array(data, char *, 3); + add_groups[0] = talloc_strdup(data, "testgroup28001"); + add_groups[1] = talloc_strdup(data, "testgroup28002"); + add_groups[2] = NULL; + + req = sysdb_update_members_send(data, data->ev, data->handle, + data->ctx->domain, user, + add_groups, NULL); + talloc_free(add_groups); + talloc_free(user); + if (!req) { + DEBUG(0, ("Could not add groups\n")); + test_return(data, EIO); + return; + } + + tevent_req_set_callback(req, test_sysdb_update_members_add_del, data); +} + +static void test_sysdb_update_members_del(struct tevent_req *req); +static void test_sysdb_update_members_add_del(struct tevent_req *req) +{ + struct test_data *data = tevent_req_callback_data(req, struct test_data); + errno_t ret; + char **add_groups = NULL; + char **del_groups = NULL; + char *user; + + ret = sysdb_update_members_recv(req); + talloc_zfree(req); + if (ret != EOK) { + DEBUG(0, ("Group addition failed [%d](%s)\n", ret, strerror(ret))); + test_return(data, ret); + return; + } + + /* Remove a user from one group and add to another */ + user = talloc_strdup(data, data->username); + del_groups = talloc_array(data, char *, 2); + del_groups[0] = talloc_strdup(del_groups, "testgroup28001"); + del_groups[1] = NULL; + add_groups = talloc_array(data, char *, 2); + add_groups[0] = talloc_strdup(add_groups, "testgroup28003"); + add_groups[1] = NULL; + + req = sysdb_update_members_send(data, data->ev, data->handle, + data->ctx->domain, user, + add_groups, del_groups); + talloc_free(add_groups); + talloc_free(del_groups); + talloc_free(user); + if (!req) { + DEBUG(0, ("Could not add/del groups\n")); + test_return(data, EIO); + return; + } + + tevent_req_set_callback(req, test_sysdb_update_members_del, data); +} + +static void test_sysdb_update_members_done(struct tevent_req *req); +static void test_sysdb_update_members_del(struct tevent_req *req) +{ + struct test_data *data = tevent_req_callback_data(req, struct test_data); + errno_t ret; + char **del_groups = NULL; + char *user; + + ret = sysdb_update_members_recv(req); + talloc_zfree(req); + if (ret != EOK) { + DEBUG(0, ("Group replace failed [%d](%s)\n", ret, strerror(ret))); + test_return(data, EIO); + return; + } + + /* Remove a user from one group and add to another */ + user = talloc_strdup(data, data->username); + del_groups = talloc_array(data, char *, 3); + del_groups[0] = talloc_strdup(del_groups, "testgroup28002"); + del_groups[1] = talloc_strdup(del_groups, "testgroup28003"); + del_groups[2] = NULL; + + req = sysdb_update_members_send(data, data->ev, data->handle, + data->ctx->domain, user, + NULL, del_groups); + talloc_free(del_groups); + talloc_free(user); + if (!req) { + DEBUG(0, ("Could not del groups\n")); + test_return(data, EIO); + return; + } + + tevent_req_set_callback(req, test_sysdb_update_members_done, data); +} + +static void test_sysdb_update_members_done(struct tevent_req *req) +{ + struct test_data *data = tevent_req_callback_data(req, struct test_data); + errno_t ret; + + ret = sysdb_update_members_recv(req); + talloc_zfree(req); + if (ret != EOK) { + DEBUG(0, ("Group delete failed [%d](%s)\n", ret, strerror(ret))); + } + test_return(data, ret); +} + Suite *create_sysdb_suite(void) { Suite *s = suite_create("sysdb"); @@ -3177,6 +3342,9 @@ Suite *create_sysdb_suite(void) /* test the change */ tcase_add_loop_test(tc_sysdb, test_sysdb_get_user_attr, 27000, 27010); + /* Add and remove users in a group with sysdb_update_members */ + tcase_add_test(tc_sysdb, test_sysdb_update_members); + /* Remove the other half by gid */ tcase_add_loop_test(tc_sysdb, test_sysdb_remove_local_group_by_gid, 28000, 28010); -- cgit