From 3b424a435eda09336f2d02008eb22e5839595417 Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Mon, 3 Oct 2011 14:23:22 -0400
Subject: [PATCH 14/14] LDAP: Add support for multiple search bases for group
 enumeration

---
 src/providers/ldap/ldap_id.c           |    3 +-
 src/providers/ldap/ldap_id_enum.c      |    3 +-
 src/providers/ldap/sdap_async.h        |    3 +-
 src/providers/ldap/sdap_async_groups.c |   83 +++++++++++++++++++++++--------
 4 files changed, 67 insertions(+), 25 deletions(-)

diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
index c381c19b1bf56f6a66bde46ba15d655f1995abac..d300184886244e030fb9fdd629d2596f3c54922b 100644
--- a/src/providers/ldap/ldap_id.c
+++ b/src/providers/ldap/ldap_id.c
@@ -408,7 +408,8 @@ static void groups_get_connect_done(struct tevent_req *subreq)
                                   sdap_id_op_handle(state->op),
                                   state->attrs, state->filter,
                                   dp_opt_get_int(state->ctx->opts->basic,
-                                                 SDAP_SEARCH_TIMEOUT));
+                                                 SDAP_SEARCH_TIMEOUT),
+                                  false);
     if (!subreq) {
         tevent_req_error(req, ENOMEM);
         return;
diff --git a/src/providers/ldap/ldap_id_enum.c b/src/providers/ldap/ldap_id_enum.c
index 9923379db94b7cb46daa5da8795d5c08c4d96695..7a8d0712ec8a93a3b5d97bfb12b133a65d767996 100644
--- a/src/providers/ldap/ldap_id_enum.c
+++ b/src/providers/ldap/ldap_id_enum.c
@@ -607,7 +607,8 @@ static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
                                  sdap_id_op_handle(state->op),
                                  state->attrs, state->filter,
                                  dp_opt_get_int(state->ctx->opts->basic,
-                                                SDAP_ENUM_SEARCH_TIMEOUT));
+                                                SDAP_ENUM_SEARCH_TIMEOUT),
+                                 true);
     if (!subreq) {
         ret = ENOMEM;
         goto fail;
diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
index 262c04a0d5096bb57b95ba0b15c60feed267e359..e628c7daa096929dac9583bed0a80f8f295066ea 100644
--- a/src/providers/ldap/sdap_async.h
+++ b/src/providers/ldap/sdap_async.h
@@ -63,7 +63,8 @@ struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx,
                                        struct sdap_handle *sh,
                                        const char **attrs,
                                        const char *filter,
-                                       int timeout);
+                                       int timeout,
+                                       bool enumeration);
 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 bc1787d59f267f37b8a85a168a3ebbd3521f931f..fd7cd2c505ab5993edce8e09fbd8ea31d70b7a7e 100644
--- a/src/providers/ldap/sdap_async_groups.c
+++ b/src/providers/ldap/sdap_async_groups.c
@@ -1188,6 +1188,7 @@ struct sdap_get_groups_state {
     const char *base_filter;
     char *filter;
     int timeout;
+    bool enumeration;
 
     char *higher_usn;
     struct sysdb_attrs **groups;
@@ -1214,7 +1215,8 @@ struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx,
                                        struct sdap_handle *sh,
                                        const char **attrs,
                                        const char *filter,
-                                       int timeout)
+                                       int timeout,
+                                       bool enumeration)
 {
     errno_t ret;
     struct tevent_req *req;
@@ -1233,6 +1235,7 @@ struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx,
     state->groups =  NULL;
     state->count = 0;
     state->timeout = timeout;
+    state->enumeration = enumeration;
     state->base_filter = filter;
     state->base_iter = 0;
     state->search_bases = search_bases;
@@ -1297,22 +1300,55 @@ static void sdap_get_groups_process(struct tevent_req *subreq)
                         tevent_req_data(req, struct sdap_get_groups_state);
     int ret;
     int i;
-    bool enumeration = false;
+    bool next_base = false;
+    size_t count;
+    struct sysdb_attrs **groups;
 
     ret = sdap_get_generic_recv(subreq, state,
-                                &state->count, &state->groups);
+                                &count, &groups);
     talloc_zfree(subreq);
     if (ret) {
         tevent_req_error(req, ret);
         return;
     }
 
-    DEBUG(6, ("Search for groups, returned %d results.\n", state->count));
+    DEBUG(6, ("Search for groups, returned %d results.\n", count));
 
-    switch(state->count) {
-    case 0:
-        /* No groups found in this search */
-        talloc_zfree(state->groups);
+    if (!state->enumeration && count > 1) {
+        DEBUG(SSSDBG_MINOR_FAILURE,
+              ("Individual group search returned multiple results\n"));
+        tevent_req_error(req, EINVAL);
+        return;
+    }
+
+    if (state->enumeration || count == 0) {
+        next_base = true;
+    }
+
+    /* Add this batch of groups to the list */
+    if (count > 0) {
+        state->groups =
+                talloc_realloc(state,
+                               state->groups,
+                               struct sysdb_attrs *,
+                               state->count + count + 1);
+        if (!state->groups) {
+            tevent_req_error(req, ENOMEM);
+            return;
+        }
+
+        /* Copy the new groups into the list
+         * They're already allocated on 'state'
+         */
+        for (i = 0; i < count; i++) {
+            state->groups[state->count + i] = groups[i];
+        }
+
+        state->count += count;
+        state->groups[state->count] = NULL;
+    }
+
+    if (next_base) {
         talloc_zfree(state->filter);
 
         state->base_iter++;
@@ -1324,12 +1360,22 @@ static void sdap_get_groups_process(struct tevent_req *subreq)
             }
             return;
         }
+    }
 
+    /* No more search bases
+     * Return ENOENT if no groups were found
+     */
+    if (state->count == 0) {
         tevent_req_error(req, ENOENT);
         return;
+    }
 
-    case 1:
-        /* Single group search */
+    /* Check whether we need to do nested searches
+     * for RFC2307bis/FreeIPA/ActiveDirectory
+     * We don't need to do this for enumeration,
+     * because all groups will be picked up anyway.
+     */
+    if (!state->enumeration) {
         if ((state->opts->schema_type != SDAP_SCHEMA_RFC2307) &&
             (dp_opt_get_int(state->opts->basic, SDAP_NESTING_LEVEL) != 0)) {
 
@@ -1363,17 +1409,10 @@ static void sdap_get_groups_process(struct tevent_req *subreq)
 
             tevent_req_set_callback(subreq, sdap_nested_done, req);
             return;
-        } else {
-            /* RFC2307 or disabled nested groups */
-            break;
         }
-
-    default:
-        /* Enumeration */
-        enumeration = true;
-        break;
     }
 
+    /* We have all of the groups. Save them to the sysdb */
     state->check_count = state->count;
 
     ret = sysdb_transaction_start(state->sysdb);
@@ -1383,9 +1422,9 @@ static void sdap_get_groups_process(struct tevent_req *subreq)
         return;
     }
 
-    if (enumeration && (state->opts->schema_type != SDAP_SCHEMA_RFC2307) &&
-        (dp_opt_get_int(state->opts->basic, SDAP_NESTING_LEVEL) != 0)) {
-
+    if (state->enumeration
+            && state->opts->schema_type != SDAP_SCHEMA_RFC2307
+            && dp_opt_get_int(state->opts->basic, SDAP_NESTING_LEVEL) != 0) {
         DEBUG(9, ("Saving groups without members first "
                   "to allow unrolling of nested groups.\n"));
         ret = sdap_save_groups(state, state->sysdb, state->dom, state->opts,
@@ -1401,7 +1440,7 @@ static void sdap_get_groups_process(struct tevent_req *subreq)
         subreq = sdap_process_group_send(state, state->ev, state->dom,
                                          state->sysdb, state->opts,
                                          state->sh, state->groups[i],
-                                         enumeration);
+                                         state->enumeration);
 
         if (!subreq) {
             tevent_req_error(req, ENOMEM);
-- 
1.7.6.2

