summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Gallagher <sgallagh@redhat.com>2010-07-28 12:24:39 -0400
committerStephen Gallagher <sgallagh@redhat.com>2010-07-30 15:57:58 -0400
commit41edee286a924ec00ed9b9fc8a9cb37539fc6237 (patch)
tree2f21c6ca6d7461d372ddb637e0531c226264f3c4
parentd412e76b28894271a29ce53eac47de562fc86a59 (diff)
downloadsssd-41edee286a924ec00ed9b9fc8a9cb37539fc6237.tar.gz
sssd-41edee286a924ec00ed9b9fc8a9cb37539fc6237.tar.xz
sssd-41edee286a924ec00ed9b9fc8a9cb37539fc6237.zip
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
-rw-r--r--src/db/sysdb.h10
-rw-r--r--src/db/sysdb_ops.c191
-rw-r--r--src/tests/sysdb-tests.c168
3 files changed, 369 insertions, 0 deletions
diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 2de2a6485..04ce49e66 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 6fcc95b19..52102706c 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 584335ed7..5bdc00547 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);