Hi,

the attached patches address ticket
https://fedorahosted.org/sssd/ticket/2142

There are some things I'm still not satisfied with and one of them is
refreshing subdomains. Currently the subdomain refresh happens after
startup and then only if a direct lookup for a user or group happens and
the timeout for subdomain refresh is over. So in theory it's possible
that the user and group objects will be refreshed by the enumeration
task only and there would be no lookup to trigger the subdomain refresh.

With master domain enumeration we've solved this problem by
re-downloading master domain info before the enumeration request. We
could do something similar with subdomains (although a little more
involved becase there is always precisely one subdomain), but I didn't
like doing all the changes in 1.11.3. I can code up additional patch
only for master, though.

Something similar is with fallback from GC to LDAP. Although here I'm
not convinced we need to perform the fallback at all, since there are
already patches on the list that implement the option to disable GC
lookups and there will also be a patch to autodetect POSIX attributes in
GC.

These patches must be applied on top of my previous patches.
>From 56380e444a8085aa457bd046841a3338ba061bfc Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhro...@redhat.com>
Date: Tue, 10 Dec 2013 17:33:35 +0100
Subject: [PATCH 1/4] AD: Store info on whether a subdomain is set to enumerate

Depending on the state of the subdomain_enumerate variable, the newly
created subdomain object is created with the right value of "enumerate"
attribute in the sysdb.
---
 src/providers/ad/ad_subdomains.c | 38 +++++++++++++++++++++++++++++++++-----
 1 file changed, 33 insertions(+), 5 deletions(-)

diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
index 
e438a688c364084a3f2bbca338a39d61aa86b5d6..3bbf801e9fb44a164684e84a2f5a5f03267b6575
 100644
--- a/src/providers/ad/ad_subdomains.c
+++ b/src/providers/ad/ad_subdomains.c
@@ -222,10 +222,28 @@ ads_store_sdap_subdom(struct ad_subdomains_ctx *ctx,
     return EOK;
 }
 
+static errno_t ad_subdom_enumerates(struct sss_domain_info *parent,
+                                    struct sysdb_attrs *attrs,
+                                    bool *_enumerates)
+{
+    errno_t ret;
+    const char *name;
+
+    ret = sysdb_attrs_get_string(attrs, AD_AT_TRUST_PARTNER, &name);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_string failed.\n"));
+        return ret;
+    }
+
+    *_enumerates = subdomain_enumerates(parent, name);
+    return EOK;
+}
+
 static errno_t
 ad_subdom_store(struct ad_subdomains_ctx *ctx,
                 struct sss_domain_info *domain,
-                struct sysdb_attrs *subdom_attrs)
+                struct sysdb_attrs *subdom_attrs,
+                bool enumerate)
 {
     TALLOC_CTX *tmp_ctx;
     const char *name;
@@ -292,9 +310,8 @@ ad_subdom_store(struct ad_subdomains_ctx *ctx,
                                              name,
                                              sid_str);
 
-    /* AD subdomains are currently all mpg and do not enumerate */
     ret = sysdb_subdomain_store(domain->sysdb, name, realm, flat, sid_str,
-                                mpg, false, NULL);
+                                mpg, enumerate, NULL);
     if (ret != EOK) {
         DEBUG(SSSDBG_OP_FAILURE, ("sysdb_subdomain_store failed.\n"));
         goto done;
@@ -318,6 +335,7 @@ static errno_t ad_subdomains_refresh(struct 
ad_subdomains_ctx *ctx,
     const char *value;
     int c, h;
     int ret;
+    bool enumerate;
 
     domain = ctx->be_ctx->domain;
     memset(handled, 0, sizeof(bool) * count);
@@ -366,7 +384,12 @@ static errno_t ad_subdomains_refresh(struct 
ad_subdomains_ctx *ctx,
             talloc_zfree(sdom);
         } else {
             /* ok let's try to update it */
-            ret = ad_subdom_store(ctx, domain, reply[c]);
+            ret = ad_subdom_enumerates(domain, reply[c], &enumerate);
+            if (ret != EOK) {
+                goto done;
+            }
+
+            ret = ad_subdom_store(ctx, domain, reply[c], enumerate);
             if (ret) {
                 /* Nothing we can do about the error. Let's at least try
                  * to reuse the existing domains
@@ -395,7 +418,12 @@ static errno_t ad_subdomains_refresh(struct 
ad_subdomains_ctx *ctx,
         /* Nothing we can do about the error. Let's at least try
          * to reuse the existing domains.
          */
-        ret = ad_subdom_store(ctx, domain, reply[c]);
+        ret = ad_subdom_enumerates(domain, reply[c], &enumerate);
+        if (ret != EOK) {
+            goto done;
+        }
+
+        ret = ad_subdom_store(ctx, domain, reply[c], enumerate);
         if (ret) {
             DEBUG(SSSDBG_MINOR_FAILURE, ("Failed to parse subdom data, "
                   "will try to use cached subdomain\n"));
-- 
1.8.4.2

>From 904d9e8a887b7ddfa456bbb12186478131a6850a Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhro...@redhat.com>
Date: Tue, 10 Dec 2013 21:49:45 +0100
Subject: [PATCH 2/4] LDAP: Pass a private context to enumeration ptask instead
 of hardcoded connection

Previously, the sdap-domain enumeration request used a single connection 
context to
download all the data. Now we'd like to use different connections to
download different objects, so the ID context is passed in and the
request itself decides which connection to use for the sdap-domain
enumeration.
---
 src/providers/ad/ad_id.c           | 12 ++++++++----
 src/providers/ad/ad_init.c         |  7 ++++---
 src/providers/ad/ad_subdomains.c   |  8 +++++---
 src/providers/ipa/ipa_subdomains.c |  8 +++++---
 src/providers/ldap/ldap_common.c   | 15 +++++++++------
 src/providers/ldap/ldap_common.h   | 17 +++++++++--------
 src/providers/ldap/ldap_id_enum.c  | 21 ++++++++++++---------
 7 files changed, 52 insertions(+), 36 deletions(-)

diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
index 
3a90a17f387a6714958e31d603a50ab8e58b82a6..97599c3cb1c599995fba0157e51f9db949f53938
 100644
--- a/src/providers/ad/ad_id.c
+++ b/src/providers/ad/ad_id.c
@@ -420,6 +420,7 @@ ad_check_online(struct be_req *be_req)
 }
 
 struct ad_enumeration_state {
+    struct ad_id_ctx *id_ctx;
     struct ldap_enum_ctx *ectx;
     struct sdap_id_op *sdap_op;
     struct tevent_context *ev;
@@ -449,6 +450,7 @@ ad_enumeration_send(TALLOC_CTX *mem_ctx,
 
     ectx = talloc_get_type(pvt, struct ldap_enum_ctx);
     if (ectx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot retrieve ldap_enum_ctx!\n"));
         ret = EFAULT;
         goto fail;
     }
@@ -456,8 +458,10 @@ ad_enumeration_send(TALLOC_CTX *mem_ctx,
     state->ectx = ectx;
     state->ev = ev;
     state->sdom = ectx->sdom;
+    state->id_ctx = talloc_get_type(ectx->pvt, struct ad_id_ctx);
 
-    state->sdap_op = sdap_id_op_create(state, ectx->conn->conn_cache);
+    state->sdap_op = sdap_id_op_create(state,
+                                       state->id_ctx->ldap_ctx->conn_cache);
     if (state->sdap_op == NULL) {
         DEBUG(SSSDBG_OP_FAILURE, ("sdap_id_op_create failed.\n"));
         ret = ENOMEM;
@@ -523,7 +527,7 @@ ad_enumeration_conn_done(struct tevent_req *subreq)
     }
 
     subreq = ad_master_domain_send(state, state->ev,
-                                   state->ectx->conn,
+                                   state->id_ctx->ldap_ctx,
                                    state->sdap_op,
                                    state->sdom->dom->name);
     if (subreq == NULL) {
@@ -569,8 +573,8 @@ ad_enumeration_master_done(struct tevent_req *subreq)
         return;
     }
 
-    subreq = sdap_dom_enum_send(state, state->ev, state->ectx->ctx,
-                                state->sdom, state->ectx->conn);
+    subreq = sdap_dom_enum_send(state, state->ev, state->id_ctx->sdap_id_ctx,
+                                state->sdom, state->id_ctx->ldap_ctx);
     if (subreq == NULL) {
         /* The ptask API will reschedule the enumeration on its own on
          * failure */
diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
index 
858b445d3d294635e5ca17c0be492a34865deaf8..b99caac0c73f3a757869a9ad549a57e2e34d2f7d
 100644
--- a/src/providers/ad/ad_init.c
+++ b/src/providers/ad/ad_init.c
@@ -205,11 +205,12 @@ sssm_ad_id_init(struct be_ctx *bectx,
         goto done;
     }
 
-    ret = sdap_id_setup_tasks(ad_ctx->sdap_id_ctx,
-                              ad_ctx->sdap_id_ctx->conn,
+    ret = sdap_id_setup_tasks(bectx,
+                              ad_ctx->sdap_id_ctx,
                               ad_ctx->sdap_id_ctx->opts->sdom,
                               ad_enumeration_send,
-                              ad_enumeration_recv);
+                              ad_enumeration_recv,
+                              ad_ctx);
     if (ret != EOK) {
         goto done;
     }
diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
index 
3bbf801e9fb44a164684e84a2f5a5f03267b6575..381d17697b73e6a9cfb81ca7e03e20f88de433f5
 100644
--- a/src/providers/ad/ad_subdomains.c
+++ b/src/providers/ad/ad_subdomains.c
@@ -176,10 +176,12 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
         return EFAULT;
     }
 
-    ret = sdap_id_setup_tasks(ad_id_ctx->sdap_id_ctx,
-                              ad_id_ctx->ldap_ctx, sdom,
+    ret = sdap_id_setup_tasks(be_ctx,
+                              ad_id_ctx->sdap_id_ctx,
+                              sdom,
                               ldap_enumeration_send,
-                              ldap_enumeration_recv);
+                              ldap_enumeration_recv,
+                              ad_id_ctx->sdap_id_ctx);
     if (ret != EOK) {
         talloc_free(ad_options);
         return ret;
diff --git a/src/providers/ipa/ipa_subdomains.c 
b/src/providers/ipa/ipa_subdomains.c
index 
56fd4f99654aa07f822c49d6d39526765785f0de..b43e622c2cac8a4a2f4a8e0b2174004f629e0c7e
 100644
--- a/src/providers/ipa/ipa_subdomains.c
+++ b/src/providers/ipa/ipa_subdomains.c
@@ -183,10 +183,12 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx,
         return EFAULT;
     }
 
-    ret = sdap_id_setup_tasks(ad_id_ctx->sdap_id_ctx,
-                              ad_id_ctx->ldap_ctx, sdom,
+    ret = sdap_id_setup_tasks(be_ctx,
+                              ad_id_ctx->sdap_id_ctx,
+                              sdom,
                               ldap_enumeration_send,
-                              ldap_enumeration_recv);
+                              ldap_enumeration_recv,
+                              ad_id_ctx->sdap_id_ctx);
     if (ret != EOK) {
         talloc_free(ad_options);
         return ret;
diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
index 
482271b8c22095116c7090e3ec70ed2a3c763b34..ee7296f206422ec0b78d1b3a8a669738ea55dfd9
 100644
--- a/src/providers/ldap/ldap_common.c
+++ b/src/providers/ldap/ldap_common.c
@@ -986,16 +986,18 @@ void sdap_mark_offline(struct sdap_id_ctx *ctx)
 
 int ldap_id_setup_tasks(struct sdap_id_ctx *ctx)
 {
-    return sdap_id_setup_tasks(ctx, ctx->conn, ctx->opts->sdom,
+    return sdap_id_setup_tasks(ctx->be, ctx, ctx->opts->sdom,
                                ldap_enumeration_send,
-                               ldap_enumeration_recv);
+                               ldap_enumeration_recv,
+                               ctx);
 }
 
-int sdap_id_setup_tasks(struct sdap_id_ctx *ctx,
-                        struct sdap_id_conn_ctx *conn,
+int sdap_id_setup_tasks(struct be_ctx *be_ctx,
+                        struct sdap_id_ctx *ctx,
                         struct sdap_domain *sdom,
                         be_ptask_send_t send_fn,
-                        be_ptask_recv_t recv_fn)
+                        be_ptask_recv_t recv_fn,
+                        void *pvt)
 {
     int ret;
 
@@ -1003,7 +1005,8 @@ int sdap_id_setup_tasks(struct sdap_id_ctx *ctx,
     if (sdom->dom->enumerate) {
         DEBUG(SSSDBG_TRACE_FUNC, ("Setting up enumeration for %s\n",
                                   sdom->dom->name));
-        ret = ldap_setup_enumeration(ctx, conn, sdom, send_fn, recv_fn);
+        ret = ldap_setup_enumeration(be_ctx, ctx->opts, sdom,
+                                     send_fn, recv_fn, pvt);
     } else {
         /* the enumeration task, runs the cleanup process by itself,
          * but if enumeration is not running we need to schedule it */
diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
index 
b3bd950e1dca6df0f5668397d5e5a0796e519862..889d5b118861e4ea3f51ab8a8ea5c5947e2560b9
 100644
--- a/src/providers/ldap/ldap_common.h
+++ b/src/providers/ldap/ldap_common.h
@@ -95,11 +95,12 @@ void sdap_handle_account_info(struct be_req *breq, struct 
sdap_id_ctx *ctx,
 
 /* Set up enumeration and/or cleanup */
 int ldap_id_setup_tasks(struct sdap_id_ctx *ctx);
-int sdap_id_setup_tasks(struct sdap_id_ctx *ctx,
-                        struct sdap_id_conn_ctx *conn,
+int sdap_id_setup_tasks(struct be_ctx *be_ctx,
+                        struct sdap_id_ctx *ctx,
                         struct sdap_domain *sdom,
                         be_ptask_send_t send_fn,
-                        be_ptask_recv_t recv_fn);
+                        be_ptask_recv_t recv_fn,
+                        void *pvt);
 
 struct tevent_req *
 sdap_handle_acct_req_send(TALLOC_CTX *mem_ctx,
@@ -177,16 +178,16 @@ int ldap_get_autofs_options(TALLOC_CTX *memctx,
  * structure that contains the request data
  */
 struct ldap_enum_ctx {
-    struct sdap_id_ctx *ctx;
     struct sdap_domain *sdom;
-    struct sdap_id_conn_ctx *conn;
+    void *pvt;
 };
 
-errno_t ldap_setup_enumeration(struct sdap_id_ctx *ctx,
-                               struct sdap_id_conn_ctx *conn,
+errno_t ldap_setup_enumeration(struct be_ctx *be_ctx,
+                               struct sdap_options *opts,
                                struct sdap_domain *sdom,
                                be_ptask_send_t send_fn,
-                               be_ptask_recv_t recv_fn);
+                               be_ptask_recv_t recv_fn,
+                               void *pvt);
 struct tevent_req *
 ldap_enumeration_send(TALLOC_CTX *mem_ctx,
                       struct tevent_context *ev,
diff --git a/src/providers/ldap/ldap_id_enum.c 
b/src/providers/ldap/ldap_id_enum.c
index 
58ff459c0914cf4f703261d7c5e207ee1f6f00cb..368ad932862f21f82089068c0fd78c06a5bf4679
 100644
--- a/src/providers/ldap/ldap_id_enum.c
+++ b/src/providers/ldap/ldap_id_enum.c
@@ -27,11 +27,12 @@
 #include "providers/ldap/ldap_common.h"
 #include "providers/ldap/sdap_async_enum.h"
 
-errno_t ldap_setup_enumeration(struct sdap_id_ctx *ctx,
-                               struct sdap_id_conn_ctx *conn,
+errno_t ldap_setup_enumeration(struct be_ctx *be_ctx,
+                               struct sdap_options *opts,
                                struct sdap_domain *sdom,
                                be_ptask_send_t send_fn,
-                               be_ptask_recv_t recv_fn)
+                               be_ptask_recv_t recv_fn,
+                               void *pvt)
 {
     errno_t ret;
     time_t first_delay;
@@ -60,17 +61,16 @@ errno_t ldap_setup_enumeration(struct sdap_id_ctx *ctx,
         first_delay = 0;
     }
 
-    period = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
+    period = dp_opt_get_int(opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
 
     ectx = talloc(sdom, struct ldap_enum_ctx);
     if (ectx == NULL) {
         return ENOMEM;
     }
-    ectx->ctx = ctx;
     ectx->sdom = sdom;
-    ectx->conn = conn;
+    ectx->pvt = pvt;
 
-    ret = be_ptask_create(sdom, ctx->be,
+    ret = be_ptask_create(sdom, be_ctx,
                           period,                   /* period */
                           first_delay,              /* first_delay */
                           5,                        /* enabled delay */
@@ -91,6 +91,7 @@ errno_t ldap_setup_enumeration(struct sdap_id_ctx *ctx,
 
 struct ldap_enumeration_state {
     struct ldap_enum_ctx *ectx;
+    struct sdap_id_ctx *id_ctx;
     struct sss_domain_info *dom;
 };
 
@@ -118,14 +119,16 @@ ldap_enumeration_send(TALLOC_CTX *mem_ctx,
 
     ectx = talloc_get_type(pvt, struct ldap_enum_ctx);
     if (ectx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot retrieve ldap_enum_ctx!\n"));
         ret = EFAULT;
         goto fail;
     }
     state->ectx = ectx;
     state->dom = ectx->sdom->dom;
+    state->id_ctx = talloc_get_type_abort(ectx->pvt, struct sdap_id_ctx);
 
-    subreq = sdap_dom_enum_send(ectx, ev, ectx->ctx, ectx->sdom,
-                                ectx->conn);
+    subreq = sdap_dom_enum_send(ectx, ev, state->id_ctx, ectx->sdom,
+                                state->id_ctx->conn);
     if (subreq == NULL) {
         /* The ptask API will reschedule the enumeration on its own on
          * failure */
-- 
1.8.4.2

>From 149c251bef8d9a539ac1a67e195a416939b16ffc Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhro...@redhat.com>
Date: Mon, 16 Dec 2013 02:41:53 +0100
Subject: [PATCH 3/4] LDAP: Add enum request with custom connection

This commit changes the enumerate-sdap-domain request to accept a
connection context per object that can be enumerated. Internally in the
request, an sdap_id_op is also created per enumerated object type.

This change will allow i.e. users to be enumerated using GC connection,
while keeping the LDAP connection for groups and services.
---
 src/providers/ldap/sdap_async_enum.c | 309 +++++++++++++++++++++--------------
 src/providers/ldap/sdap_async_enum.h |  11 ++
 2 files changed, 193 insertions(+), 127 deletions(-)

diff --git a/src/providers/ldap/sdap_async_enum.c 
b/src/providers/ldap/sdap_async_enum.c
index 
a006d1e11f80b3a43ce8096d306f18378e996c27..2ded3b82b69d9a0913705bff5970fedcaeda5cbf
 100644
--- a/src/providers/ldap/sdap_async_enum.c
+++ b/src/providers/ldap/sdap_async_enum.c
@@ -48,49 +48,56 @@ static struct tevent_req *enum_groups_send(TALLOC_CTX 
*memctx,
                                           bool purge);
 static errno_t enum_groups_recv(struct tevent_req *req);
 
-/* ==Enumeration-Request==================================================== */
-struct sdap_dom_enum_state {
+/* ==Enumeration-Request-with-connections=================================== */
+struct sdap_dom_enum_ex_state {
     struct tevent_context *ev;
     struct sdap_id_ctx *ctx;
     struct sdap_domain *sdom;
-    struct sdap_id_conn_ctx *conn;
-    struct sdap_id_op *op;
+
+    struct sdap_id_conn_ctx *user_conn;
+    struct sdap_id_conn_ctx *group_conn;
+    struct sdap_id_conn_ctx *svc_conn;
+    struct sdap_id_op *user_op;
+    struct sdap_id_op *group_op;
+    struct sdap_id_op *svc_op;
 
     bool purge;
 };
 
-static errno_t sdap_dom_enum_retry(struct tevent_req *req);
-static void sdap_dom_enum_conn_done(struct tevent_req *subreq);
-static void sdap_dom_enum_users_done(struct tevent_req *subreq);
-static void sdap_dom_enum_groups_done(struct tevent_req *subreq);
-static void sdap_dom_enum_services_done(struct tevent_req *subreq);
+static errno_t sdap_dom_enum_ex_retry(struct tevent_req *req,
+                                      struct sdap_id_op *op,
+                                      tevent_req_fn tcb);
+static bool sdap_dom_enum_ex_connected(struct tevent_req *subreq);
+static void sdap_dom_enum_ex_get_users(struct tevent_req *subreq);
+static void sdap_dom_enum_ex_users_done(struct tevent_req *subreq);
+static void sdap_dom_enum_ex_get_groups(struct tevent_req *subreq);
+static void sdap_dom_enum_ex_groups_done(struct tevent_req *subreq);
+static void sdap_dom_enum_ex_get_svcs(struct tevent_req *subreq);
+static void sdap_dom_enum_ex_svcs_done(struct tevent_req *subreq);
 
 struct tevent_req *
-sdap_dom_enum_send(TALLOC_CTX *memctx,
-                   struct tevent_context *ev,
-                   struct sdap_id_ctx *ctx,
-                   struct sdap_domain *sdom,
-                   struct sdap_id_conn_ctx *conn)
+sdap_dom_enum_ex_send(TALLOC_CTX *memctx,
+                      struct tevent_context *ev,
+                      struct sdap_id_ctx *ctx,
+                      struct sdap_domain *sdom,
+                      struct sdap_id_conn_ctx *user_conn,
+                      struct sdap_id_conn_ctx *group_conn,
+                      struct sdap_id_conn_ctx *svc_conn)
 {
     struct tevent_req *req;
-    struct sdap_dom_enum_state *state;
+    struct sdap_dom_enum_ex_state *state;
     int t;
     errno_t ret;
 
-    req = tevent_req_create(ctx, &state, struct sdap_dom_enum_state);
-    if (!req) return NULL;
+    req = tevent_req_create(ctx, &state, struct sdap_dom_enum_ex_state);
+    if (req == NULL) return NULL;
 
     state->ev = ev;
     state->ctx = ctx;
     state->sdom = sdom;
-    state->conn = conn;
-    state->op = sdap_id_op_create(state, state->ctx->conn->conn_cache);
-    if (!state->op) {
-        DEBUG(SSSDBG_CRIT_FAILURE, ("sdap_id_op_create failed\n"));
-        ret = EIO;
-        goto fail;
-    }
-
+    state->user_conn = user_conn;
+    state->group_conn = group_conn;
+    state->svc_conn = svc_conn;
     sdom->last_enum = tevent_timeval_current();
 
     t = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT);
@@ -98,9 +105,17 @@ sdap_dom_enum_send(TALLOC_CTX *memctx,
         state->purge = true;
     }
 
-    ret = sdap_dom_enum_retry(req);
+    state->user_op = sdap_id_op_create(state, user_conn->conn_cache);
+    if (state->user_op == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("sdap_id_op_create failed for users\n"));
+        ret = EIO;
+        goto fail;
+    }
+
+    ret = sdap_dom_enum_ex_retry(req, state->user_op,
+                                 sdap_dom_enum_ex_get_users);
     if (ret != EOK) {
-        DEBUG(SSSDBG_OP_FAILURE, ("ldap_id_enumerate_retry failed\n"));
+        DEBUG(SSSDBG_OP_FAILURE, ("sdap_dom_enum_ex_retry failed\n"));
         goto fail;
     }
 
@@ -112,31 +127,32 @@ fail:
     return req;
 }
 
-static errno_t sdap_dom_enum_retry(struct tevent_req *req)
+static errno_t sdap_dom_enum_ex_retry(struct tevent_req *req,
+                                      struct sdap_id_op *op,
+                                      tevent_req_fn tcb)
 {
-    struct sdap_dom_enum_state *state = tevent_req_data(req,
-                                                   struct sdap_dom_enum_state);
+    struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
+                                                   struct 
sdap_dom_enum_ex_state);
     struct tevent_req *subreq;
     errno_t ret;
 
-    subreq = sdap_id_op_connect_send(state->op, state, &ret);
+    subreq = sdap_id_op_connect_send(op, state, &ret);
     if (subreq == NULL) {
         DEBUG(SSSDBG_OP_FAILURE,
               ("sdap_id_op_connect_send failed: %d\n", ret));
         return ret;
     }
 
-    tevent_req_set_callback(subreq, sdap_dom_enum_conn_done, req);
+    tevent_req_set_callback(subreq, tcb, req);
     return EOK;
 }
 
-static void sdap_dom_enum_conn_done(struct tevent_req *subreq)
+static bool sdap_dom_enum_ex_connected(struct tevent_req *subreq)
 {
+    errno_t ret;
+    int dp_error;
     struct tevent_req *req = tevent_req_callback_data(subreq,
                                                       struct tevent_req);
-    struct sdap_dom_enum_state *state = tevent_req_data(req,
-                                                   struct sdap_dom_enum_state);
-    int ret, dp_error;
 
     ret = sdap_id_op_connect_recv(subreq, &dp_error);
     talloc_zfree(subreq);
@@ -151,150 +167,173 @@ static void sdap_dom_enum_conn_done(struct tevent_req 
*subreq)
                    "LDAP server: (%d)[%s]\n", ret, strerror(ret)));
             tevent_req_error(req, ret);
         }
+        return false;
+    }
+
+    return true;
+}
+
+static void sdap_dom_enum_ex_get_users(struct tevent_req *subreq)
+{
+    struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                      struct tevent_req);
+    struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
+                                                   struct 
sdap_dom_enum_ex_state);
+
+    if (sdap_dom_enum_ex_connected(subreq) == false) {
         return;
     }
 
     subreq = enum_users_send(state, state->ev,
                              state->ctx, state->sdom,
-                             state->op, state->purge);
+                             state->user_op, state->purge);
     if (subreq == NULL) {
         tevent_req_error(req, ENOMEM);
         return;
     }
-    tevent_req_set_callback(subreq, sdap_dom_enum_users_done, req);
+    tevent_req_set_callback(subreq, sdap_dom_enum_ex_users_done, req);
 }
 
-static void sdap_dom_enum_users_done(struct tevent_req *subreq)
+static void sdap_dom_enum_ex_users_done(struct tevent_req *subreq)
 {
     struct tevent_req *req = tevent_req_callback_data(subreq,
                                                       struct tevent_req);
-    struct sdap_dom_enum_state *state = tevent_req_data(req,
-                                                   struct sdap_dom_enum_state);
-    uint64_t err = 0;
-    int ret, dp_error = DP_ERR_FATAL;
+    struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
+                                                   struct 
sdap_dom_enum_ex_state);
+    errno_t ret;
+    int dp_error;
 
-    err = enum_users_recv(subreq);
+    ret = enum_users_recv(subreq);
     talloc_zfree(subreq);
-    if (err != EOK && err != ENOENT) {
-        /* We call sdap_id_op_done only on error
-         * as the connection is reused by groups enumeration */
-        ret = sdap_id_op_done(state->op, (int)err, &dp_error);
-        if (dp_error == DP_ERR_OK) {
-            /* retry */
-            ret = sdap_dom_enum_retry(req);
-            if (ret == EOK) {
-                return;
-            }
-
-            dp_error = DP_ERR_FATAL;
-        }
-
-        if (dp_error == DP_ERR_OFFLINE) {
-            tevent_req_done(req);
-        } else {
-            DEBUG(SSSDBG_OP_FAILURE,
-                  ("User enumeration failed with: (%d)[%s]\n",
-                   ret, strerror(ret)));
+    ret = sdap_id_op_done(state->user_op, ret, &dp_error);
+    if (dp_error == DP_ERR_OK && ret != EOK) {
+        /* retry */
+        ret = sdap_dom_enum_ex_retry(req, state->user_op,
+                                     sdap_dom_enum_ex_get_users);
+        if (ret != EOK) {
             tevent_req_error(req, ret);
+            return;
         }
         return;
     }
 
+    state->group_op = sdap_id_op_create(state, state->group_conn->conn_cache);
+    if (state->group_op == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("sdap_id_op_create failed for groups\n"));
+        tevent_req_error(req, EIO);
+        return;
+    }
+
+    ret = sdap_dom_enum_ex_retry(req, state->group_op,
+                                 sdap_dom_enum_ex_get_groups);
+    if (ret != EOK) {
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    /* Continues to sdap_dom_enum_ex_get_groups */
+}
+
+static void sdap_dom_enum_ex_get_groups(struct tevent_req *subreq)
+{
+    struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                      struct tevent_req);
+    struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
+                                                   struct 
sdap_dom_enum_ex_state);
+
+    if (sdap_dom_enum_ex_connected(subreq) == false) {
+        return;
+    }
+
     subreq = enum_groups_send(state, state->ev, state->ctx,
                               state->sdom,
-                              state->op, state->purge);
+                              state->group_op, state->purge);
     if (subreq == NULL) {
         tevent_req_error(req, ENOMEM);
         return;
     }
-    tevent_req_set_callback(subreq, sdap_dom_enum_groups_done, req);
+    tevent_req_set_callback(subreq, sdap_dom_enum_ex_groups_done, req);
 }
 
-static void sdap_dom_enum_groups_done(struct tevent_req *subreq)
+static void sdap_dom_enum_ex_groups_done(struct tevent_req *subreq)
 {
     struct tevent_req *req = tevent_req_callback_data(subreq,
                                                       struct tevent_req);
-    struct sdap_dom_enum_state *state = tevent_req_data(req,
-                                                   struct sdap_dom_enum_state);
-    uint64_t err = 0;
-    int ret, dp_error = DP_ERR_FATAL;
+    struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
+                                                   struct 
sdap_dom_enum_ex_state);
+    int ret;
+    int dp_error;
 
-    err = enum_groups_recv(subreq);
+    ret = enum_groups_recv(subreq);
     talloc_zfree(subreq);
-    if (err != EOK && err != ENOENT) {
-        /* We call sdap_id_op_done only on error
-         * as the connection is reused by services enumeration */
-        ret = sdap_id_op_done(state->op, (int)err, &dp_error);
-        if (dp_error == DP_ERR_OK && ret != EOK) {
-            /* retry */
-            ret = sdap_dom_enum_retry(req);
-            if (ret == EOK) {
-                return;
-            }
-
-            dp_error = DP_ERR_FATAL;
-        }
-
+    ret = sdap_id_op_done(state->group_op, ret, &dp_error);
+    if (dp_error == DP_ERR_OK && ret != EOK) {
+        /* retry */
+        ret = sdap_dom_enum_ex_retry(req, state->group_op,
+                                     sdap_dom_enum_ex_get_groups);
         if (ret != EOK) {
-            if (dp_error == DP_ERR_OFFLINE) {
-                tevent_req_done(req);
-            } else {
-                DEBUG(SSSDBG_OP_FAILURE,
-                      ("Group enumeration failed with: (%d)[%s]\n",
-                       ret, strerror(ret)));
-                tevent_req_error(req, ret);
-            }
-
+            tevent_req_error(req, ret);
             return;
         }
+        return;
+    }
+
+
+    state->svc_op = sdap_id_op_create(state, state->svc_conn->conn_cache);
+    if (state->svc_op == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("sdap_id_op_create failed for svcs\n"));
+        tevent_req_error(req, EIO);
+        return;
+    }
+
+    ret = sdap_dom_enum_ex_retry(req, state->svc_op,
+                                 sdap_dom_enum_ex_get_svcs);
+    if (ret != EOK) {
+        tevent_req_error(req, ret);
+        return;
+    }
+}
+
+static void sdap_dom_enum_ex_get_svcs(struct tevent_req *subreq)
+{
+    struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                      struct tevent_req);
+    struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
+                                                   struct 
sdap_dom_enum_ex_state);
+
+    if (sdap_dom_enum_ex_connected(subreq) == false) {
+        return;
     }
 
     subreq = enum_services_send(state, state->ev, state->ctx,
-                                state->op, state->purge);
+                                state->svc_op, state->purge);
     if (!subreq) {
         tevent_req_error(req, ENOMEM);
         return;
     }
-    tevent_req_set_callback(subreq, sdap_dom_enum_services_done, req);
+    tevent_req_set_callback(subreq, sdap_dom_enum_ex_svcs_done, req);
 }
 
-static void sdap_dom_enum_services_done(struct tevent_req *subreq)
+static void sdap_dom_enum_ex_svcs_done(struct tevent_req *subreq)
 {
-    errno_t ret;
-    int dp_error = DP_ERR_FATAL;
     struct tevent_req *req = tevent_req_callback_data(subreq,
                                                       struct tevent_req);
-    struct sdap_dom_enum_state *state = tevent_req_data(req,
-                                                   struct sdap_dom_enum_state);
+    struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
+                                                   struct 
sdap_dom_enum_ex_state);
+    int ret;
+    int dp_error;
 
     ret = enum_services_recv(subreq);
     talloc_zfree(subreq);
-    if (ret == ENOENT) ret = EOK;
-
-    /* All enumerations are complete, so conclude the
-     * id_op
-     */
-    ret = sdap_id_op_done(state->op, ret, &dp_error);
+    ret = sdap_id_op_done(state->svc_op, ret, &dp_error);
     if (dp_error == DP_ERR_OK && ret != EOK) {
         /* retry */
-        ret = sdap_dom_enum_retry(req);
-        if (ret == EOK) {
-            return;
-        }
-
-        dp_error = DP_ERR_FATAL;
-    }
-
-    if (ret != EOK) {
-        if (dp_error == DP_ERR_OFFLINE) {
-            tevent_req_done(req);
-        } else {
-            DEBUG(SSSDBG_MINOR_FAILURE,
-                  ("Service enumeration failed with: (%d)[%s]\n",
-                   ret, strerror(ret)));
+        ret = sdap_dom_enum_ex_retry(req, state->user_op,
+                                     sdap_dom_enum_ex_get_svcs);
+        if (ret != EOK) {
             tevent_req_error(req, ret);
+            return;
         }
-
         return;
     }
 
@@ -323,11 +362,27 @@ static void sdap_dom_enum_services_done(struct tevent_req 
*subreq)
     tevent_req_done(req);
 }
 
+errno_t sdap_dom_enum_ex_recv(struct tevent_req *req)
+{
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    return EOK;
+}
+
+/* ==Enumeration-Request==================================================== */
+struct tevent_req *
+sdap_dom_enum_send(TALLOC_CTX *memctx,
+                   struct tevent_context *ev,
+                   struct sdap_id_ctx *ctx,
+                   struct sdap_domain *sdom,
+                   struct sdap_id_conn_ctx *conn)
+{
+    return sdap_dom_enum_ex_send(memctx, ev, ctx, sdom, conn, conn, conn);
+}
+
 errno_t sdap_dom_enum_recv(struct tevent_req *req)
 {
-    TEVENT_REQ_RETURN_ON_ERROR(req);
-
-    return EOK;
+    return sdap_dom_enum_ex_recv(req);
 }
 
 /* ==User-Enumeration===================================================== */
diff --git a/src/providers/ldap/sdap_async_enum.h 
b/src/providers/ldap/sdap_async_enum.h
index 
04ec8c6dcbec4bcce0de67b9e10acc857c9e9416..2da38f988913fa0d6f252697925e50e05eb794a6
 100644
--- a/src/providers/ldap/sdap_async_enum.h
+++ b/src/providers/ldap/sdap_async_enum.h
@@ -27,6 +27,17 @@
 #define _SDAP_ASYNC_ENUM_H_
 
 struct tevent_req *
+sdap_dom_enum_ex_send(TALLOC_CTX *memctx,
+                      struct tevent_context *ev,
+                      struct sdap_id_ctx *ctx,
+                      struct sdap_domain *sdom,
+                      struct sdap_id_conn_ctx *user_conn,
+                      struct sdap_id_conn_ctx *group_conn,
+                      struct sdap_id_conn_ctx *svc_conn);
+
+errno_t sdap_dom_enum_ex_recv(struct tevent_req *req);
+
+struct tevent_req *
 sdap_dom_enum_send(TALLOC_CTX *memctx,
                    struct tevent_context *ev,
                    struct sdap_id_ctx *ctx,
-- 
1.8.4.2

>From c11b25307153a473fd3a5e226c9486e112305083 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhro...@redhat.com>
Date: Mon, 16 Dec 2013 02:51:43 +0100
Subject: [PATCH 4/4] AD: Enumerate users from GC, other entities from LDAP

https://fedorahosted.org/sssd/ticket/2142

When performing regular user or group lookups, we connect to GC
primarily. However, the enumeration task could only connect to LDAP.
When different attributes are present in GC and LDAP, this could have
lead to very confusing results.

This patch switches to using GC by default for both users and groups.
Services, if present, are downloaded using the LDAP connection.
---
 src/providers/ad/ad_id.c         | 127 ++++++++++++++++++++++++++++++++++++++-
 src/providers/ad/ad_id.h         |  10 +++
 src/providers/ad/ad_subdomains.c |  24 ++++----
 3 files changed, 147 insertions(+), 14 deletions(-)

diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
index 
97599c3cb1c599995fba0157e51f9db949f53938..c72f8bc7403e52555735c0a9d8c1318a899b2b8c
 100644
--- a/src/providers/ad/ad_id.c
+++ b/src/providers/ad/ad_id.c
@@ -549,6 +549,7 @@ ad_enumeration_master_done(struct tevent_req *subreq)
     char *flat_name;
     char *master_sid;
     int dp_error;
+    struct sdap_id_conn_ctx *user_conn;
 
     ret = ad_master_domain_recv(subreq, state,
                                 &flat_name, &master_sid);
@@ -573,8 +574,17 @@ ad_enumeration_master_done(struct tevent_req *subreq)
         return;
     }
 
-    subreq = sdap_dom_enum_send(state, state->ev, state->id_ctx->sdap_id_ctx,
-                                state->sdom, state->id_ctx->ldap_ctx);
+    if (dp_opt_get_bool(state->id_ctx->ad_options->basic, AD_ENABLE_GC)) {
+        user_conn = state->id_ctx->gc_ctx;
+    } else {
+        user_conn = state->id_ctx->ldap_ctx;
+    }
+
+    subreq = sdap_dom_enum_ex_send(state, state->ev, 
state->id_ctx->sdap_id_ctx,
+                                   state->sdom,
+                                   user_conn,       /* Users  */
+                                   user_conn,       /* Groups */
+                                   state->id_ctx->ldap_ctx); /* svcs */
     if (subreq == NULL) {
         /* The ptask API will reschedule the enumeration on its own on
          * failure */
@@ -595,7 +605,7 @@ ad_enumeration_done(struct tevent_req *subreq)
     struct ad_enumeration_state *state = tevent_req_data(req,
                                                 struct ad_enumeration_state);
 
-    ret = sdap_dom_enum_recv(subreq);
+    ret = sdap_dom_enum_ex_recv(subreq);
     talloc_zfree(subreq);
     if (ret != EOK) {
         DEBUG(SSSDBG_OP_FAILURE,
@@ -613,3 +623,114 @@ ad_enumeration_recv(struct tevent_req *req)
     TEVENT_REQ_RETURN_ON_ERROR(req);
     return EOK;
 }
+
+/* Enumerate a subdomain */
+struct ad_enum_subdom_state {
+    struct ad_id_ctx *id_ctx;
+    struct ad_id_ctx *subdom_id_ctx;
+
+    struct ldap_enum_ctx *ectx;
+    struct tevent_context *ev;
+
+    struct sdap_domain *sdom;
+};
+
+static void ad_enum_subdom_done(struct tevent_req *subreq);
+
+struct tevent_req *
+ad_enum_subdom_send(TALLOC_CTX *mem_ctx,
+                    struct tevent_context *ev,
+                    struct be_ctx *be_ctx,
+                    struct be_ptask *be_ptask,
+                    void *pvt)
+{
+    struct tevent_req *req;
+    struct tevent_req *subreq;
+    struct ad_enum_subdom_state *state;
+    struct ldap_enum_ctx *ectx;
+    errno_t ret;
+    struct sdap_id_conn_ctx *user_conn;
+
+    req = tevent_req_create(mem_ctx, &state, struct ad_enum_subdom_state);
+    if (req == NULL) return NULL;
+
+    ectx = talloc_get_type(pvt, struct ldap_enum_ctx);
+    if (ectx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot retrieve ldap_enum_ctx!\n"));
+        ret = EFAULT;
+        goto fail;
+    }
+
+    state->ectx = ectx;
+    state->ev = ev;
+    state->sdom = ectx->sdom;
+    state->id_ctx = talloc_get_type(ectx->pvt, struct ad_id_ctx);
+    if (state->id_ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot retrieve ad_id_ctx!\n"));
+        ret = EFAULT;
+        goto fail;
+    }
+
+    state->subdom_id_ctx = talloc_get_type(state->sdom->pvt, struct ad_id_ctx);
+    if (state->subdom_id_ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot retrieve subdomain ad_id_ctx!\n"));
+        ret = EFAULT;
+        goto fail;
+    }
+
+    if (dp_opt_get_bool(state->id_ctx->ad_options->basic, AD_ENABLE_GC)) {
+        user_conn = state->id_ctx->gc_ctx;
+    } else {
+        user_conn = state->subdom_id_ctx->ldap_ctx;
+    }
+
+    subreq = sdap_dom_enum_ex_send(state, state->ev, 
state->id_ctx->sdap_id_ctx,
+                                   state->sdom,
+                                   user_conn,       /* Users  */
+                                   user_conn,       /* Groups */
+                                   state->subdom_id_ctx->ldap_ctx); /* svcs */
+    if (subreq == NULL) {
+        /* The ptask API will reschedule the enumeration on its own on
+         * failure */
+        DEBUG(SSSDBG_OP_FAILURE,
+              ("Failed to schedule enumeration, retrying later!\n"));
+        ret = ENOMEM;
+        goto fail;
+    }
+    tevent_req_set_callback(subreq, ad_enum_subdom_done, req);
+
+    return req;
+
+fail:
+    tevent_req_error(req, ret);
+    tevent_req_post(req, ev);
+    return req;
+}
+
+static void
+ad_enum_subdom_done(struct tevent_req *subreq)
+{
+    errno_t ret;
+    struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                      struct tevent_req);
+    struct ad_enum_subdom_state *state = tevent_req_data(req,
+                                                struct ad_enum_subdom_state);
+
+    ret = sdap_dom_enum_ex_recv(subreq);
+    talloc_zfree(subreq);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE,
+              ("Could not enumerate domain %s\n", state->sdom->dom->name));
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    tevent_req_done(req);
+}
+
+errno_t
+ad_enum_subdom_recv(struct tevent_req *req)
+{
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+    return EOK;
+}
diff --git a/src/providers/ad/ad_id.h b/src/providers/ad/ad_id.h
index 
74b85645c2d6458617a4064fe3fb3f99696c3741..20fe0b76350f1246fd0ad3f24b1138271a8a1521
 100644
--- a/src/providers/ad/ad_id.h
+++ b/src/providers/ad/ad_id.h
@@ -47,6 +47,16 @@ ad_enumeration_send(TALLOC_CTX *mem_ctx,
 errno_t
 ad_enumeration_recv(struct tevent_req *req);
 
+struct tevent_req *
+ad_enum_subdom_send(TALLOC_CTX *mem_ctx,
+                    struct tevent_context *ev,
+                    struct be_ctx *be_ctx,
+                    struct be_ptask *be_ptask,
+                    void *pvt);
+
+errno_t
+ad_enum_subdom_recv(struct tevent_req *req);
+
 void
 ad_check_online(struct be_req *be_req);
 #endif /* AD_ID_H_ */
diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
index 
381d17697b73e6a9cfb81ca7e03e20f88de433f5..9a4117cc6a6d232b2d12bdf60f88aa876480929e
 100644
--- a/src/providers/ad/ad_subdomains.c
+++ b/src/providers/ad/ad_subdomains.c
@@ -26,6 +26,7 @@
 #include "providers/ad/ad_subdomains.h"
 #include "providers/ad/ad_domain_info.h"
 #include "providers/ad/ad_srv.h"
+#include "providers/ad/ad_id.h"
 #include "providers/ldap/sdap_idmap.h"
 #include "util/util_sss_idmap.h"
 #include <ctype.h>
@@ -176,17 +177,6 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
         return EFAULT;
     }
 
-    ret = sdap_id_setup_tasks(be_ctx,
-                              ad_id_ctx->sdap_id_ctx,
-                              sdom,
-                              ldap_enumeration_send,
-                              ldap_enumeration_recv,
-                              ad_id_ctx->sdap_id_ctx);
-    if (ret != EOK) {
-        talloc_free(ad_options);
-        return ret;
-    }
-
     /* Set up the ID mapping object */
     ad_id_ctx->sdap_id_ctx->opts->idmap_ctx =
         id_ctx->sdap_id_ctx->opts->idmap_ctx;
@@ -217,6 +207,18 @@ ads_store_sdap_subdom(struct ad_subdomains_ctx *ctx,
                 DEBUG(SSSDBG_OP_FAILURE, ("ad_subdom_ad_ctx_new failed.\n"));
             } else {
                 sditer->pvt = subdom_id_ctx;
+
+                /* Set up enumeration/cleanup for the new subdomain */
+                ret = sdap_id_setup_tasks(ctx->be_ctx,
+                                          ctx->ad_id_ctx->sdap_id_ctx,
+                                          sditer,
+                                          ad_enum_subdom_send,
+                                          ad_enum_subdom_recv,
+                                          subdom_id_ctx);
+                if (ret != EOK) {
+                    return ret;
+                }
+
             }
         }
     }
-- 
1.8.4.2

_______________________________________________
sssd-devel mailing list
sssd-devel@lists.fedorahosted.org
https://lists.fedorahosted.org/mailman/listinfo/sssd-devel

Reply via email to