[SSSD] [PATCH] Connect to GC during enumeration

Jakub Hrozek jhrozek at redhat.com
Fri Jan 24 19:31:00 UTC 2014


On Wed, Jan 22, 2014 at 03:26:07PM +0100, Jakub Hrozek wrote:
> On Wed, Jan 22, 2014 at 12:02:34AM +0100, Jakub Hrozek wrote:
> > On Fri, Jan 10, 2014 at 02:54:46PM +0100, Sumit Bose wrote:
> > > On Fri, Jan 10, 2014 at 02:35:12PM +0100, Jakub Hrozek wrote:
> > > > On Fri, Jan 10, 2014 at 12:59:05PM +0100, Sumit Bose wrote:
> > > > > On Tue, Dec 17, 2013 at 09:00:25PM +0100, Jakub Hrozek wrote:
> > > > > > 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.
> > > > > 
> > > > > Can you rebase these patches and their prerequisites? They do not apply
> > > > > to master anymore. I also cloud not apply "AD: Retry and terminate
> > > > > sdap_id_op if possible".
> > 
> > Hi,
> > 
> > the "AD: Retry and terminate sdap_id_op if possible" patch is not
> > strictly required, so I haven't rebased and resent it yet.
> > 
> > > > 
> > > > Sure, will do.
> > > > 
> > > > > 
> > > > > Based on the experience with AD group-memberships and the recent
> > > > > changes where we switch back from GC to LDAP to determine
> > > > > group-memberships I would suggest to use the LDAP connect for the group
> > > > > enumeration as well.
> > > > 
> > > > The last word in a private mini-thread with Simo was to use LDAP for the
> > > > parent domain by default and GC elsewhere, right? I would also like to
> > > > check all code is consistent when changing these patches.
> > > 
> > > I think in the general only universal group can be retrieve correctly
> > > form the GC. If we read LDAP for the parent domain there are still the
> > > global groups from the other domains which might be incomplete in the
> > > GC.
> > 
> > I've been testing the enumeration quite a bit and unfortunately I
> > found a defect that is not so easily fixed with the current enumeration
> > architecture. Because the original patches enumerated the primary domain and
> > subdomain separately, cross-domain memberships were hard, if not impossible
> > to maintain, at least because there was no guarantee on the order or
> > completeness of enumeration.
> > 
> > So attached are rebased the original patches with the connections fixed
> > as you liked. But cross-domain memberships don't work.
> > 
> > I have two additional patches, one finished and one WIP in my ad_enum branch:
> > http://fedorapeople.org/cgit/jhrozek/public_git/sssd.git/log/?h=ad_enum
> > 
> > The first makes sure the original_member contains the original DN and
> > not sysdb DN :-) The other is not finished but my intent was to
> >     1) check if any subdomains were enumerated. If not, do nothing
> >     2) if any of the groups saved had more original members than sysdb
> >     members, check if members of these groups can be linked now that all
> >     users and groups are saved.
> > 
> > I hope this would be acceptable, because the cost is only incurred  if
> > subdomains are enumerated and there are cross-domain memberships at the
> > same time.. Any other solution I could think of would require bigger
> > changes, but I'd welcome other ideas.
> 
> Hi,
> 
> all patches are attached now. With the attached patches, even
> cross-domain memberships are established in my testing if enumeration is
> on.

Hi,

Sumit found a rather embarrasing bug in the code, where a tevent_req was
terminated even if it shouldn't. I guess my testing only went fine
because the server and client are really close to one another and thus
the request completed quickly.

Thank you for the review. A new set of patches is attached.
-------------- next part --------------
>From 0c32d88e90f5922af6b8029a586521df8ea4ebce Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Tue, 10 Dec 2013 17:33:35 +0100
Subject: [PATCH 1/6] 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 62c3e16d0d3323a32848b4fbf54d2a151c16f64c..348561a85524c203293c713d3f31552a99d74a43 100644
--- a/src/providers/ad/ad_subdomains.c
+++ b/src/providers/ad/ad_subdomains.c
@@ -223,10 +223,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;
@@ -293,9 +311,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, domain->forest);
+                                mpg, enumerate, domain->forest);
     if (ret != EOK) {
         DEBUG(SSSDBG_OP_FAILURE, ("sysdb_subdomain_store failed.\n"));
         goto done;
@@ -319,6 +336,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);
@@ -367,7 +385,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
@@ -396,7 +419,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

-------------- next part --------------
>From 94d55a4ffc1072ee44b0043e9c20158c143a9091 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Tue, 10 Dec 2013 21:49:45 +0100
Subject: [PATCH 2/6] 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 85edcf6d604f705f5645f77689c2b4c7471b5edd..99383c13bdadfe9eb2af9f9323ca19a9759d4620 100644
--- a/src/providers/ad/ad_id.c
+++ b/src/providers/ad/ad_id.c
@@ -414,6 +414,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;
@@ -443,6 +444,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;
     }
@@ -450,8 +452,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;
@@ -500,7 +504,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) {
@@ -540,8 +544,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 ed69a7d9889bac1281b5ff7c7b0f290ab09173fb..eff6d990d131e3aba124d252d001dd39e78b45cf 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 348561a85524c203293c713d3f31552a99d74a43..e7871cc32407893948fe1b2803258d68c70889c1 100644
--- a/src/providers/ad/ad_subdomains.c
+++ b/src/providers/ad/ad_subdomains.c
@@ -177,10 +177,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 d9c204451f1b734ee98ce4c48f3f139731e47dec..88b6ba52538be83417e98c9a5dd033bea87ebe4b 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 f1a2ed97e211757ebc21906482f7f18d4012b913..1eb848a9de5f67e4aa48c4675ef424576fbed89b 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

-------------- next part --------------
>From 6d86784555a647a7ee18ca111d77d5a07a7a683a Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Mon, 16 Dec 2013 02:41:53 +0100
Subject: [PATCH 3/6] 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..ad4fa896371d102c76fe334c2490db6f4ad2de80 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

-------------- next part --------------
>From 5351f0acf77b10c7a49a725be996b04d331432c9 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Mon, 16 Dec 2013 02:51:43 +0100
Subject: [PATCH 4/6] AD: Enumerate users from GC, other entities from LDAP

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

When performing regular lookups, we connect to GC for users from all domains,
but defer to LDAP to read group memberships.  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 for users and LDAP for groups as is the
case for normal lookups.

Services, if present, are downloaded using the LDAP connection.
---
 src/providers/ad/ad_id.c         | 134 ++++++++++++++++++++++++++++++++++++++-
 src/providers/ad/ad_subdomains.c |  11 ----
 2 files changed, 131 insertions(+), 14 deletions(-)

diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
index 99383c13bdadfe9eb2af9f9323ca19a9759d4620..1bdacf74f0e6de2120603401bcf115549a03ac4f 100644
--- a/src/providers/ad/ad_id.c
+++ b/src/providers/ad/ad_id.c
@@ -526,6 +526,7 @@ ad_enumeration_master_done(struct tevent_req *subreq)
     char *flat_name;
     char *master_sid;
     char *forest;
+    struct sdap_id_conn_ctx *user_conn;
 
     ret = ad_master_domain_recv(subreq, state,
                                 &flat_name, &master_sid, &forest);
@@ -544,8 +545,21 @@ 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;
+    }
+
+    /* Groups are searched for in LDAP, users in GC. Services (if present,
+     * which is unlikely in AD) from LDAP as well
+     */
+    subreq = sdap_dom_enum_ex_send(state, state->ev,
+                                   state->id_ctx->sdap_id_ctx,
+                                   state->sdom,
+                                   user_conn,                /* Users    */
+                                   state->id_ctx->ldap_ctx,  /* Groups   */
+                                   state->id_ctx->ldap_ctx); /* Services */
     if (subreq == NULL) {
         /* The ptask API will reschedule the enumeration on its own on
          * failure */
@@ -566,7 +580,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,
@@ -584,3 +598,117 @@ 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;
+    }
+
+    /* Groups are searched for in LDAP, users in GC. Services (if present,
+     * which is unlikely in AD) from LDAP as well
+     */
+    subreq = sdap_dom_enum_ex_send(state, state->ev, state->id_ctx->sdap_id_ctx,
+                                   state->sdom,
+                                   user_conn,                      /* Users  */
+                                   state->subdom_id_ctx->ldap_ctx, /* 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_subdomains.c b/src/providers/ad/ad_subdomains.c
index e7871cc32407893948fe1b2803258d68c70889c1..0d9652b5c615add47958cfdc61eba862a332ae4d 100644
--- a/src/providers/ad/ad_subdomains.c
+++ b/src/providers/ad/ad_subdomains.c
@@ -177,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;
-- 
1.8.4.2

-------------- next part --------------
>From a9bc79c510ff95abc1684c40880730bec06471f6 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Tue, 21 Jan 2014 23:40:17 +0100
Subject: [PATCH 5/6] LDAP: Don't clobber original_member during enumeration

---
 src/providers/ldap/sdap_async_groups.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c
index 4ae772636863acf4c1fd59a20a20d1ad3a28ace0..f203bc962957d469a97a9c114617a0b160ebc4b3 100644
--- a/src/providers/ldap/sdap_async_groups.c
+++ b/src/providers/ldap/sdap_async_groups.c
@@ -804,6 +804,7 @@ static int sdap_save_groups(TALLOC_CTX *memctx,
                             int num_groups,
                             bool populate_members,
                             hash_table_t *ghosts,
+                            bool save_orig_member,
                             char **_usn_value)
 {
     TALLOC_CTX *tmpctx;
@@ -862,7 +863,8 @@ static int sdap_save_groups(TALLOC_CTX *memctx,
 
         /* if 2 pass savemembers = false */
         ret = sdap_save_group(tmpctx, opts, dom, groups[i],
-                              populate_members, has_nesting,
+                              populate_members,
+                              has_nesting && save_orig_member,
                               ghosts, &usn_value, now);
 
         /* Do not fail completely on errors.
@@ -1828,7 +1830,7 @@ static void sdap_get_groups_process(struct tevent_req *subreq)
                   "to allow unrolling of nested groups.\n"));
         ret = sdap_save_groups(state, state->sysdb, state->dom, state->opts,
                                state->groups, state->count, false,
-                               NULL, NULL);
+                               NULL, true, NULL);
         if (ret) {
             DEBUG(2, ("Failed to store groups.\n"));
             tevent_req_error(req, ret);
@@ -1880,10 +1882,14 @@ static void sdap_get_groups_done(struct tevent_req *subreq)
 
         /* If ignore_group_members is set for the domain, don't update
          * group memberships in the cache.
+         *
+         * If enumeration is on, don't overwrite orig_members as they've been
+         * saved earlier.
          */
         ret = sdap_save_groups(state, state->sysdb, state->dom, state->opts,
                                state->groups, state->count,
                                !state->dom->ignore_group_members, NULL,
+                               !state->enumeration,
                                &state->higher_usn);
         if (ret) {
             DEBUG(2, ("Failed to store groups.\n"));
@@ -2007,7 +2013,7 @@ static void sdap_ad_match_rule_members_process(struct tevent_req *subreq)
     /* Now save the group, users and ghosts to the cache */
     ret = sdap_save_groups(tmp_ctx, state->sysdb, state->dom,
                            state->opts, state->groups, 1,
-                           false, ghosts, NULL);
+                           false, ghosts, true, NULL);
     if (ret != EOK) {
         DEBUG(SSSDBG_MINOR_FAILURE,
               ("Could not save group to the cache: [%s]\n",
@@ -2083,7 +2089,7 @@ static void sdap_nested_done(struct tevent_req *subreq)
     }
 
     ret = sdap_save_groups(state, state->sysdb, state->dom, state->opts,
-                           groups, group_count, false, ghosts,
+                           groups, group_count, false, ghosts, true,
                            &state->higher_usn);
     if (ret != EOK) {
         goto fail;
-- 
1.8.4.2

-------------- next part --------------
>From 066ce9945b6af3748f0ead06213f0180a742c542 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Wed, 22 Jan 2014 15:21:24 +0100
Subject: [PATCH 6/6] AD: Establish cross-domain memberships after enumeration
 finishes

Because domain enumeration currently works for each domain separately,
the code has to establish cross-domain memberships after all domains are
enumerated. The code works as follows:

    1) check if any *sub*domains were enumerated. If not, do nothing
    2) if any of the groups saved had more original members than
       sysdb members, check if members of these groups can be linked now
       that all users and groups are saved using the orig_member
       attribute of the group matched against originalDN member of the
       user.

Related:
https://fedorahosted.org/sssd/ticket/2142
---
 src/providers/ad/ad_id.c | 515 +++++++++++++++++++++++++++++++++++------------
 1 file changed, 390 insertions(+), 125 deletions(-)

diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
index 1bdacf74f0e6de2120603401bcf115549a03ac4f..8818869f73be4afa8b36c0da0341391b569aafd2 100644
--- a/src/providers/ad/ad_id.c
+++ b/src/providers/ad/ad_id.c
@@ -420,10 +420,13 @@ struct ad_enumeration_state {
     struct tevent_context *ev;
 
     struct sdap_domain *sdom;
+    struct sdap_domain *sditer;
 };
 
 static void ad_enumeration_conn_done(struct tevent_req *subreq);
 static void ad_enumeration_master_done(struct tevent_req *subreq);
+static errno_t ad_enum_sdom(struct tevent_req *req, struct sdap_domain *sd,
+                            struct ad_id_ctx *id_ctx);
 static void ad_enumeration_done(struct tevent_req *subreq);
 
 struct tevent_req *
@@ -452,6 +455,7 @@ ad_enumeration_send(TALLOC_CTX *mem_ctx,
     state->ectx = ectx;
     state->ev = ev;
     state->sdom = ectx->sdom;
+    state->sditer = state->sdom;
     state->id_ctx = talloc_get_type(ectx->pvt, struct ad_id_ctx);
 
     state->sdap_op = sdap_id_op_create(state,
@@ -526,7 +530,6 @@ ad_enumeration_master_done(struct tevent_req *subreq)
     char *flat_name;
     char *master_sid;
     char *forest;
-    struct sdap_id_conn_ctx *user_conn;
 
     ret = ad_master_domain_recv(subreq, state,
                                 &flat_name, &master_sid, &forest);
@@ -545,32 +548,57 @@ ad_enumeration_master_done(struct tevent_req *subreq)
         return;
     }
 
-    if (dp_opt_get_bool(state->id_ctx->ad_options->basic, AD_ENABLE_GC)) {
-        user_conn = state->id_ctx->gc_ctx;
+    ret = ad_enum_sdom(req, state->sdom, state->id_ctx);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE,
+                ("Could not enumerate domain %s\n", state->sdom->dom->name));
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    /* Execution will resume in ad_enumeration_done */
+}
+
+static errno_t
+ad_enum_sdom(struct tevent_req *req,
+             struct sdap_domain *sd,
+             struct ad_id_ctx *id_ctx)
+{
+    struct sdap_id_conn_ctx *user_conn;
+    struct tevent_req *subreq;
+    struct ad_enumeration_state *state = tevent_req_data(req,
+                                                struct ad_enumeration_state);
+
+    if (dp_opt_get_bool(id_ctx->ad_options->basic, AD_ENABLE_GC)) {
+        user_conn = id_ctx->gc_ctx;
     } else {
-        user_conn = state->id_ctx->ldap_ctx;
+        user_conn = id_ctx->ldap_ctx;
     }
 
     /* Groups are searched for in LDAP, users in GC. Services (if present,
      * which is unlikely in AD) from LDAP as well
      */
     subreq = sdap_dom_enum_ex_send(state, state->ev,
-                                   state->id_ctx->sdap_id_ctx,
-                                   state->sdom,
-                                   user_conn,                /* Users    */
-                                   state->id_ctx->ldap_ctx,  /* Groups   */
-                                   state->id_ctx->ldap_ctx); /* Services */
+                                   id_ctx->sdap_id_ctx,
+                                   sd,
+                                   user_conn,         /* Users    */
+                                   id_ctx->ldap_ctx,  /* Groups   */
+                                   id_ctx->ldap_ctx); /* Services */
     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"));
-        tevent_req_error(req, ENOMEM);
-        return;
+        return ENOMEM;
     }
     tevent_req_set_callback(subreq, ad_enumeration_done, req);
+
+    return EOK;
 }
 
+static errno_t ad_enum_cross_dom_members(struct sdap_options *opts,
+                                         struct sss_domain_info *dom);
+
 static void
 ad_enumeration_done(struct tevent_req *subreq)
 {
@@ -579,121 +607,8 @@ ad_enumeration_done(struct tevent_req *subreq)
                                                       struct tevent_req);
     struct ad_enumeration_state *state = tevent_req_data(req,
                                                 struct ad_enumeration_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_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;
-    }
-
-    /* Groups are searched for in LDAP, users in GC. Services (if present,
-     * which is unlikely in AD) from LDAP as well
-     */
-    subreq = sdap_dom_enum_ex_send(state, state->ev, state->id_ctx->sdap_id_ctx,
-                                   state->sdom,
-                                   user_conn,                      /* Users  */
-                                   state->subdom_id_ctx->ldap_ctx, /* 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) {
@@ -703,11 +618,361 @@ ad_enum_subdom_done(struct tevent_req *subreq)
         return;
     }
 
+    state->sditer = state->sditer->next;
+    if (state->sditer != NULL) {
+        subdom_id_ctx = talloc_get_type(state->sdom->pvt, struct ad_id_ctx);
+        if (subdom_id_ctx == NULL) {
+            DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot retrieve subdomain ad_id_ctx!\n"));
+            tevent_req_error(req, EFAULT);
+            return;
+        }
+
+        ret = ad_enum_sdom(req, state->sditer, state->sditer->pvt);
+        DEBUG(SSSDBG_OP_FAILURE,
+              ("Could not enumerate domain %s\n", state->sditer->dom->name));
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    /* No more subdomains to enumerate. Check if we need to fixup
+     * cross-domain membership
+     */
+    if (state->sditer != state->sdom) {
+        /* We did enumerate at least one subdomain. Walk the subdomains
+         * and fixup members for each of them
+         */
+        for (state->sditer = state->sdom;
+             state->sditer;
+             state->sditer = state->sditer->next) {
+            ret = ad_enum_cross_dom_members(state->id_ctx->ad_options->id,
+                                            state->sditer->dom);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_MINOR_FAILURE, ("Could not check cross-domain "
+                      "memberships for %s, group memberships might be "
+                      "incomplete!\n", state->sdom->dom->name));
+                continue;
+            }
+        }
+    }
+
     tevent_req_done(req);
 }
 
+static errno_t ad_group_extra_members(TALLOC_CTX *mem_ctx,
+                                      const struct ldb_message *group,
+                                      struct sss_domain_info *dom,
+                                      char ***_group_only);
+static errno_t ad_group_add_member(struct sdap_options *opts,
+                                   struct sss_domain_info *group_domain,
+                                   struct ldb_dn *group_dn,
+                                   const char *member);
+
+static errno_t
+ad_enum_cross_dom_members(struct sdap_options *opts,
+                          struct sss_domain_info *dom)
+{
+    errno_t ret;
+    errno_t sret;
+    char *filter;
+    TALLOC_CTX *tmp_ctx;
+    const char *attrs[] = {
+            SYSDB_NAME,
+            SYSDB_MEMBER,
+            SYSDB_ORIG_MEMBER,
+            NULL
+    };
+    size_t count, i, mi;
+    struct ldb_message **msgs;
+    bool in_transaction = false;
+    char **group_only;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) return ENOMEM;
+
+    ret = sysdb_transaction_start(dom->sysdb);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to start transaction\n"));
+        goto done;
+    }
+    in_transaction = true;
+
+    filter = talloc_asprintf(tmp_ctx, "(%s=*)", SYSDB_NAME);
+    if (filter == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = sysdb_search_groups(tmp_ctx, dom, filter, attrs, &count, &msgs);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    for (i = 0; i < count; i++) {
+        ret = ad_group_extra_members(tmp_ctx, msgs[i], dom, &group_only);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, ("Failed to check extra members\n"));
+        } else if (group_only == NULL) {
+            DEBUG(SSSDBG_TRACE_INTERNAL, ("No extra members\n"));
+            continue;
+        }
+
+        /* Group has extra members */
+        for (mi = 0; group_only[mi]; mi++) {
+            ret = ad_group_add_member(opts, dom, msgs[i]->dn, group_only[mi]);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_MINOR_FAILURE, ("Failed to add [%s]: %s\n",
+                      group_only[mi], strerror(ret)));
+                continue;
+            }
+        }
+    }
+
+    ret = sysdb_transaction_commit(dom->sysdb);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to commit transaction\n"));
+        goto done;
+    }
+    in_transaction = false;
+
+    ret = EOK;
+done:
+    if (in_transaction) {
+        sret = sysdb_transaction_cancel(dom->sysdb);
+        if (sret != EOK) {
+            DEBUG(SSSDBG_CRIT_FAILURE, ("Could not cancel transaction\n"));
+        }
+    }
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
+static char **
+ad_group_orig_members(TALLOC_CTX *mem_ctx, struct ldb_message_element *om);
+static errno_t
+ad_group_stored_orig_members(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
+                             struct ldb_dn *dn, char ***_odn_list);
+
+static errno_t
+ad_group_extra_members(TALLOC_CTX *mem_ctx, const struct ldb_message *group,
+                       struct sss_domain_info *dom, char ***_group_only)
+{
+    TALLOC_CTX *tmp_ctx;
+    struct ldb_message_element *m, *om;
+    const char *name;
+    errno_t ret;
+    char **sysdb_odn_list;
+    char **group_odn_list;
+    char **group_only = NULL;
+
+    if (_group_only == NULL) return EINVAL;
+    *_group_only = NULL;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) return ENOMEM;
+
+    om = ldb_msg_find_element(group, SYSDB_ORIG_MEMBER);
+    m = ldb_msg_find_element(group, SYSDB_MEMBER);
+    name = ldb_msg_find_attr_as_string(group, SYSDB_NAME, NULL);
+    if (name == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, ("A group with no name!\n"));
+        ret = EFAULT;
+        goto done;
+    }
+
+    if (om == NULL || om->num_values == 0) {
+        DEBUG(SSSDBG_TRACE_FUNC, ("Group %s has no original members\n", name));
+        ret = EOK;
+        goto done;
+    }
+
+    if (m == NULL || (m->num_values < om->num_values)) {
+        DEBUG(SSSDBG_TRACE_FUNC,
+              ("Group %s has %d members but %d original members\n",
+               name, m ? m->num_values : 0, om->num_values));
+
+        /* Get the list of originalDN attributes that are already
+         * linked to the group
+         */
+        ret = ad_group_stored_orig_members(tmp_ctx, dom, group->dn,
+                                           &sysdb_odn_list);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE,
+                  ("Could not retrieve list of original members for %s\n",
+                  name));
+            goto done;
+        }
+
+        /* Get the list of original DN attributes the group had in AD */
+        group_odn_list = ad_group_orig_members(tmp_ctx, om);
+        if (group_odn_list == NULL) {
+            ret = EFAULT;
+            goto done;
+        }
+
+        /* Compare the two lists */
+        ret = diff_string_lists(tmp_ctx, group_odn_list, sysdb_odn_list,
+                                &group_only, NULL, NULL);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE,
+                  ("Could not compare lists of members for %s\n", name));
+            goto done;
+        }
+    }
+
+    ret = EOK;
+    *_group_only = talloc_steal(mem_ctx, group_only);
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
+static char **
+ad_group_orig_members(TALLOC_CTX *mem_ctx, struct ldb_message_element *om)
+{
+    char **odn_list;
+    size_t i;
+
+    /* Get the list of original DN attributes the group had in AD */
+    odn_list = talloc_zero_array(mem_ctx, char *, om->num_values + 1);
+    if (odn_list == NULL) {
+        return NULL;
+    }
+
+    for (i=0; i < om->num_values; i++) {
+        odn_list[i] = (char *) om->values[i].data;
+    }
+
+    return odn_list;
+}
+
+static errno_t
+ad_group_stored_orig_members(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
+                             struct ldb_dn *dn, char ***_odn_list)
+{
+    errno_t ret;
+    TALLOC_CTX *tmp_ctx;
+    size_t m_count, i;
+    struct ldb_message **members;
+    const char *attrs[] = {
+            SYSDB_NAME,
+            SYSDB_ORIG_DN,
+            NULL
+    };
+    char **odn_list;
+    const char *odn;
+    size_t oi;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) return ENOMEM;
+
+    /* Get all entries member element points to */
+    ret = sysdb_asq_search(tmp_ctx, dom, dn, NULL, SYSDB_MEMBER,
+                           attrs, &m_count, &members);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    odn_list = talloc_zero_array(tmp_ctx, char *, m_count + 1);
+    if (odn_list == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    /* Get a list of their original DNs */
+    oi = 0;
+    for (i = 0; i < m_count; i++) {
+        odn = ldb_msg_find_attr_as_string(members[i], SYSDB_ORIG_DN, NULL);
+        if (odn == NULL) {
+            continue;
+        }
+
+        odn_list[oi] = talloc_strdup(odn_list, odn);
+        if (odn_list[oi] == NULL) {
+            continue;
+        }
+        oi++;
+        DEBUG(SSSDBG_TRACE_INTERNAL, ("Member %s already in sysdb\n", odn));
+    }
+
+    ret = EOK;
+    *_odn_list = talloc_steal(mem_ctx, odn_list);
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
+static errno_t
+ad_group_add_member(struct sdap_options *opts,
+                    struct sss_domain_info *group_domain,
+                    struct ldb_dn *group_dn,
+                    const char *member)
+{
+    struct sdap_domain *sd;
+    struct ldb_dn *base_dn;
+    TALLOC_CTX *tmp_ctx;
+    errno_t ret;
+    const char *mem_filter;
+    size_t msgs_count;
+    struct ldb_message **msgs;
+
+    /* This member would be from a different domain */
+    sd = sdap_domain_get_by_dn(opts, member);
+    if (sd == NULL) {
+        DEBUG(SSSDBG_MINOR_FAILURE, ("No matching domain for %s\n", member));
+        return ENOENT;
+    }
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) return ENOMEM;
+
+    mem_filter = talloc_asprintf(tmp_ctx, "(%s=%s)",
+                                 SYSDB_ORIG_DN, member);
+    if (mem_filter == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    base_dn = sysdb_domain_dn(tmp_ctx, sd->dom);
+    if (base_dn == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = sysdb_search_entry(tmp_ctx, sd->dom->sysdb, base_dn,
+                             LDB_SCOPE_SUBTREE, mem_filter, NULL,
+                             &msgs_count, &msgs);
+    if (ret == ENOENT) {
+        DEBUG(SSSDBG_TRACE_FUNC, ("No member [%s] in sysdb\n", member));
+        ret = EOK;
+        goto done;
+    } else if (ret != EOK) {
+        goto done;
+    }
+    DEBUG(SSSDBG_TRACE_INTERNAL, ("[%s] found in sysdb\n", member));
+
+    if (msgs_count != 1) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+               ("Search by orig DN returned %zd results!\n", msgs_count));
+        ret = EFAULT;
+        goto done;
+    }
+
+    ret = sysdb_mod_group_member(group_domain, msgs[0]->dn, group_dn, SYSDB_MOD_ADD);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, ("Could not add [%s] as a member of [%s]\n",
+              ldb_dn_get_linearized(msgs[0]->dn),
+              ldb_dn_get_linearized(group_dn)));
+        goto done;
+    }
+
+    ret = EOK;
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
 errno_t
-ad_enum_subdom_recv(struct tevent_req *req)
+ad_enumeration_recv(struct tevent_req *req)
 {
     TEVENT_REQ_RETURN_ON_ERROR(req);
     return EOK;
-- 
1.8.4.2



More information about the sssd-devel mailing list