From bc7378a8999bc7a077ddd18e62749eb7230433ee Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Fri, 16 Sep 2011 15:17:28 -0400
Subject: [PATCH 07/14] LDAP: Support multiple group search bases
 (non-enumeration, RFC2307)

---
 src/providers/ldap/ldap_id.c           |    4 +-
 src/providers/ldap/ldap_id_enum.c      |    8 +++-
 src/providers/ldap/sdap_async.h        |    3 +-
 src/providers/ldap/sdap_async_groups.c |   78 ++++++++++++++++++++++++++-----
 4 files changed, 77 insertions(+), 16 deletions(-)

diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
index f3a2a1b3a561bb5fdb2014ad3a0ae0771fed8aaa..607fd27841cb34abb8684923f5bd68e92e3f7f79 100644
--- a/src/providers/ldap/ldap_id.c
+++ b/src/providers/ldap/ldap_id.c
@@ -422,7 +422,9 @@ static void groups_get_connect_done(struct tevent_req *subreq)
 
     subreq = sdap_get_groups_send(state, state->ev,
                                   state->domain, state->sysdb,
-                                  state->ctx->opts, sdap_id_op_handle(state->op),
+                                  state->ctx->opts,
+                                  state->ctx->opts->group_search_bases,
+                                  sdap_id_op_handle(state->op),
                                   state->attrs, state->filter,
                                   dp_opt_get_int(state->ctx->opts->basic,
                                                  SDAP_SEARCH_TIMEOUT));
diff --git a/src/providers/ldap/ldap_id_enum.c b/src/providers/ldap/ldap_id_enum.c
index d85c52203d611ba516174f3d2fe0700fdd401bfa..d49b64dd8663854e258f714b93325a0b162189a7 100644
--- a/src/providers/ldap/ldap_id_enum.c
+++ b/src/providers/ldap/ldap_id_enum.c
@@ -614,10 +614,16 @@ static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
                                SDAP_OPTS_GROUP, &state->attrs);
     if (ret != EOK) goto fail;
 
+    /* TODO: restrict the enumerations to using a single
+     * search base at a time.
+     */
+
     subreq = sdap_get_groups_send(state, state->ev,
                                  state->ctx->be->domain,
                                  state->ctx->be->sysdb,
-                                 state->ctx->opts, sdap_id_op_handle(state->op),
+                                 state->ctx->opts,
+                                 state->ctx->opts->group_search_bases,
+                                 sdap_id_op_handle(state->op),
                                  state->attrs, state->filter,
                                  dp_opt_get_int(state->ctx->opts->basic,
                                                 SDAP_ENUM_SEARCH_TIMEOUT));
diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
index 2ef5ff24787d7f27f9b1427a25ef0685a22c5680..ef18c775a35a4ff6b25ee0bd4e5432815700a088 100644
--- a/src/providers/ldap/sdap_async.h
+++ b/src/providers/ldap/sdap_async.h
@@ -58,9 +58,10 @@ struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx,
                                        struct sss_domain_info *dom,
                                        struct sysdb_ctx *sysdb,
                                        struct sdap_options *opts,
+                                       struct sdap_search_base **search_bases,
                                        struct sdap_handle *sh,
                                        const char **attrs,
-                                       const char *wildcard,
+                                       const char *filter,
                                        int timeout);
 int sdap_get_groups_recv(struct tevent_req *req,
                          TALLOC_CTX *mem_ctx, char **timestamp);
diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c
index 1e8e4b3d8766fec9f0907ef61e27e542cd769731..4c382fb84f09c25c4a7278b7b07b597ff4163c38 100644
--- a/src/providers/ldap/sdap_async_groups.c
+++ b/src/providers/ldap/sdap_async_groups.c
@@ -1185,7 +1185,9 @@ struct sdap_get_groups_state {
     struct sss_domain_info *dom;
     struct sysdb_ctx *sysdb;
     const char **attrs;
-    const char *filter;
+    const char *base_filter;
+    char *filter;
+    int timeout;
 
     char *higher_usn;
     struct sysdb_attrs **groups;
@@ -1194,8 +1196,12 @@ struct sdap_get_groups_state {
 
     hash_table_t *user_hash;
     hash_table_t *group_hash;
+
+    size_t base_iter;
+    struct sdap_search_base **search_bases;
 };
 
+static errno_t sdap_get_groups_next_base(struct tevent_req *req);
 static void sdap_get_groups_process(struct tevent_req *subreq);
 static void sdap_get_groups_done(struct tevent_req *subreq);
 
@@ -1204,12 +1210,14 @@ struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx,
                                        struct sss_domain_info *dom,
                                        struct sysdb_ctx *sysdb,
                                        struct sdap_options *opts,
+                                       struct sdap_search_base **search_bases,
                                        struct sdap_handle *sh,
                                        const char **attrs,
                                        const char *filter,
                                        int timeout)
 {
-    struct tevent_req *req, *subreq;
+    errno_t ret;
+    struct tevent_req *req;
     struct sdap_get_groups_state *state;
 
     req = tevent_req_create(memctx, &state, struct sdap_get_groups_state);
@@ -1220,26 +1228,56 @@ struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx,
     state->dom = dom;
     state->sh = sh;
     state->sysdb = sysdb;
-    state->filter = filter;
     state->attrs = attrs;
     state->higher_usn = NULL;
     state->groups =  NULL;
     state->count = 0;
+    state->timeout = timeout;
+    state->base_filter = filter;
+    state->base_iter = 0;
+    state->search_bases = search_bases;
 
-    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,
-                                   state->filter, state->attrs,
-                                   state->opts->group_map, SDAP_OPTS_GROUP,
-                                   timeout);
+    ret = sdap_get_groups_next_base(req);
+    if (ret != EOK) {
+        tevent_req_error(req, ret);
+        tevent_req_post(req, ev);
+    }
+
+    return req;
+}
+
+static errno_t sdap_get_groups_next_base(struct tevent_req *req)
+{
+    struct tevent_req *subreq;
+    struct sdap_get_groups_state *state;
+
+    state = tevent_req_data(req, struct sdap_get_groups_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 groups with base [%s]\n",
+           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_get_groups_process, req);
 
-    return req;
+    return EOK;
 }
 
 static struct tevent_req *sdap_nested_group_process_send(
@@ -1273,6 +1311,20 @@ static void sdap_get_groups_process(struct tevent_req *subreq)
 
     switch(state->count) {
     case 0:
+        /* No groups found in this search */
+        talloc_zfree(state->groups);
+        talloc_zfree(state->filter);
+
+        state->base_iter++;
+        if (state->search_bases[state->base_iter]) {
+            /* There are more search bases to try */
+            ret = sdap_get_groups_next_base(req);
+            if (ret != EOK) {
+                tevent_req_error(req, ret);
+            }
+            return;
+        }
+
         tevent_req_error(req, ENOENT);
         return;
 
-- 
1.7.6.4

