From b7b5c48d3af1925a857d68b047b179e1c081f131 Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Wed, 28 Jul 2010 12:24:39 -0400
Subject: [PATCH 5/6] 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
---
 src/db/sysdb.h     |   10 +++
 src/db/sysdb_ops.c |  161 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 171 insertions(+), 0 deletions(-)

diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index aec2809cab1b794eddf08cd133aa9d3cfda52d2b..c838fb96b3f845d0cadd5c9c534d4a0a3cd36b84 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 6fcc95b19223ae9ee029519f54da524f16514c28..0b0ca59e0dc966817d441736ac0a5fdc1f0b44f5 100644
--- a/src/db/sysdb_ops.c
+++ b/src/db/sysdb_ops.c
@@ -5065,3 +5065,164 @@ 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;
+    char *add_group_iter;
+
+    char **del_groups;
+    char *del_group_iter;
+};
+
+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 = user;
+    state->domain = domain;
+    state->ev = ev;
+    state->handle = handle;
+
+    state->add_groups = dup_string_list(state, add_groups);
+    if (!state->add_groups) {
+        goto error;
+    }
+    state->add_group_iter = state->add_groups[0];
+
+    state->del_groups = dup_string_list(state, del_groups);
+    if (!state->del_groups) {
+        goto error;
+    }
+    state->add_group_iter = state->add_groups[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_group_iter) {
+        subreq = sysdb_add_group_member_send(state, state->ev, state->handle,
+                                             state->domain,
+                                             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_group_iter) {
+        subreq = sysdb_remove_group_member_send(state, state->ev,
+                                                state->handle, state->domain,
+                                                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);
+}
-- 
1.7.2

