From ad5f4a73703e52de258aa22bcef17af29ae30f2a Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Sun, 25 Sep 2011 10:02:09 -0400
Subject: [PATCH 10/11] LDAP: Add multiple search bases for initgroups
 (RFC2307bis groups)

---
 src/providers/ldap/sdap_async_initgroups.c |  288 +++++++++++++++++++++-------
 1 files changed, 217 insertions(+), 71 deletions(-)

diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c
index a4a39e5ede469d00bf6f7da81f0f5da7f3f50d4c..89c2e2b284bc169a71c9e83c4f5a4d1a2cdf974b 100644
--- a/src/providers/ldap/sdap_async_initgroups.c
+++ b/src/providers/ldap/sdap_async_initgroups.c
@@ -242,6 +242,7 @@ struct sdap_initgr_rfc2307_state {
     const char **attrs;
     const char *name;
     const char *base_filter;
+    const char *orig_dn;
     char *filter;
     int timeout;
 
@@ -1054,6 +1055,7 @@ static int sdap_initgr_nested_recv(struct tevent_req *req)
 
 /* ==Initgr-call-(groups-a-user-is-member-of)-RFC2307-BIS================= */
 
+static errno_t sdap_initgr_rfc2307bis_next_base(struct tevent_req *req);
 static void sdap_initgr_rfc2307bis_process(struct tevent_req *subreq);
 static void sdap_initgr_rfc2307bis_done(struct tevent_req *subreq);
 errno_t save_rfc2307bis_user_memberships(
@@ -1073,16 +1075,12 @@ static struct tevent_req *sdap_initgr_rfc2307bis_send(
         struct sysdb_ctx *sysdb,
         struct sss_domain_info *dom,
         struct sdap_handle *sh,
-        const char *base_dn,
         const char *name,
         const char *orig_dn)
 {
     errno_t ret;
     struct tevent_req *req;
-    struct tevent_req *subreq;
     struct sdap_initgr_rfc2307_state *state;
-    const char *filter;
-    const char **attrs;
     char *clean_orig_dn;
 
     req = tevent_req_create(memctx, &state, struct sdap_initgr_rfc2307_state);
@@ -1095,46 +1093,85 @@ static struct tevent_req *sdap_initgr_rfc2307bis_send(
     state->sh = sh;
     state->op = NULL;
     state->name = name;
+    state->ldap_groups = NULL;
+    state->ldap_groups_count = 0;
+    state->timeout = dp_opt_get_int(state->opts->basic, SDAP_SEARCH_TIMEOUT);
+    state->orig_dn = orig_dn;
+    state->base_iter = 0;
+    state->search_bases = opts->group_search_bases;
 
     ret = build_attrs_from_map(state, opts->group_map,
-                               SDAP_OPTS_GROUP, &attrs);
+                               SDAP_OPTS_GROUP, &state->attrs);
     if (ret != EOK) {
-        talloc_free(req);
-        return NULL;
+        tevent_req_error(req, ret);
+        tevent_req_post(req, ev);
+        return req;
     }
 
     ret = sss_filter_sanitize(state, orig_dn, &clean_orig_dn);
     if (ret != EOK) {
-        talloc_free(req);
-        return NULL;
+        tevent_req_error(req, ret);
+        tevent_req_post(req, ev);
+        return req;
     }
 
-    filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s)(%s=*))",
-                             opts->group_map[SDAP_AT_GROUP_MEMBER].name,
-                             clean_orig_dn,
-                             opts->group_map[SDAP_OC_GROUP].name,
-                             opts->group_map[SDAP_AT_GROUP_NAME].name);
-    if (!filter) {
-        talloc_zfree(req);
-        return NULL;
+    state->base_filter =
+            talloc_asprintf(state, "(&(%s=%s)(objectclass=%s)(%s=*))",
+                            opts->group_map[SDAP_AT_GROUP_MEMBER].name,
+                            clean_orig_dn,
+                            opts->group_map[SDAP_OC_GROUP].name,
+                            opts->group_map[SDAP_AT_GROUP_NAME].name);
+    if (!state->base_filter) {
+        tevent_req_error(req, ENOMEM);
+        tevent_req_post(req, ev);
+        return req;
     }
     talloc_zfree(clean_orig_dn);
 
-    DEBUG(6, ("Looking up parent groups for user [%s]\n", orig_dn));
-    subreq = sdap_get_generic_send(state, state->ev, state->opts,
-                                   state->sh, base_dn, LDAP_SCOPE_SUBTREE,
-                                   filter, attrs,
-                                   state->opts->group_map, SDAP_OPTS_GROUP,
-                                   dp_opt_get_int(state->opts->basic,
-                                                  SDAP_SEARCH_TIMEOUT));
+    ret = sdap_initgr_rfc2307bis_next_base(req);
+    if (ret != EOK) {
+        tevent_req_error(req, ENOMEM);
+        tevent_req_post(req, ev);
+    }
+
+    return req;
+
+}
+
+static errno_t sdap_initgr_rfc2307bis_next_base(struct tevent_req *req)
+{
+    struct tevent_req *subreq;
+    struct sdap_initgr_rfc2307_state *state;
+
+    state = tevent_req_data(req, struct sdap_initgr_rfc2307_state);
+
+    talloc_zfree(state->filter);
+    state->filter = sdap_get_id_specific_filter(
+            state,
+            state->base_filter,
+            state->search_bases[state->base_iter]->filter);
+    if (!state->filter) {
+        return ENOMEM;
+    }
+
+    DEBUG(SSSDBG_TRACE_FUNC,
+          ("Searching for parent groups for user [%s] with base [%s]\n",
+           state->orig_dn, state->search_bases[state->base_iter]->basedn));
+
+    subreq = sdap_get_generic_send(
+            state, state->ev, state->opts, state->sh,
+            state->search_bases[state->base_iter]->basedn,
+            state->search_bases[state->base_iter]->scope,
+            state->filter, state->attrs,
+            state->opts->group_map, SDAP_OPTS_GROUP,
+            state->timeout);
     if (!subreq) {
         talloc_zfree(req);
-        return NULL;
+        return ENOMEM;
     }
     tevent_req_set_callback(subreq, sdap_initgr_rfc2307bis_process, req);
 
-    return req;
-
+    return EOK;
 }
 
 static void sdap_initgr_rfc2307bis_process(struct tevent_req *subreq)
@@ -1142,19 +1179,59 @@ static void sdap_initgr_rfc2307bis_process(struct tevent_req *subreq)
     struct tevent_req *req;
     struct sdap_initgr_rfc2307_state *state;
     int ret;
+    struct sysdb_attrs **ldap_groups;
+    size_t count;
+    size_t i;
 
     req = tevent_req_callback_data(subreq, struct tevent_req);
     state = tevent_req_data(req, struct sdap_initgr_rfc2307_state);
 
     ret = sdap_get_generic_recv(subreq, state,
-                                &state->ldap_groups_count,
-                                &state->ldap_groups);
+                                &count,
+                                &ldap_groups);
     talloc_zfree(subreq);
     if (ret) {
         tevent_req_error(req, ret);
         return;
     }
 
+    /* Add this batch of groups to the list */
+    if (count > 0) {
+        state->ldap_groups =
+                talloc_realloc(state,
+                               state->ldap_groups,
+                               struct sysdb_attrs *,
+                               state->ldap_groups_count + count + 1);
+        if (!state->ldap_groups) {
+            tevent_req_error(req, ret);
+            return;
+        }
+
+        /* Copy the new groups into the list.
+         * They're already allocated on 'state'.
+         */
+        for (i = 0; i < count; i++) {
+            state->ldap_groups[state->ldap_groups_count + i] = ldap_groups[i];
+        }
+
+        state->ldap_groups_count += count;
+
+        state->ldap_groups[state->ldap_groups_count] = NULL;
+    }
+
+    state->base_iter++;
+
+    /* Check for additional search bases, and iterate
+     * through again.
+     */
+    if (state->search_bases[state->base_iter] != NULL) {
+        ret = sdap_initgr_rfc2307bis_next_base(req);
+        if (ret != EOK) {
+            tevent_req_error(req, ret);
+        }
+        return;
+    }
+
     if (state->ldap_groups_count == 0) {
         /* Start a transaction to look up the groups in the sysdb
          * and update them with LDAP data
@@ -1363,6 +1440,11 @@ struct sdap_rfc2307bis_nested_ctx {
     struct sysdb_ctx *sysdb;
     struct sss_domain_info *dom;
     struct sdap_handle *sh;
+    int timeout;
+    const char *base_filter;
+    char *filter;
+    const char *orig_dn;
+    const char **attrs;
     struct sysdb_attrs **groups;
     size_t num_groups;
 
@@ -1373,6 +1455,9 @@ struct sdap_rfc2307bis_nested_ctx {
     size_t ldap_groups_count;
 
     struct sysdb_handle *handle;
+
+    size_t base_iter;
+    struct sdap_search_base **search_bases;
 };
 
 static errno_t rfc2307bis_nested_groups_step(struct tevent_req *req);
@@ -1408,6 +1493,9 @@ struct tevent_req *rfc2307bis_nested_groups_send(
     state->num_groups = num_groups;
     state->group_iter = 0;
     state->nesting_level = nesting;
+    state->timeout = dp_opt_get_int(state->opts->basic, SDAP_SEARCH_TIMEOUT);
+    state->base_iter = 0;
+    state->search_bases = opts->group_search_bases;
 
     ret = rfc2307bis_nested_groups_step(req);
     if (ret != EOK) {
@@ -1417,19 +1505,16 @@ struct tevent_req *rfc2307bis_nested_groups_send(
     return req;
 }
 
+static errno_t rfc2307bis_nested_groups_next_base(struct tevent_req *req);
 static void rfc2307bis_nested_groups_process(struct tevent_req *subreq);
 static errno_t rfc2307bis_nested_groups_step(struct tevent_req *req)
 {
     errno_t ret, tret;
-    struct tevent_req *subreq;
     const char *name;
     struct sysdb_attrs **grouplist;
     char **groupnamelist;
     bool in_transaction = false;
     TALLOC_CTX *tmp_ctx = NULL;
-    char *filter;
-    const char *orig_dn;
-    const char **attrs;
     char *clean_orig_dn;
     struct sdap_rfc2307bis_nested_ctx *state =
             tevent_req_data(req, struct sdap_rfc2307bis_nested_ctx);
@@ -1498,65 +1583,86 @@ static errno_t rfc2307bis_nested_groups_step(struct tevent_req *req)
     /* Get any parent groups for this group */
     ret = sysdb_attrs_get_string(state->groups[state->group_iter],
                                  SYSDB_ORIG_DN,
-                                 &orig_dn);
+                                 &state->orig_dn);
     if (ret != EOK) {
         goto error;
     }
 
-    ret = build_attrs_from_map(tmp_ctx, state->opts->group_map,
-                               SDAP_OPTS_GROUP, &attrs);
+    ret = build_attrs_from_map(state, state->opts->group_map,
+                               SDAP_OPTS_GROUP, &state->attrs);
     if (ret != EOK) {
         goto error;
     }
 
-    ret = sss_filter_sanitize(state, orig_dn, &clean_orig_dn);
+    ret = sss_filter_sanitize(tmp_ctx, state->orig_dn, &clean_orig_dn);
     if (ret != EOK) {
         goto error;
     }
 
-    filter = talloc_asprintf(
-            tmp_ctx, "(&(%s=%s)(objectclass=%s)(%s=*))",
+    state->base_filter = talloc_asprintf(
+            state, "(&(%s=%s)(objectclass=%s)(%s=*))",
             state->opts->group_map[SDAP_AT_GROUP_MEMBER].name,
             clean_orig_dn,
             state->opts->group_map[SDAP_OC_GROUP].name,
             state->opts->group_map[SDAP_AT_GROUP_NAME].name);
-    if (!filter) {
+    if (!state->base_filter) {
         ret = ENOMEM;
         goto error;
     }
-    talloc_zfree(clean_orig_dn);
-
-    DEBUG(6, ("Looking up parent groups for group [%s]\n", orig_dn));
-    subreq = sdap_get_generic_send(state, state->ev, state->opts,
-                                   state->sh,
-                                   dp_opt_get_string(state->opts->basic,
-                                                     SDAP_GROUP_SEARCH_BASE),
-                                   LDAP_SCOPE_SUBTREE,
-                                   filter, attrs,
-                                   state->opts->group_map, SDAP_OPTS_GROUP,
-                                   dp_opt_get_int(state->opts->basic,
-                                                  SDAP_SEARCH_TIMEOUT));
+
+    ret = rfc2307bis_nested_groups_next_base(req);
+    if (ret != EOK) goto error;
+
+    talloc_free(tmp_ctx);
+    return EOK;
+
+error:
+    if (in_transaction) {
+        tret = sysdb_transaction_cancel(state->sysdb);
+        if (tret != EOK) {
+            DEBUG(1, ("Failed to cancel transaction\n"));
+        }
+    }
+
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
+static errno_t rfc2307bis_nested_groups_next_base(struct tevent_req *req)
+{
+    struct tevent_req *subreq;
+    struct sdap_rfc2307bis_nested_ctx *state;
+
+    state = tevent_req_data(req, struct sdap_rfc2307bis_nested_ctx);
+
+    talloc_zfree(state->filter);
+    state->filter = sdap_get_id_specific_filter(
+            state, state->base_filter,
+            state->search_bases[state->base_iter]->filter);
+    if (!state->filter) {
+        return ENOMEM;
+    }
+
+    DEBUG(SSSDBG_TRACE_FUNC,
+          ("Searching for parent groups of group [%s] with base [%s]\n",
+           state->orig_dn,
+           state->search_bases[state->base_iter]->basedn));
+
+    subreq = sdap_get_generic_send(
+            state, state->ev, state->opts, state->sh,
+            state->search_bases[state->base_iter]->basedn,
+            state->search_bases[state->base_iter]->scope,
+            state->filter, state->attrs,
+            state->opts->group_map, SDAP_OPTS_GROUP,
+            state->timeout);
     if (!subreq) {
-        ret = EIO;
-        goto error;
+        return ENOMEM;
     }
-    talloc_steal(subreq, tmp_ctx);
     tevent_req_set_callback(subreq,
                             rfc2307bis_nested_groups_process,
                             req);
 
     return EOK;
-
-error:
-    if (in_transaction) {
-        tret = sysdb_transaction_cancel(state->sysdb);
-        if (tret != EOK) {
-            DEBUG(1, ("Failed to cancel transaction\n"));
-        }
-    }
-
-    talloc_free(tmp_ctx);
-    return ret;
 }
 
 static errno_t rfc2307bis_nested_groups_update_sysdb(
@@ -1569,16 +1675,59 @@ static void rfc2307bis_nested_groups_process(struct tevent_req *subreq)
             tevent_req_callback_data(subreq, struct tevent_req);
     struct sdap_rfc2307bis_nested_ctx *state =
             tevent_req_data(req, struct sdap_rfc2307bis_nested_ctx);
+    size_t count;
+    size_t i;
+    struct sysdb_attrs **ldap_groups;
 
     ret = sdap_get_generic_recv(subreq, state,
-                                &state->ldap_groups_count,
-                                &state->ldap_groups);
+                                &count,
+                                &ldap_groups);
     talloc_zfree(subreq);
     if (ret) {
         tevent_req_error(req, ret);
         return;
     }
 
+    /* Add this batch of groups to the list */
+    if (count > 0) {
+        state->ldap_groups =
+                talloc_realloc(state,
+                               state->ldap_groups,
+                               struct sysdb_attrs *,
+                               state->ldap_groups_count + count + 1);
+        if (!state->ldap_groups) {
+            tevent_req_error(req, ret);
+            return;
+        }
+
+        /* Copy the new groups into the list.
+         * They're already allocated on 'state'.
+         */
+        for (i = 0; i < count; i++) {
+            state->ldap_groups[state->ldap_groups_count + i] = ldap_groups[i];
+        }
+
+        state->ldap_groups_count += count;
+
+        state->ldap_groups[state->ldap_groups_count] = NULL;
+    }
+
+    state->base_iter++;
+
+    /* Check for additional search bases, and iterate
+     * through again.
+     */
+    if (state->search_bases[state->base_iter] != NULL) {
+        ret = rfc2307bis_nested_groups_next_base(req);
+        if (ret != EOK) {
+            tevent_req_error(req, ret);
+        }
+        return;
+    }
+
+    /* Reset the base iterator for future lookups */
+    state->base_iter = 0;
+
     if (state->ldap_groups_count == 0) {
         /* No parent groups for this group in LDAP
          * We need to ensure that there are no groups
@@ -1953,7 +2102,6 @@ static struct tevent_req *sdap_initgr_rfc2307bis_send(
         struct sysdb_ctx *sysdb,
         struct sss_domain_info *dom,
         struct sdap_handle *sh,
-        const char *base_dn,
         const char *name,
         const char *orig_dn);
 static void sdap_get_initgr_user(struct tevent_req *subreq)
@@ -2054,8 +2202,6 @@ static void sdap_get_initgr_user(struct tevent_req *subreq)
         subreq = sdap_initgr_rfc2307bis_send(
                 state, state->ev, state->opts, state->sysdb,
                 state->dom, state->sh,
-                dp_opt_get_string(state->opts->basic,
-                                  SDAP_GROUP_SEARCH_BASE),
                 state->name, orig_dn);
         if (!subreq) {
             tevent_req_error(req, ENOMEM);
-- 
1.7.6.2

