[SSSD] [PATCH] Connect to GC during enumeration

Jakub Hrozek jhrozek at redhat.com
Tue Jan 28 14:34:52 UTC 2014


On Tue, Jan 28, 2014 at 11:17:55AM +0100, Sumit Bose wrote:
> > Thank you for the review. A new set of patches is attached.
> 
> Patches 1, 2, 3 and 5 are looking good.
> 
> In patch 4 you add ad_enum_subdom_send() and ad_enum_subdom_done()
> (without calling them) and in patch 6 you remove them again.

Right, that's a remnant from a previous iteration. The code is
completely removed now.

> 
> Other comments for patch 6 are inline.
> 
> bye,
> Sumit
> 
> 
> > 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;
> >  };
> >  

[snip]

> > -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)
> > -{
> 
> see above.

Squashed into patch 4

> > +    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);
> 
> ret is not checked here as well.

Fixed. I will also run this version of patches through Coverity to see
if there are any new warnings.

> > +    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;
> > +    }
> 
> You try to process all groups in a domain in a single batch. We might
> run into performance/memory issues if there are a lot of groups. But I
> think we can keep it as it is for the time being since the easy
> workaround is to disable enumeration :-)

Yes, I thought this would come up during review, but I couldn't think of
a better way with the current sysdb code. ldb seems to have some kind of
paging support (at least judging by a quick look to ldb.h), but our API
does not use it. So in this code I just limited the number of attributes
we request to a minimum to keep the reply small.

btw the same problem is on the responder side as well -- sysdb_enumpwent
and similar calls also retrieve everything in a single go.

And I agree subdomain enumeration should be strongly discouraged.
Unfortunately, many users are still running enumeration and I'm afraid
they'll continue doing so even with trusted domains.

> 
> > +
> > +    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;
> > +            }
> > +        }

I also added a talloc_free(group_only) here to keep the memory usage
down.

> > +    }
> > +
> > +    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;
> > +}
> > +

[snip]

> > +static char **
> > +ad_group_orig_members(TALLOC_CTX *mem_ctx, struct ldb_message_element *om)
> 
> this looks like a generic ldb_message_element_to_string_list call. I
> would recommend to rename it and maybe move it to utils/ or db/ ebcause
> it might be useful for others as well?

Done. I choose db/ after all because all the includes (ldb.h and
similar) are already there. This is done in a new patch along with a
unit test.

> 
> > +{
> > +    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;
> > +}

[snip]

> > +    /* 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;
> 
> do you really want to continue if talloc_strdup() fails?

No, fixed.

Thank you for the review. New patches are 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/7] 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/7] 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/7] 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 49419d3e2ea321b04f2b1ff743e408cc9f61baf5 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Tue, 28 Jan 2014 13:59:44 +0100
Subject: [PATCH 4/7] AD: Enumerate users from GC, other entities from LDAP

---
 src/providers/ad/ad_id.c | 20 +++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)

diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
index 99383c13bdadfe9eb2af9f9323ca19a9759d4620..a47aa4f75ab348b0f4597fea264d770b5abe3184 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,
-- 
1.8.4.2

-------------- next part --------------
>From c57774fda0e13fc393a02abc173e1ef349e5a2c3 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/7] 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 86ae19029906397ef36999b41606ac3d8fa05039 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Tue, 28 Jan 2014 14:51:58 +0100
Subject: [PATCH 6/7] DB: Add sss_ldb_el_to_string_list

---
 src/db/sysdb.c          | 41 ++++++++++++++++++++++++++---------------
 src/db/sysdb.h          |  2 ++
 src/tests/sysdb-tests.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 77 insertions(+), 15 deletions(-)

diff --git a/src/db/sysdb.c b/src/db/sysdb.c
index b026a298e816862c9b1a22b00c8139b8a27950e7..65277af01630ce94de49315507c0aaf0d284c951 100644
--- a/src/db/sysdb.c
+++ b/src/db/sysdb.c
@@ -464,35 +464,46 @@ errno_t sysdb_attrs_get_bool(struct sysdb_attrs *attrs, const char *name,
     return EOK;
 }
 
-int sysdb_attrs_get_string_array(struct sysdb_attrs *attrs, const char *name,
-                                 TALLOC_CTX *mem_ctx, const char ***string)
+const char **sss_ldb_el_to_string_list(TALLOC_CTX *mem_ctx,
+                                       struct ldb_message_element *el)
 {
-    struct ldb_message_element *el;
-    int ret;
     unsigned int u;
     const char **a;
 
-    ret = sysdb_attrs_get_el_ext(attrs, name, false, &el);
-    if (ret) {
-        return ret;
-    }
-
-    a = talloc_array(mem_ctx, const char *, el->num_values + 1);
+    a = talloc_zero_array(mem_ctx, const char *, el->num_values + 1);
     if (a == NULL) {
-        return ENOMEM;
+        return NULL;
     }
 
-    memset(a, 0, sizeof(const char *) * (el->num_values + 1));
-
-    for(u = 0; u < el->num_values; u++) {
+    for (u = 0; u < el->num_values; u++) {
         a[u] = talloc_strndup(a, (const char *)el->values[u].data,
                               el->values[u].length);
         if (a[u] == NULL) {
             talloc_free(a);
-            return ENOMEM;
+            return NULL;
         }
     }
 
+    return a;
+}
+
+int sysdb_attrs_get_string_array(struct sysdb_attrs *attrs, const char *name,
+                                 TALLOC_CTX *mem_ctx, const char ***string)
+{
+    struct ldb_message_element *el;
+    int ret;
+    const char **a;
+
+    ret = sysdb_attrs_get_el_ext(attrs, name, false, &el);
+    if (ret) {
+        return ret;
+    }
+
+    a = sss_ldb_el_to_string_list(mem_ctx, el);
+    if (a == NULL) {
+        return ENOMEM;
+    }
+
     *string = a;
     return EOK;
 }
diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 1f779875db13f887ef4b211450f1b4e170628907..5d337ffd8c0f7fbe6808d50538192369102caf17 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -288,6 +288,8 @@ int sysdb_attrs_steal_string(struct sysdb_attrs *attrs,
                              const char *name, char *str);
 int sysdb_attrs_get_string(struct sysdb_attrs *attrs, const char *name,
                            const char **string);
+const char **sss_ldb_el_to_string_list(TALLOC_CTX *mem_ctx,
+                                       struct ldb_message_element *el);
 int sysdb_attrs_get_string_array(struct sysdb_attrs *attrs, const char *name,
                                  TALLOC_CTX *mem_ctx, const char ***string);
 errno_t sysdb_attrs_get_bool(struct sysdb_attrs *attrs, const char *name,
diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
index ee0030c14b49144f529039569ab88aa7ec37dc1e..f7d84732a42585029b6f101c8bc1d5f7a10a5139 100644
--- a/src/tests/sysdb-tests.c
+++ b/src/tests/sysdb-tests.c
@@ -4359,6 +4359,52 @@ START_TEST(test_sysdb_attrs_add_lc_name_alias)
 }
 END_TEST
 
+START_TEST(test_sysdb_attrs_get_string_array)
+{
+    int ret;
+    struct sysdb_attrs *attrs;
+    const char **list;
+    const char *attrname = "test_attr";
+    TALLOC_CTX *tmp_ctx;
+    struct ldb_message_element *el = NULL;
+
+    tmp_ctx = talloc_new(NULL);
+    fail_unless(tmp_ctx != NULL, "talloc_new failed");
+
+    attrs = sysdb_new_attrs(NULL);
+    fail_unless(attrs != NULL, "sysdb_new_attrs failed");
+
+    ret = sysdb_attrs_add_string(attrs, attrname, "val1");
+    fail_unless(ret == EOK, "sysdb_attrs_add_string failed");
+    ret = sysdb_attrs_add_string(attrs, attrname, "val2");
+    fail_unless(ret == EOK, "sysdb_attrs_add_string failed");
+
+    ret = sysdb_attrs_get_el_ext(attrs, attrname, false, &el);
+    fail_unless(ret == EOK, "sysdb_attrs_get_el_ext failed");
+
+    list = sss_ldb_el_to_string_list(tmp_ctx, el);
+    fail_if(list == NULL, ("sss_ldb_el_to_string_list failed\n"));
+
+    ck_assert_str_eq(list[0], "val1");
+    ck_assert_str_eq(list[1], "val2");
+    fail_unless(list[2] == NULL, "Expected terminated list");
+
+    talloc_free(list);
+
+    ret = sysdb_attrs_get_string_array(attrs, attrname, tmp_ctx, &list);
+    fail_unless(ret == EOK, "sysdb_attrs_get_string_array failed");
+
+    /* This test relies on values keeping the same order. It is the case
+     * with LDB, but if we ever switch from LDB, we need to amend the test
+     */
+    ck_assert_str_eq(list[0], "val1");
+    ck_assert_str_eq(list[1], "val2");
+    fail_unless(list[2] == NULL, "Expected terminated list");
+
+    talloc_free(tmp_ctx);
+}
+END_TEST
+
 START_TEST(test_sysdb_has_enumerated)
 {
     errno_t ret;
@@ -5119,6 +5165,9 @@ Suite *create_sysdb_suite(void)
 
     tcase_add_test(tc_sysdb, test_sysdb_attrs_add_lc_name_alias);
 
+/* ===== UTIL TESTS ===== */
+    tcase_add_test(tc_sysdb, test_sysdb_attrs_get_string_array);
+
 /* Add all test cases to the test suite */
     suite_add_tcase(s, tc_sysdb);
 
-- 
1.8.4.2

-------------- next part --------------
>From 5d41ed61b844e0e2cb9334ab44cd2aaf0d8d8b9b 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 7/7] 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         | 388 +++++++++++++++++++++++++++++++++++++--
 src/providers/ad/ad_subdomains.c |  11 --
 2 files changed, 377 insertions(+), 22 deletions(-)

diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
index a47aa4f75ab348b0f4597fea264d770b5abe3184..db921b11850c16cc7e818cad481705acbb4b9127 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,6 +607,7 @@ ad_enumeration_done(struct tevent_req *subreq)
                                                       struct tevent_req);
     struct ad_enumeration_state *state = tevent_req_data(req,
                                                 struct ad_enumeration_state);
+    struct ad_id_ctx *subdom_id_ctx;
 
     ret = sdap_dom_enum_ex_recv(subreq);
     talloc_zfree(subreq);
@@ -589,9 +618,346 @@ ad_enumeration_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);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, ("Could not enumerate domain %s\n",
+                  state->sditer->dom->name));
+            tevent_req_error(req, ret);
+            return;
+        }
+
+        /* Execution will resume in ad_enumeration_done */
+        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;
+            }
+        }
+
+        talloc_zfree(group_only);
+    }
+
+    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 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;
+    const 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 = sss_ldb_el_to_string_list(tmp_ctx, om);
+        if (group_odn_list == NULL) {
+            ret = EFAULT;
+            goto done;
+        }
+
+        /* Compare the two lists */
+        ret = diff_string_lists(tmp_ctx, discard_const(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 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) {
+            ret = ENOMEM;
+            goto done;
+        }
+        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_enumeration_recv(struct tevent_req *req)
 {
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



More information about the sssd-devel mailing list