[SSSD] [PATCHES] Enable enumeration and cleanup tasks for subdomains

Jakub Hrozek jhrozek at redhat.com
Wed Aug 28 09:59:59 UTC 2013


On Mon, Aug 26, 2013 at 04:16:54PM +0200, Sumit Bose wrote:
> On Sat, Aug 24, 2013 at 06:42:21PM +0200, Jakub Hrozek wrote:
> > On Thu, Aug 22, 2013 at 12:25:28PM +0200, Jakub Hrozek wrote:
> > > On Thu, Aug 22, 2013 at 12:06:33PM +0200, Jakub Hrozek wrote:
> > > > Hi,
> > > > 
> > > > the attached patch implements enumeration and cleanup for the IPA server
> > > > mode and also makes it possible to support enumeration and cleanup for
> > > > other subdomains in general (we already have a request from one of our
> > > > users to enumerate trusted AD domains).
> > > > 
> > > > Some of the changes can also be leveraged to special-case enumeration
> > > > requests in AD or IPA providers to e.g. download the master domain data
> > > > before enumerating the domain for the first time.
> > > > 
> > > > I hope the patches are split well to make it possible to review them
> > > > easily. The bigger patches usually just move code around.
> > > 
> > > I forgot to note two important things:
> > > 
> > > 1) the subdomain enumeration setting is inherited from the master domain
> > > enumeration. Is this OK or do we need to enumerate the AD trusted domain
> > > automatically? I think that only a minority of the legacy clients
> > > actually need enumeration, so as long as we document how enumeration
> > > works in the server mode, we should be fine.
> > > 
> > > 2) These patches currently do not optimize the enumeration which is what
> > > the ticket initially talked about. The reason is that just enabling the
> > > enumeration properly took a long time and also performance is only a
> > > problem for the initial enumeration. The subsequent ones can leverage
> > > lastUSN to only download deltas. Because the IPA server would mostly
> > > stay online and running, I think the initial enumeration can be further
> > > optimized in 1.11.1. Sumit came up with some idea when he visited Brno,
> > > so I'll work on that next week.
> > 
> > I found a couple of bugs (tevent_req_error not terminated with return,
> > uninitialized variable etc). New patches are attached.
> > 
> > Please note that these patches depend on the patch with subject "DB:
> > Update sss_domain_info with new updated data".
> 
> Please find my comments below. The patches work as expected. So far I've
> only tested against a small amount of users and groups but I'll try to
> test with a larger domain as well.
> 
> bye,
> Sumit
> 

Thanks for the review.

> > Subject: [PATCH 01/11] LDAP: Add enum_{users,groups} to follow the tevent_req
> >  style
> > 
> ...
> > @@ -296,22 +298,12 @@ static void ldap_id_enum_users_done(struct tevent_req *subreq)
> >                                                        struct tevent_req);
> >      struct global_enum_state *state = tevent_req_data(req,
> >                                                   struct global_enum_state);
> > -    enum tevent_req_state tstate;
> >      uint64_t err = 0;
> >      int ret, dp_error = DP_ERR_FATAL;
> >  
> > -    if (tevent_req_is_error(subreq, &tstate, &err)) {
> > -        if (tstate != TEVENT_REQ_USER_ERROR) {
> > -            err = EIO;
> > -        }
> > -
> > -        if (err == ENOENT) {
> > -            err = EOK;
> > -        }
> > -    }
> > +    err = enum_users_recv(subreq);
> >      talloc_zfree(subreq);
> > -
> > -    if (err != EOK) {
> > +    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);
> > @@ -351,21 +343,11 @@ static void ldap_id_enum_groups_done(struct tevent_req *subreq)
> >                                                        struct tevent_req);
> >      struct global_enum_state *state = tevent_req_data(req,
> >                                                   struct global_enum_state);
> > -    enum tevent_req_state tstate;
> >      uint64_t err = 0;
> >      int ret, dp_error = DP_ERR_FATAL;
> >  
> > -    if (tevent_req_is_error(subreq, &tstate, &err)) {
> > -        if (tstate != TEVENT_REQ_USER_ERROR) {
> > -            err = EIO;
> > -        }
> > -
> > -        if (err == ENOENT) {
> > -            err = EOK;
> > -        }
> > -    }
> > +    err = enum_groups_recv(subreq);
> >      talloc_zfree(subreq);
> > -
> >      if (err != EOK) {
> 
> I wonder how ENOENT is handled or of it needs to be handled at all? In
> the old code for users and groups err was set to EOK is it was ENOENT.
> Now you check for (err != EOK && err != ENOENT) for users but only (err
> != EOK) for groups. In a later patch you drop the ENOENT check for users
> as well.
> 
> Can enum_users_recv() or enum_groups_recv() return ENOENT? If yes and if
> it means the either no users or groups were found I think we should not
> treat it as an error.

You're right, the attached patches ignore ENOENT from enum_users_recv,
enum_groups_recv and enum_services_recv. The enumeration request itself
doesn't report ENOENT back to the caller.

> 
> >          /* We call sdap_id_op_done only on error
> >           * as the connection is reused by services enumeration */
> > @@ -632,6 +614,13 @@ static void enum_users_op_done(struct tevent_req *subreq)
> >      tevent_req_done(req);
> >  }
> >  
> 
> > Subject: [PATCH 02/11] LDAP: Remove unused constant
> ACK

No changes to this patch.

> 
> > Subject: [PATCH 03/11] LDAP: Move the ldap enum request to its own reusable
> >  module
> ACK

ENOENT handled same as after patch #1.

> 
> > Subject: [PATCH 04/11] LDAP: Convert enumeration to the ptask API
> ACK

No changes to this patch.

> 
> > Subject: [PATCH 05/11] LDAP: Make cleanup synchronous
> ACK
> 

No changes to this patch.

> > Subject: [PATCH 06/11] LDAP: Make the cleanup task reusable for subdomains
> ACK
> 

No changes to this patch.

> > Subject: [PATCH 07/11] LDAP: Make sdap_id_setup_tasks reusable for subdomains
> ACK

No changes to this patch.

> 
> > Subject: [PATCH 08/11] SYSDB: Store enumerate flag for subdomain
> ACK

No changes to this patch.

> 
> > Subject: [PATCH 09/11] Read enumerate state for subdomains from cache
> ACK

No changes to this patch.

> 
> > Subject: [PATCH 10/11] IPA: enable enumeration if parent domain enumerates in
> >  server mode
> ...
> > 
> >  static errno_t ipa_subdom_store(struct sss_domain_info *domain,
> >                                  struct sdap_idmap_ctx *sdap_idmap_ctx,
> > -                                struct sysdb_attrs *attrs)
> > +                                struct sysdb_attrs *attrs,
> > +                                bool server_mode)
> 
> I think it would be better to pass just the enumerate flag here instead
> of the server_mode flag and make the decision if enumeration should be
> used or not in the caller.
> 
> >  {
> >      TALLOC_CTX *tmp_ctx;
> >      const char *name;
> > @@ -413,6 +432,7 @@ static errno_t ipa_subdom_store(struct sss_domain_info *domain,
> >      const char *id;
> >      int ret;
> >      bool mpg;
> > +    bool enumerate;
> >  
> >      tmp_ctx = talloc_new(domain);
> >      if (tmp_ctx == NULL) {
> > @@ -445,8 +465,14 @@ static errno_t ipa_subdom_store(struct sss_domain_info *domain,
> >  
> >      mpg = sdap_idmap_domain_has_algorithmic_mapping(sdap_idmap_ctx, id);
> >  
> > +    if (server_mode == true) {
> > +        enumerate = domain->enumerate;
> > +    } else {
> > +        enumerate = false;
> > +    }
> > +
> 
> As said above I would prefer that the decision is made in the caller.
> Additionally I do not like the logic, because it forces to use
> enumerating for the IPA domain as well which  in my opinion is only of
> limited use because since we are in server mode sssd is running on the
> IPA server.
> 
> A separate option like ipa_server_mode_enum with values like 'all',
> 'none' or a list of subdomains which should be enumerated would help.
> Or, and I think I like this better even if it requires some work on the
> IPA side as well, read a flag from the IPA trust object like
> ipaEnumerate which indicates if the domain should be enumerated or not.

OK, there is a new patch (#10) that adds a subdomain_enumerate option to
the domain section. Currently it defaults to "none" as without slapi-nis
taking advantage of the enumeration, there can't even be a consumer. Can
you file a freeipa ticket so that they implement the ipaEnumerate flag?
I agree it would be the best way. Then we can change the default of the
SSSD option to be "autodetect".

> 
> >      ret = sysdb_subdomain_store(domain->sysdb, name, realm, flat,
> > -                                id, mpg, false);
> > +                                id, mpg, enumerate);
> >      if (ret) {
> >          DEBUG(SSSDBG_OP_FAILURE, ("sysdb_subdomain_store failed.\n"));
> >          goto done;
> 
> > Subject: [PATCH 11/11] NSS: Descend into subdomains if enumerate=true
> ACK

Since enumeration of domain and subdomain is configured separately now,
I also amended the check if any domain enumerates to be able to recurse
to subdomains.
-------------- next part --------------
>From 2d54c461afe3dab6193ccde8657ca0ad5836c2f7 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Tue, 20 Aug 2013 16:12:13 +0200
Subject: [PATCH 01/12] LDAP: Add enum_{users,groups}_recv to follow the
 tevent_req style

The enum code was quite old and predated the tevent_req style. In
particular, the enum code was checking tevent state direcly and not
using _recv functions or the helper macros we added later.
As a consequence, it was not easy to read. This patch adds the standard
_recv functions to read the status of the enum requests.
---
 src/providers/ldap/ldap_id_enum.c | 43 +++++++++++++++++----------------------
 1 file changed, 19 insertions(+), 24 deletions(-)

diff --git a/src/providers/ldap/ldap_id_enum.c b/src/providers/ldap/ldap_id_enum.c
index 06d6e8772c066169a38dc9b37080d07cf710a8d8..4e8a80c44d8515dedb80502a2a57872e6bffed7a 100644
--- a/src/providers/ldap/ldap_id_enum.c
+++ b/src/providers/ldap/ldap_id_enum.c
@@ -192,6 +192,7 @@ static struct tevent_req *enum_users_send(TALLOC_CTX *memctx,
                                           struct sdap_domain *sdom,
                                           struct sdap_id_op *op,
                                           bool purge);
+static errno_t enum_users_recv(struct tevent_req *req);
 static void ldap_id_enum_users_done(struct tevent_req *subreq);
 static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
                                           struct tevent_context *ev,
@@ -199,6 +200,7 @@ static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
                                           struct sdap_domain *sdom,
                                           struct sdap_id_op *op,
                                           bool purge);
+static errno_t enum_groups_recv(struct tevent_req *req);
 static void ldap_id_enum_groups_done(struct tevent_req *subreq);
 static void ldap_id_enum_services_done(struct tevent_req *subreq);
 static void ldap_id_enum_cleanup_done(struct tevent_req *subreq);
@@ -296,22 +298,12 @@ static void ldap_id_enum_users_done(struct tevent_req *subreq)
                                                       struct tevent_req);
     struct global_enum_state *state = tevent_req_data(req,
                                                  struct global_enum_state);
-    enum tevent_req_state tstate;
     uint64_t err = 0;
     int ret, dp_error = DP_ERR_FATAL;
 
-    if (tevent_req_is_error(subreq, &tstate, &err)) {
-        if (tstate != TEVENT_REQ_USER_ERROR) {
-            err = EIO;
-        }
-
-        if (err == ENOENT) {
-            err = EOK;
-        }
-    }
+    err = enum_users_recv(subreq);
     talloc_zfree(subreq);
-
-    if (err != EOK) {
+    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);
@@ -351,22 +343,12 @@ static void ldap_id_enum_groups_done(struct tevent_req *subreq)
                                                       struct tevent_req);
     struct global_enum_state *state = tevent_req_data(req,
                                                  struct global_enum_state);
-    enum tevent_req_state tstate;
     uint64_t err = 0;
     int ret, dp_error = DP_ERR_FATAL;
 
-    if (tevent_req_is_error(subreq, &tstate, &err)) {
-        if (tstate != TEVENT_REQ_USER_ERROR) {
-            err = EIO;
-        }
-
-        if (err == ENOENT) {
-            err = EOK;
-        }
-    }
+    err = enum_groups_recv(subreq);
     talloc_zfree(subreq);
-
-    if (err != EOK) {
+    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);
@@ -632,6 +614,13 @@ static void enum_users_op_done(struct tevent_req *subreq)
     tevent_req_done(req);
 }
 
+static errno_t enum_users_recv(struct tevent_req *req)
+{
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    return EOK;
+}
+
 /* =Group-Enumeration===================================================== */
 
 struct enum_groups_state {
@@ -794,3 +783,9 @@ static void enum_groups_op_done(struct tevent_req *subreq)
     tevent_req_done(req);
 }
 
+static errno_t enum_groups_recv(struct tevent_req *req)
+{
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    return EOK;
+}
-- 
1.8.3.1

-------------- next part --------------
>From dddc067a2fa97d9740fa62c5b425092e912c8083 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Tue, 20 Aug 2013 16:12:32 +0200
Subject: [PATCH 02/12] LDAP: Remove unused constant

The constant was not used since Euegene came up with his reconnection
logic.
---
 src/providers/ldap/ldap_id_enum.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/providers/ldap/ldap_id_enum.c b/src/providers/ldap/ldap_id_enum.c
index 4e8a80c44d8515dedb80502a2a57872e6bffed7a..7d9ff3be2e01af79ba7c1969464dcc96860122b9 100644
--- a/src/providers/ldap/ldap_id_enum.c
+++ b/src/providers/ldap/ldap_id_enum.c
@@ -176,8 +176,6 @@ int ldap_id_enumerate_set_timer(struct sdap_id_ctx *ctx, struct timeval tv)
     return EOK;
 }
 
-#define MAX_ENUM_RESTARTS 3
-
 struct global_enum_state {
     struct tevent_context *ev;
     struct sdap_id_ctx *ctx;
-- 
1.8.3.1

-------------- next part --------------
>From 52eda3e41945531adb9bda4772fe1eae3e472343 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Tue, 27 Aug 2013 11:59:10 +0200
Subject: [PATCH 03/12] LDAP: Move the ldap enum request to its own reusable
 module

The LDAP enumeration was too closely tied to the LDAP identity provider.
Because some providers might need special handling such as refresh the
master domain record before proceeding with the enumeration itself, this
patch splits the request itself to a separate async request and lets the
ldap_id_enum.c module only configure this new request.

Also move the enum timestamp to sdap_domain to make the enum tracking
per sdap domain. The cleanup timestamp will be moved in another patch.
---
 Makefile.am                                        |   2 +
 src/providers/ldap/ldap_common.h                   |   5 -
 src/providers/ldap/ldap_id_enum.c                  | 637 +--------------------
 src/providers/ldap/sdap.h                          |   3 +
 .../ldap/{ldap_id_enum.c => sdap_async_enum.c}     | 356 ++++--------
 src/providers/ldap/sdap_async_enum.h               |  38 ++
 src/providers/ldap/sdap_reinit.c                   |  13 +-
 7 files changed, 183 insertions(+), 871 deletions(-)
 copy src/providers/ldap/{ldap_id_enum.c => sdap_async_enum.c} (64%)
 create mode 100644 src/providers/ldap/sdap_async_enum.h

diff --git a/Makefile.am b/Makefile.am
index c3f3c4a54953ff71a680ecdb5b8c8c2a6498e730..e24fb061e102cefa4171515095780220ee58c85c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -460,6 +460,7 @@ dist_noinst_HEADERS = \
     src/providers/ldap/sdap_range.h \
     src/providers/ldap/sdap_users.h \
     src/providers/ldap/sdap_dyndns.h \
+    src/providers/ldap/sdap_async_enum.h \
     src/providers/ipa/ipa_common.h \
     src/providers/ipa/ipa_config.h \
     src/providers/ipa/ipa_access.h \
@@ -1428,6 +1429,7 @@ pkglib_LTLIBRARIES += libsss_ldap_common.la
 libsss_ldap_common_la_SOURCES = \
     src/providers/ldap/ldap_id.c \
     src/providers/ldap/ldap_id_enum.c \
+    src/providers/ldap/sdap_async_enum.c \
     src/providers/ldap/ldap_id_cleanup.c \
     src/providers/ldap/ldap_id_netgroup.c \
     src/providers/ldap/ldap_id_services.c \
diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
index db2466ad832d7867d9244a835cde1adab39d347d..c9b2f663b72658c9cdcd4d54ec32b1dd74f31326 100644
--- a/src/providers/ldap/ldap_common.h
+++ b/src/providers/ldap/ldap_common.h
@@ -63,8 +63,6 @@ struct sdap_id_ctx {
     /* connection to a server */
     struct sdap_id_conn_ctx *conn;
 
-    /* enumeration loop timer */
-    struct timeval last_enum;
     /* cleanup loop timer */
     struct timeval last_purge;
 
@@ -170,9 +168,6 @@ int ldap_get_autofs_options(TALLOC_CTX *memctx,
 int ldap_id_enumerate_set_timer(struct sdap_id_ctx *ctx, struct timeval tv);
 int ldap_id_cleanup_set_timer(struct sdap_id_ctx *ctx, struct timeval tv);
 
-struct tevent_req *ldap_id_enumerate_send(struct tevent_context *ev,
-                                          struct sdap_id_ctx *ctx);
-
 void sdap_mark_offline(struct sdap_id_ctx *ctx);
 
 struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
diff --git a/src/providers/ldap/ldap_id_enum.c b/src/providers/ldap/ldap_id_enum.c
index 7d9ff3be2e01af79ba7c1969464dcc96860122b9..43eb4c9972bb7383435e2e130f01646af46c0c38 100644
--- a/src/providers/ldap/ldap_id_enum.c
+++ b/src/providers/ldap/ldap_id_enum.c
@@ -31,6 +31,7 @@
 #include "providers/ldap/ldap_common.h"
 #include "providers/ldap/sdap_async.h"
 #include "providers/ldap/sdap_idmap.h"
+#include "providers/ldap/sdap_async_enum.h"
 
 extern struct tevent_req *ldap_id_cleanup_send(TALLOC_CTX *memctx,
                                                struct tevent_context *ev,
@@ -38,9 +39,6 @@ extern struct tevent_req *ldap_id_cleanup_send(TALLOC_CTX *memctx,
 
 /* ==Enumeration-Task===================================================== */
 
-static int ldap_id_enumerate_retry(struct tevent_req *req);
-static void ldap_id_enumerate_connect_done(struct tevent_req *req);
-
 static void ldap_id_enumerate_reschedule(struct tevent_req *req);
 
 static void ldap_id_enumerate_timeout(struct tevent_context *ev,
@@ -66,7 +64,7 @@ static void ldap_id_enumerate_timer(struct tevent_context *ev,
         return;
     }
 
-    req = ldap_id_enumerate_send(ev, ctx);
+    req = sdap_dom_enum_send(ctx, ev, ctx, ctx->opts->sdom, ctx->conn);
     if (!req) {
         DEBUG(1, ("Failed to schedule enumeration, retrying later!\n"));
         /* schedule starting from now, not the last run */
@@ -129,30 +127,19 @@ static void ldap_id_enumerate_reschedule(struct tevent_req *req)
 {
     struct sdap_id_ctx *ctx = tevent_req_callback_data(req,
                                                        struct sdap_id_ctx);
-    enum tevent_req_state tstate;
-    uint64_t err;
     struct timeval tv;
     int delay;
     errno_t ret;
 
-    if (tevent_req_is_error(req, &tstate, &err)) {
+    ret = sdap_dom_enum_recv(req);
+    talloc_zfree(req);
+    if (ret != EOK) {
         /* On error schedule starting from now, not the last run */
         tv = tevent_timeval_current();
     } else {
-        tv = ctx->last_enum;
+        tv = ctx->opts->sdom->last_enum;
 
-        /* Ok, we've completed an enumeration. Save this to the
-         * sysdb so we can postpone starting up the enumeration
-         * process on the next SSSD service restart (to avoid
-         * slowing down system boot-up
-         */
-        ret = sysdb_set_enumerated(ctx->be->domain->sysdb, ctx->be->domain, true);
-        if (ret != EOK) {
-            DEBUG(1, ("Could not mark domain as having enumerated.\n"));
-            /* This error is non-fatal, so continue */
-        }
     }
-    talloc_zfree(req);
 
     delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
     tv = tevent_timeval_add(&tv, delay, 0);
@@ -175,615 +162,3 @@ int ldap_id_enumerate_set_timer(struct sdap_id_ctx *ctx, struct timeval tv)
 
     return EOK;
 }
-
-struct global_enum_state {
-    struct tevent_context *ev;
-    struct sdap_id_ctx *ctx;
-    struct sdap_id_op *op;
-
-    bool purge;
-};
-
-static struct tevent_req *enum_users_send(TALLOC_CTX *memctx,
-                                          struct tevent_context *ev,
-                                          struct sdap_id_ctx *ctx,
-                                          struct sdap_domain *sdom,
-                                          struct sdap_id_op *op,
-                                          bool purge);
-static errno_t enum_users_recv(struct tevent_req *req);
-static void ldap_id_enum_users_done(struct tevent_req *subreq);
-static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
-                                          struct tevent_context *ev,
-                                          struct sdap_id_ctx *ctx,
-                                          struct sdap_domain *sdom,
-                                          struct sdap_id_op *op,
-                                          bool purge);
-static errno_t enum_groups_recv(struct tevent_req *req);
-static void ldap_id_enum_groups_done(struct tevent_req *subreq);
-static void ldap_id_enum_services_done(struct tevent_req *subreq);
-static void ldap_id_enum_cleanup_done(struct tevent_req *subreq);
-
-struct tevent_req *ldap_id_enumerate_send(struct tevent_context *ev,
-                                          struct sdap_id_ctx *ctx)
-{
-    struct global_enum_state *state;
-    struct tevent_req *req;
-    int t;
-
-    req = tevent_req_create(ctx, &state, struct global_enum_state);
-    if (!req) return NULL;
-
-    state->ev = ev;
-    state->ctx = ctx;
-    state->op = sdap_id_op_create(state, state->ctx->conn->conn_cache);
-    if (!state->op) {
-        DEBUG(2, ("sdap_id_op_create failed\n"));
-        talloc_zfree(req);
-        return NULL;
-    }
-
-    ctx->last_enum = tevent_timeval_current();
-
-    t = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT);
-    if ((ctx->last_purge.tv_sec + t) < ctx->last_enum.tv_sec) {
-        state->purge = true;
-    } else {
-        state->purge = false;
-    }
-
-    int ret = ldap_id_enumerate_retry(req);
-    if (ret != EOK) {
-        DEBUG(2, ("ldap_id_enumerate_retry failed\n"));
-        talloc_zfree(req);
-        return NULL;
-    }
-
-    return req;
-}
-
-static int ldap_id_enumerate_retry(struct tevent_req *req)
-{
-    struct global_enum_state *state = tevent_req_data(req,
-                                                      struct global_enum_state);
-    struct tevent_req *subreq;
-    int ret;
-
-    subreq = sdap_id_op_connect_send(state->op, state, &ret);
-    if (!subreq) {
-        return ret;
-    }
-
-    tevent_req_set_callback(subreq, ldap_id_enumerate_connect_done, req);
-    return EOK;
-}
-
-static void ldap_id_enumerate_connect_done(struct tevent_req *subreq)
-{
-    struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                      struct tevent_req);
-    struct global_enum_state *state = tevent_req_data(req,
-                                                 struct global_enum_state);
-    int ret, dp_error;
-
-    ret = sdap_id_op_connect_recv(subreq, &dp_error);
-    talloc_zfree(subreq);
-    if (ret != EOK) {
-        if (dp_error == DP_ERR_OFFLINE) {
-            tevent_req_done(req);
-        } else {
-            DEBUG(9, ("User enumeration failed to connect to LDAP server: (%d)[%s]\n",
-                      ret, strerror(ret)));
-            tevent_req_error(req, ret);
-        }
-
-        return;
-    }
-
-    subreq = enum_users_send(state, state->ev,
-                             state->ctx, state->ctx->opts->sdom,
-                             state->op, state->purge);
-    if(!subreq) {
-        tevent_req_error(req, ENOMEM);
-        return;
-    }
-
-    tevent_req_set_callback(subreq, ldap_id_enum_users_done, req);
-}
-
-static void ldap_id_enum_users_done(struct tevent_req *subreq)
-{
-    struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                      struct tevent_req);
-    struct global_enum_state *state = tevent_req_data(req,
-                                                 struct global_enum_state);
-    uint64_t err = 0;
-    int ret, dp_error = DP_ERR_FATAL;
-
-    err = 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 = ldap_id_enumerate_retry(req);
-            if (ret == EOK) {
-                return;
-            }
-
-            dp_error = DP_ERR_FATAL;
-        }
-
-        if (dp_error == DP_ERR_OFFLINE) {
-            tevent_req_done(req);
-        } else {
-            DEBUG(9, ("User enumeration failed with: (%d)[%s]\n",
-                      ret, strerror(ret)));
-            tevent_req_error(req, ret);
-        }
-        return;
-    }
-
-    subreq = enum_groups_send(state, state->ev, state->ctx,
-                              state->ctx->opts->sdom,
-                              state->op, state->purge);
-    if (!subreq) {
-        tevent_req_error(req, ENOMEM);
-        return;
-    }
-    tevent_req_set_callback(subreq, ldap_id_enum_groups_done, req);
-}
-
-static void ldap_id_enum_groups_done(struct tevent_req *subreq)
-{
-    struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                      struct tevent_req);
-    struct global_enum_state *state = tevent_req_data(req,
-                                                 struct global_enum_state);
-    uint64_t err = 0;
-    int ret, dp_error = DP_ERR_FATAL;
-
-    err = 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 = ldap_id_enumerate_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(9, ("Group enumeration failed with: (%d)[%s]\n",
-                          ret, strerror(ret)));
-                tevent_req_error(req, ret);
-            }
-
-            return;
-        }
-    }
-
-    subreq = enum_services_send(state, state->ev, state->ctx,
-                                state->op, state->purge);
-    if (!subreq) {
-        tevent_req_error(req, ENOMEM);
-        return;
-    }
-    tevent_req_set_callback(subreq, ldap_id_enum_services_done, req);
-}
-
-static void ldap_id_enum_services_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 global_enum_state *state = tevent_req_data(req,
-                                                 struct global_enum_state);
-
-    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);
-    if (dp_error == DP_ERR_OK && ret != EOK) {
-        /* retry */
-        ret = ldap_id_enumerate_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)));
-            tevent_req_error(req, ret);
-        }
-
-        return;
-    }
-
-    if (state->purge) {
-
-        subreq = ldap_id_cleanup_send(state, state->ev, state->ctx);
-        if (!subreq) {
-            tevent_req_error(req, ENOMEM);
-            return;
-        }
-
-        tevent_req_set_callback(subreq, ldap_id_enum_cleanup_done, req);
-        return;
-    }
-
-    tevent_req_done(req);
-}
-
-static void ldap_id_enum_cleanup_done(struct tevent_req *subreq)
-{
-    struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                      struct tevent_req);
-    talloc_zfree(subreq);
-    tevent_req_done(req);
-}
-
-/* ==User-Enumeration===================================================== */
-
-struct enum_users_state {
-    struct tevent_context *ev;
-    struct sdap_id_ctx *ctx;
-    struct sdap_domain *sdom;
-    struct sdap_id_op *op;
-
-    char *filter;
-    const char **attrs;
-};
-
-static void enum_users_op_done(struct tevent_req *subreq);
-
-static struct tevent_req *enum_users_send(TALLOC_CTX *memctx,
-                                          struct tevent_context *ev,
-                                          struct sdap_id_ctx *ctx,
-                                          struct sdap_domain *sdom,
-                                          struct sdap_id_op *op,
-                                          bool purge)
-{
-    struct tevent_req *req, *subreq;
-    struct enum_users_state *state;
-    int ret;
-    bool use_mapping;
-
-    req = tevent_req_create(memctx, &state, struct enum_users_state);
-    if (!req) return NULL;
-
-    state->ev = ev;
-    state->sdom = sdom;
-    state->ctx = ctx;
-    state->op = op;
-
-    use_mapping = sdap_idmap_domain_has_algorithmic_mapping(
-                                                          ctx->opts->idmap_ctx,
-                                                          sdom->dom->domain_id);
-
-    /* We always want to filter on objectclass and an available name */
-    state->filter = talloc_asprintf(state,
-                                    "(&(objectclass=%s)(%s=*)",
-                                    ctx->opts->user_map[SDAP_OC_USER].name,
-                                    ctx->opts->user_map[SDAP_AT_USER_NAME].name);
-    if (!state->filter) {
-        DEBUG(SSSDBG_MINOR_FAILURE,
-              ("Failed to build base filter\n"));
-        ret = ENOMEM;
-        goto fail;
-    }
-
-    if (use_mapping) {
-        /* If we're ID-mapping, check for the objectSID as well */
-        state->filter = talloc_asprintf_append_buffer(
-                state->filter, "(%s=*)",
-                ctx->opts->user_map[SDAP_AT_USER_OBJECTSID].name);
-    } else {
-        /* We're not ID-mapping, so make sure to only get entries
-         * that have UID and GID
-         */
-        state->filter = talloc_asprintf_append_buffer(
-                state->filter, "(%s=*)(%s=*)",
-                ctx->opts->user_map[SDAP_AT_USER_UID].name,
-                ctx->opts->user_map[SDAP_AT_USER_GID].name);
-    }
-    if (!state->filter) {
-        DEBUG(SSSDBG_MINOR_FAILURE,
-              ("Failed to build base filter\n"));
-        ret = ENOMEM;
-        goto fail;
-    }
-
-    if (ctx->srv_opts && ctx->srv_opts->max_user_value && !purge) {
-        /* If we have lastUSN available and we're not doing a full
-         * refresh, limit to changes with a higher entryUSN value.
-         */
-        state->filter = talloc_asprintf_append_buffer(
-                state->filter,
-                "(%s>=%s)(!(%s=%s))",
-                ctx->opts->user_map[SDAP_AT_USER_USN].name,
-                ctx->srv_opts->max_user_value,
-                ctx->opts->user_map[SDAP_AT_USER_USN].name,
-                ctx->srv_opts->max_user_value);
-
-        if (!state->filter) {
-            DEBUG(SSSDBG_MINOR_FAILURE,
-                  ("Failed to build base filter\n"));
-            ret = ENOMEM;
-            goto fail;
-        }
-    }
-
-    /* Terminate the search filter */
-    state->filter = talloc_asprintf_append_buffer(state->filter, ")");
-    if (!state->filter) {
-        DEBUG(2, ("Failed to build base filter\n"));
-        ret = ENOMEM;
-        goto fail;
-    }
-
-    /* TODO: handle attrs_type */
-    ret = build_attrs_from_map(state, ctx->opts->user_map, SDAP_OPTS_USER,
-                               NULL, &state->attrs, NULL);
-    if (ret != EOK) goto fail;
-
-    /* TODO: restrict the enumerations to using a single
-     * search base at a time.
-     */
-
-    subreq = sdap_get_users_send(state, state->ev,
-                                 state->sdom->dom,
-                                 state->sdom->dom->sysdb,
-                                 state->ctx->opts,
-                                 state->sdom->user_search_bases,
-                                 sdap_id_op_handle(state->op),
-                                 state->attrs, state->filter,
-                                 dp_opt_get_int(state->ctx->opts->basic,
-                                                SDAP_ENUM_SEARCH_TIMEOUT),
-                                 true);
-    if (!subreq) {
-        ret = ENOMEM;
-        goto fail;
-    }
-    tevent_req_set_callback(subreq, enum_users_op_done, req);
-
-    return req;
-
-fail:
-    tevent_req_error(req, ret);
-    tevent_req_post(req, ev);
-    return req;
-}
-
-static void enum_users_op_done(struct tevent_req *subreq)
-{
-    struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                      struct tevent_req);
-    struct enum_users_state *state = tevent_req_data(req,
-                                                     struct enum_users_state);
-    char *usn_value;
-    char *endptr = NULL;
-    unsigned usn_number;
-    int ret;
-
-    ret = sdap_get_users_recv(subreq, state, &usn_value);
-    talloc_zfree(subreq);
-    if (ret) {
-        tevent_req_error(req, ret);
-        return;
-    }
-
-    if (usn_value) {
-        talloc_zfree(state->ctx->srv_opts->max_user_value);
-        state->ctx->srv_opts->max_user_value = talloc_steal(state->ctx, usn_value);
-
-        usn_number = strtoul(usn_value, &endptr, 10);
-        if ((endptr == NULL || (*endptr == '\0' && endptr != usn_value))
-            && (usn_number > state->ctx->srv_opts->last_usn)) {
-            state->ctx->srv_opts->last_usn = usn_number;
-        }
-    }
-
-    DEBUG(4, ("Users higher USN value: [%s]\n",
-              state->ctx->srv_opts->max_user_value));
-
-    tevent_req_done(req);
-}
-
-static errno_t enum_users_recv(struct tevent_req *req)
-{
-    TEVENT_REQ_RETURN_ON_ERROR(req);
-
-    return EOK;
-}
-
-/* =Group-Enumeration===================================================== */
-
-struct enum_groups_state {
-    struct tevent_context *ev;
-    struct sdap_id_ctx *ctx;
-    struct sdap_domain *sdom;
-    struct sdap_id_op *op;
-
-    char *filter;
-    const char **attrs;
-};
-
-static void enum_groups_op_done(struct tevent_req *subreq);
-
-static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
-                                          struct tevent_context *ev,
-                                          struct sdap_id_ctx *ctx,
-                                          struct sdap_domain *sdom,
-                                          struct sdap_id_op *op,
-                                          bool purge)
-{
-    struct tevent_req *req, *subreq;
-    struct enum_groups_state *state;
-    int ret;
-    bool use_mapping;
-
-    req = tevent_req_create(memctx, &state, struct enum_groups_state);
-    if (!req) return NULL;
-
-    state->ev = ev;
-    state->sdom = sdom;
-    state->ctx = ctx;
-    state->op = op;
-
-    use_mapping = sdap_idmap_domain_has_algorithmic_mapping(
-                                                          ctx->opts->idmap_ctx,
-                                                          sdom->dom->domain_id);
-
-    /* We always want to filter on objectclass and an available name */
-    state->filter = talloc_asprintf(state,
-                                    "(&(objectclass=%s)(%s=*)",
-                                    ctx->opts->group_map[SDAP_OC_GROUP].name,
-                                    ctx->opts->group_map[SDAP_AT_GROUP_NAME].name);
-    if (!state->filter) {
-        DEBUG(SSSDBG_MINOR_FAILURE,
-              ("Failed to build base filter\n"));
-        ret = ENOMEM;
-        goto fail;
-    }
-
-    if (use_mapping) {
-        /* If we're ID-mapping, check for the objectSID as well */
-        state->filter = talloc_asprintf_append_buffer(
-                state->filter, "(%s=*)",
-                ctx->opts->group_map[SDAP_AT_GROUP_OBJECTSID].name);
-    } else {
-        /* We're not ID-mapping, so make sure to only get entries
-         * that have a non-zero GID.
-         */
-        state->filter = talloc_asprintf_append_buffer(
-                state->filter, "(&(%s=*)(!(%s=0)))",
-                ctx->opts->group_map[SDAP_AT_GROUP_GID].name,
-                ctx->opts->group_map[SDAP_AT_GROUP_GID].name);
-    }
-    if (!state->filter) {
-        DEBUG(SSSDBG_MINOR_FAILURE,
-              ("Failed to build base filter\n"));
-        ret = ENOMEM;
-        goto fail;
-    }
-
-    if (ctx->srv_opts && ctx->srv_opts->max_group_value && !purge) {
-        state->filter = talloc_asprintf_append_buffer(
-                state->filter,
-                "(%s>=%s)(!(%s=%s))",
-                ctx->opts->group_map[SDAP_AT_GROUP_USN].name,
-                ctx->srv_opts->max_group_value,
-                ctx->opts->group_map[SDAP_AT_GROUP_USN].name,
-                ctx->srv_opts->max_group_value);
-        if (!state->filter) {
-            DEBUG(SSSDBG_MINOR_FAILURE,
-                  ("Failed to build base filter\n"));
-            ret = ENOMEM;
-            goto fail;
-        }
-    }
-
-    /* Terminate the search filter */
-    state->filter = talloc_asprintf_append_buffer(state->filter, ")");
-    if (!state->filter) {
-        DEBUG(SSSDBG_MINOR_FAILURE,
-              ("Failed to build base filter\n"));
-        ret = ENOMEM;
-        goto fail;
-    }
-
-    /* TODO: handle attrs_type */
-    ret = build_attrs_from_map(state, ctx->opts->group_map, SDAP_OPTS_GROUP,
-                               NULL, &state->attrs, NULL);
-    if (ret != EOK) goto fail;
-
-    /* TODO: restrict the enumerations to using a single
-     * search base at a time.
-     */
-
-    subreq = sdap_get_groups_send(state, state->ev,
-                                  state->sdom,
-                                  state->ctx->opts,
-                                  sdap_id_op_handle(state->op),
-                                  state->attrs, state->filter,
-                                  dp_opt_get_int(state->ctx->opts->basic,
-                                                 SDAP_ENUM_SEARCH_TIMEOUT),
-                                  true);
-    if (!subreq) {
-        ret = ENOMEM;
-        goto fail;
-    }
-    tevent_req_set_callback(subreq, enum_groups_op_done, req);
-
-    return req;
-
-fail:
-    tevent_req_error(req, ret);
-    tevent_req_post(req, ev);
-    return req;
-}
-
-static void enum_groups_op_done(struct tevent_req *subreq)
-{
-    struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                      struct tevent_req);
-    struct enum_groups_state *state = tevent_req_data(req,
-                                                 struct enum_groups_state);
-    char *usn_value;
-    char *endptr = NULL;
-    unsigned usn_number;
-    int ret;
-
-    ret = sdap_get_groups_recv(subreq, state, &usn_value);
-    talloc_zfree(subreq);
-    if (ret) {
-        tevent_req_error(req, ret);
-        return;
-    }
-
-    if (usn_value) {
-        talloc_zfree(state->ctx->srv_opts->max_group_value);
-        state->ctx->srv_opts->max_group_value =
-                                        talloc_steal(state->ctx, usn_value);
-        usn_number = strtoul(usn_value, &endptr, 10);
-        if ((endptr == NULL || (*endptr == '\0' && endptr != usn_value))
-            && (usn_number > state->ctx->srv_opts->last_usn)) {
-            state->ctx->srv_opts->last_usn = usn_number;
-        }
-    }
-
-    DEBUG(4, ("Groups higher USN value: [%s]\n",
-              state->ctx->srv_opts->max_group_value));
-
-    tevent_req_done(req);
-}
-
-static errno_t enum_groups_recv(struct tevent_req *req)
-{
-    TEVENT_REQ_RETURN_ON_ERROR(req);
-
-    return EOK;
-}
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index 6d24982b7759f7d4679d1be3030d0de0a3b9a607..f5f6d90aa075b5e7cffa4445cda87b1757dd3ca3 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -383,6 +383,9 @@ struct sdap_domain {
     struct sdap_domain *next, *prev;
     /* Need to modify the list from a talloc destructor */
     struct sdap_domain **head;
+
+    /* enumeration loop timer */
+    struct timeval last_enum;
 };
 
 struct sdap_options {
diff --git a/src/providers/ldap/ldap_id_enum.c b/src/providers/ldap/sdap_async_enum.c
similarity index 64%
copy from src/providers/ldap/ldap_id_enum.c
copy to src/providers/ldap/sdap_async_enum.c
index 7d9ff3be2e01af79ba7c1969464dcc96860122b9..ab6ae0773141157743977aba36a9115ce02be3cb 100644
--- a/src/providers/ldap/ldap_id_enum.c
+++ b/src/providers/ldap/sdap_async_enum.c
@@ -1,12 +1,13 @@
 /*
     SSSD
 
-    LDAP Identity Enumeration
+    LDAP Enumeration Module
 
     Authors:
         Simo Sorce <ssorce at redhat.com>
+        Jakub Hrozek <jhrozek at redhat.com>
 
-    Copyright (C) 2009 Red Hat
+    Copyright (C) 2013 Red Hat
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -23,8 +24,6 @@
 */
 
 #include <errno.h>
-#include <time.h>
-#include <sys/time.h>
 
 #include "util/util.h"
 #include "db/sysdb.h"
@@ -36,154 +35,6 @@ extern struct tevent_req *ldap_id_cleanup_send(TALLOC_CTX *memctx,
                                                struct tevent_context *ev,
                                                struct sdap_id_ctx *ctx);
 
-/* ==Enumeration-Task===================================================== */
-
-static int ldap_id_enumerate_retry(struct tevent_req *req);
-static void ldap_id_enumerate_connect_done(struct tevent_req *req);
-
-static void ldap_id_enumerate_reschedule(struct tevent_req *req);
-
-static void ldap_id_enumerate_timeout(struct tevent_context *ev,
-                                      struct tevent_timer *te,
-                                      struct timeval tv, void *pvt);
-
-static void ldap_id_enumerate_timer(struct tevent_context *ev,
-                                    struct tevent_timer *tt,
-                                    struct timeval tv, void *pvt)
-{
-    struct sdap_id_ctx *ctx = talloc_get_type(pvt, struct sdap_id_ctx);
-    struct tevent_timer *timeout;
-    struct tevent_req *req;
-    int delay;
-    errno_t ret;
-
-    if (be_is_offline(ctx->be)) {
-        DEBUG(4, ("Backend is marked offline, retry later!\n"));
-        /* schedule starting from now, not the last run */
-        delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
-        tv = tevent_timeval_current_ofs(delay, 0);
-        ldap_id_enumerate_set_timer(ctx, tv);
-        return;
-    }
-
-    req = ldap_id_enumerate_send(ev, ctx);
-    if (!req) {
-        DEBUG(1, ("Failed to schedule enumeration, retrying later!\n"));
-        /* schedule starting from now, not the last run */
-        delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
-        tv = tevent_timeval_current_ofs(delay, 0);
-        ret = ldap_id_enumerate_set_timer(ctx, tv);
-        if (ret != EOK) {
-            DEBUG(1, ("Error setting up enumerate timer\n"));
-        }
-        return;
-    }
-    tevent_req_set_callback(req, ldap_id_enumerate_reschedule, ctx);
-
-    /* if enumeration takes so long, either we try to enumerate too
-     * frequently, or something went seriously wrong */
-    delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
-    tv = tevent_timeval_current_ofs(delay, 0);
-    timeout = tevent_add_timer(ctx->be->ev, req, tv,
-                               ldap_id_enumerate_timeout, req);
-    if (timeout == NULL) {
-        /* If we can't guarantee a timeout, we
-         * need to cancel the request, to avoid
-         * the possibility of starting another
-         * concurrently
-         */
-        talloc_zfree(req);
-
-        DEBUG(1, ("Failed to schedule enumeration, retrying later!\n"));
-        /* schedule starting from now, not the last run */
-        delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
-        tv = tevent_timeval_current_ofs(delay, 0);
-        ret = ldap_id_enumerate_set_timer(ctx, tv);
-        if (ret != EOK) {
-            DEBUG(1, ("Error setting up enumerate timer\n"));
-        }
-        return;
-    }
-    return;
-}
-
-static void ldap_id_enumerate_timeout(struct tevent_context *ev,
-                                      struct tevent_timer *te,
-                                      struct timeval tv, void *pvt)
-{
-    struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
-    struct sdap_id_ctx *ctx = tevent_req_callback_data(req,
-                                                       struct sdap_id_ctx);
-    int delay;
-
-    delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
-    DEBUG(1, ("Enumeration timed out! Timeout too small? (%ds)!\n", delay));
-
-    tv = tevent_timeval_current_ofs(delay, 0);
-    ldap_id_enumerate_set_timer(ctx, tv);
-
-    talloc_zfree(req);
-}
-
-static void ldap_id_enumerate_reschedule(struct tevent_req *req)
-{
-    struct sdap_id_ctx *ctx = tevent_req_callback_data(req,
-                                                       struct sdap_id_ctx);
-    enum tevent_req_state tstate;
-    uint64_t err;
-    struct timeval tv;
-    int delay;
-    errno_t ret;
-
-    if (tevent_req_is_error(req, &tstate, &err)) {
-        /* On error schedule starting from now, not the last run */
-        tv = tevent_timeval_current();
-    } else {
-        tv = ctx->last_enum;
-
-        /* Ok, we've completed an enumeration. Save this to the
-         * sysdb so we can postpone starting up the enumeration
-         * process on the next SSSD service restart (to avoid
-         * slowing down system boot-up
-         */
-        ret = sysdb_set_enumerated(ctx->be->domain->sysdb, ctx->be->domain, true);
-        if (ret != EOK) {
-            DEBUG(1, ("Could not mark domain as having enumerated.\n"));
-            /* This error is non-fatal, so continue */
-        }
-    }
-    talloc_zfree(req);
-
-    delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
-    tv = tevent_timeval_add(&tv, delay, 0);
-    ldap_id_enumerate_set_timer(ctx, tv);
-}
-
-int ldap_id_enumerate_set_timer(struct sdap_id_ctx *ctx, struct timeval tv)
-{
-    struct tevent_timer *enum_task;
-
-    DEBUG(6, ("Scheduling next enumeration at %ld.%ld\n",
-              (long)tv.tv_sec, (long)tv.tv_usec));
-
-    enum_task = tevent_add_timer(ctx->be->ev, ctx,
-                                 tv, ldap_id_enumerate_timer, ctx);
-    if (!enum_task) {
-        DEBUG(0, ("FATAL: failed to setup enumeration task!\n"));
-        return EFAULT;
-    }
-
-    return EOK;
-}
-
-struct global_enum_state {
-    struct tevent_context *ev;
-    struct sdap_id_ctx *ctx;
-    struct sdap_id_op *op;
-
-    bool purge;
-};
-
 static struct tevent_req *enum_users_send(TALLOC_CTX *memctx,
                                           struct tevent_context *ev,
                                           struct sdap_id_ctx *ctx,
@@ -191,7 +42,7 @@ static struct tevent_req *enum_users_send(TALLOC_CTX *memctx,
                                           struct sdap_id_op *op,
                                           bool purge);
 static errno_t enum_users_recv(struct tevent_req *req);
-static void ldap_id_enum_users_done(struct tevent_req *subreq);
+
 static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
                                           struct tevent_context *ev,
                                           struct sdap_id_ctx *ctx,
@@ -199,103 +50,130 @@ static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
                                           struct sdap_id_op *op,
                                           bool purge);
 static errno_t enum_groups_recv(struct tevent_req *req);
-static void ldap_id_enum_groups_done(struct tevent_req *subreq);
-static void ldap_id_enum_services_done(struct tevent_req *subreq);
-static void ldap_id_enum_cleanup_done(struct tevent_req *subreq);
 
-struct tevent_req *ldap_id_enumerate_send(struct tevent_context *ev,
-                                          struct sdap_id_ctx *ctx)
+/* ==Enumeration-Request==================================================== */
+struct sdap_dom_enum_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;
+
+    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 void sdap_dom_enum_cleanup_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)
 {
-    struct global_enum_state *state;
     struct tevent_req *req;
+    struct sdap_dom_enum_state *state;
     int t;
+    errno_t ret;
 
-    req = tevent_req_create(ctx, &state, struct global_enum_state);
+    req = tevent_req_create(ctx, &state, struct sdap_dom_enum_state);
     if (!req) 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(2, ("sdap_id_op_create failed\n"));
-        talloc_zfree(req);
-        return NULL;
+        DEBUG(SSSDBG_CRIT_FAILURE, ("sdap_id_op_create failed\n"));
+        ret = EIO;
+        goto fail;
     }
 
-    ctx->last_enum = tevent_timeval_current();
+    sdom->last_enum = tevent_timeval_current();
 
     t = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT);
-    if ((ctx->last_purge.tv_sec + t) < ctx->last_enum.tv_sec) {
+    if ((ctx->last_purge.tv_sec + t) < sdom->last_enum.tv_sec) {
         state->purge = true;
-    } else {
-        state->purge = false;
     }
 
-    int ret = ldap_id_enumerate_retry(req);
+    ret = sdap_dom_enum_retry(req);
     if (ret != EOK) {
-        DEBUG(2, ("ldap_id_enumerate_retry failed\n"));
-        talloc_zfree(req);
-        return NULL;
+        DEBUG(SSSDBG_OP_FAILURE, ("ldap_id_enumerate_retry failed\n"));
+        goto fail;
     }
 
     return req;
+
+fail:
+    tevent_req_error(req, ret);
+    tevent_req_post(req, ev);
+    return req;
 }
 
-static int ldap_id_enumerate_retry(struct tevent_req *req)
+static errno_t sdap_dom_enum_retry(struct tevent_req *req)
 {
-    struct global_enum_state *state = tevent_req_data(req,
-                                                      struct global_enum_state);
+    struct sdap_dom_enum_state *state = tevent_req_data(req,
+                                                   struct sdap_dom_enum_state);
     struct tevent_req *subreq;
-    int ret;
+    errno_t ret;
 
     subreq = sdap_id_op_connect_send(state->op, state, &ret);
-    if (!subreq) {
+    if (subreq == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE,
+              ("sdap_id_op_connect_send failed: %d\n", ret));
         return ret;
     }
 
-    tevent_req_set_callback(subreq, ldap_id_enumerate_connect_done, req);
+    tevent_req_set_callback(subreq, sdap_dom_enum_conn_done, req);
     return EOK;
 }
 
-static void ldap_id_enumerate_connect_done(struct tevent_req *subreq)
+static void sdap_dom_enum_conn_done(struct tevent_req *subreq)
 {
     struct tevent_req *req = tevent_req_callback_data(subreq,
                                                       struct tevent_req);
-    struct global_enum_state *state = tevent_req_data(req,
-                                                 struct global_enum_state);
+    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);
     if (ret != EOK) {
         if (dp_error == DP_ERR_OFFLINE) {
+            DEBUG(SSSDBG_TRACE_FUNC,
+                  ("Backend is marked offline, retry later!\n"));
             tevent_req_done(req);
         } else {
-            DEBUG(9, ("User enumeration failed to connect to LDAP server: (%d)[%s]\n",
-                      ret, strerror(ret)));
+            DEBUG(SSSDBG_MINOR_FAILURE,
+                  ("Domain enumeration failed to connect to " \
+                   "LDAP server: (%d)[%s]\n", ret, strerror(ret)));
             tevent_req_error(req, ret);
         }
-
         return;
     }
 
     subreq = enum_users_send(state, state->ev,
-                             state->ctx, state->ctx->opts->sdom,
+                             state->ctx, state->sdom,
                              state->op, state->purge);
-    if(!subreq) {
+    if (subreq == NULL) {
         tevent_req_error(req, ENOMEM);
         return;
     }
-
-    tevent_req_set_callback(subreq, ldap_id_enum_users_done, req);
+    tevent_req_set_callback(subreq, sdap_dom_enum_users_done, req);
 }
 
-static void ldap_id_enum_users_done(struct tevent_req *subreq)
+static void sdap_dom_enum_users_done(struct tevent_req *subreq)
 {
     struct tevent_req *req = tevent_req_callback_data(subreq,
                                                       struct tevent_req);
-    struct global_enum_state *state = tevent_req_data(req,
-                                                 struct global_enum_state);
+    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;
 
@@ -307,7 +185,7 @@ static void ldap_id_enum_users_done(struct tevent_req *subreq)
         ret = sdap_id_op_done(state->op, (int)err, &dp_error);
         if (dp_error == DP_ERR_OK) {
             /* retry */
-            ret = ldap_id_enumerate_retry(req);
+            ret = sdap_dom_enum_retry(req);
             if (ret == EOK) {
                 return;
             }
@@ -318,29 +196,30 @@ static void ldap_id_enum_users_done(struct tevent_req *subreq)
         if (dp_error == DP_ERR_OFFLINE) {
             tevent_req_done(req);
         } else {
-            DEBUG(9, ("User enumeration failed with: (%d)[%s]\n",
-                      ret, strerror(ret)));
+            DEBUG(SSSDBG_OP_FAILURE,
+                  ("User enumeration failed with: (%d)[%s]\n",
+                   ret, strerror(ret)));
             tevent_req_error(req, ret);
         }
         return;
     }
 
     subreq = enum_groups_send(state, state->ev, state->ctx,
-                              state->ctx->opts->sdom,
+                              state->sdom,
                               state->op, state->purge);
-    if (!subreq) {
+    if (subreq == NULL) {
         tevent_req_error(req, ENOMEM);
         return;
     }
-    tevent_req_set_callback(subreq, ldap_id_enum_groups_done, req);
+    tevent_req_set_callback(subreq, sdap_dom_enum_groups_done, req);
 }
 
-static void ldap_id_enum_groups_done(struct tevent_req *subreq)
+static void sdap_dom_enum_groups_done(struct tevent_req *subreq)
 {
     struct tevent_req *req = tevent_req_callback_data(subreq,
                                                       struct tevent_req);
-    struct global_enum_state *state = tevent_req_data(req,
-                                                 struct global_enum_state);
+    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;
 
@@ -352,7 +231,7 @@ static void ldap_id_enum_groups_done(struct tevent_req *subreq)
         ret = sdap_id_op_done(state->op, (int)err, &dp_error);
         if (dp_error == DP_ERR_OK && ret != EOK) {
             /* retry */
-            ret = ldap_id_enumerate_retry(req);
+            ret = sdap_dom_enum_retry(req);
             if (ret == EOK) {
                 return;
             }
@@ -364,8 +243,9 @@ static void ldap_id_enum_groups_done(struct tevent_req *subreq)
             if (dp_error == DP_ERR_OFFLINE) {
                 tevent_req_done(req);
             } else {
-                DEBUG(9, ("Group enumeration failed with: (%d)[%s]\n",
-                          ret, strerror(ret)));
+                DEBUG(SSSDBG_OP_FAILURE,
+                      ("Group enumeration failed with: (%d)[%s]\n",
+                       ret, strerror(ret)));
                 tevent_req_error(req, ret);
             }
 
@@ -379,17 +259,17 @@ static void ldap_id_enum_groups_done(struct tevent_req *subreq)
         tevent_req_error(req, ENOMEM);
         return;
     }
-    tevent_req_set_callback(subreq, ldap_id_enum_services_done, req);
+    tevent_req_set_callback(subreq, sdap_dom_enum_services_done, req);
 }
 
-static void ldap_id_enum_services_done(struct tevent_req *subreq)
+static void sdap_dom_enum_services_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 global_enum_state *state = tevent_req_data(req,
-                                                 struct global_enum_state);
+    struct sdap_dom_enum_state *state = tevent_req_data(req,
+                                                   struct sdap_dom_enum_state);
 
     ret = enum_services_recv(subreq);
     talloc_zfree(subreq);
@@ -401,7 +281,7 @@ static void ldap_id_enum_services_done(struct tevent_req *subreq)
     ret = sdap_id_op_done(state->op, ret, &dp_error);
     if (dp_error == DP_ERR_OK && ret != EOK) {
         /* retry */
-        ret = ldap_id_enumerate_retry(req);
+        ret = sdap_dom_enum_retry(req);
         if (ret == EOK) {
             return;
         }
@@ -422,22 +302,34 @@ static void ldap_id_enum_services_done(struct tevent_req *subreq)
         return;
     }
 
+    /* Ok, we've completed an enumeration. Save this to the
+     * sysdb so we can postpone starting up the enumeration
+     * process on the next SSSD service restart (to avoid
+     * slowing down system boot-up
+     */
+    ret = sysdb_set_enumerated(state->sdom->dom->sysdb,
+                               state->sdom->dom, true);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_MINOR_FAILURE,
+              ("Could not mark domain as having enumerated.\n"));
+        /* This error is non-fatal, so continue */
+    }
+
     if (state->purge) {
-
         subreq = ldap_id_cleanup_send(state, state->ev, state->ctx);
         if (!subreq) {
             tevent_req_error(req, ENOMEM);
             return;
         }
 
-        tevent_req_set_callback(subreq, ldap_id_enum_cleanup_done, req);
+        tevent_req_set_callback(subreq, sdap_dom_enum_cleanup_done, req);
         return;
     }
 
     tevent_req_done(req);
 }
 
-static void ldap_id_enum_cleanup_done(struct tevent_req *subreq)
+static void sdap_dom_enum_cleanup_done(struct tevent_req *subreq)
 {
     struct tevent_req *req = tevent_req_callback_data(subreq,
                                                       struct tevent_req);
@@ -445,8 +337,14 @@ static void ldap_id_enum_cleanup_done(struct tevent_req *subreq)
     tevent_req_done(req);
 }
 
+errno_t sdap_dom_enum_recv(struct tevent_req *req)
+{
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    return EOK;
+}
+
 /* ==User-Enumeration===================================================== */
-
 struct enum_users_state {
     struct tevent_context *ev;
     struct sdap_id_ctx *ctx;
@@ -457,7 +355,7 @@ struct enum_users_state {
     const char **attrs;
 };
 
-static void enum_users_op_done(struct tevent_req *subreq);
+static void enum_users_done(struct tevent_req *subreq);
 
 static struct tevent_req *enum_users_send(TALLOC_CTX *memctx,
                                           struct tevent_context *ev,
@@ -480,14 +378,14 @@ static struct tevent_req *enum_users_send(TALLOC_CTX *memctx,
     state->op = op;
 
     use_mapping = sdap_idmap_domain_has_algorithmic_mapping(
-                                                          ctx->opts->idmap_ctx,
-                                                          sdom->dom->domain_id);
+                                                        ctx->opts->idmap_ctx,
+                                                        sdom->dom->domain_id);
 
     /* We always want to filter on objectclass and an available name */
     state->filter = talloc_asprintf(state,
-                                    "(&(objectclass=%s)(%s=*)",
-                                    ctx->opts->user_map[SDAP_OC_USER].name,
-                                    ctx->opts->user_map[SDAP_AT_USER_NAME].name);
+                                  "(&(objectclass=%s)(%s=*)",
+                                  ctx->opts->user_map[SDAP_OC_USER].name,
+                                  ctx->opts->user_map[SDAP_AT_USER_NAME].name);
     if (!state->filter) {
         DEBUG(SSSDBG_MINOR_FAILURE,
               ("Failed to build base filter\n"));
@@ -567,7 +465,7 @@ static struct tevent_req *enum_users_send(TALLOC_CTX *memctx,
         ret = ENOMEM;
         goto fail;
     }
-    tevent_req_set_callback(subreq, enum_users_op_done, req);
+    tevent_req_set_callback(subreq, enum_users_done, req);
 
     return req;
 
@@ -577,7 +475,7 @@ fail:
     return req;
 }
 
-static void enum_users_op_done(struct tevent_req *subreq)
+static void enum_users_done(struct tevent_req *subreq)
 {
     struct tevent_req *req = tevent_req_callback_data(subreq,
                                                       struct tevent_req);
@@ -597,7 +495,8 @@ static void enum_users_op_done(struct tevent_req *subreq)
 
     if (usn_value) {
         talloc_zfree(state->ctx->srv_opts->max_user_value);
-        state->ctx->srv_opts->max_user_value = talloc_steal(state->ctx, usn_value);
+        state->ctx->srv_opts->max_user_value =
+                                        talloc_steal(state->ctx, usn_value);
 
         usn_number = strtoul(usn_value, &endptr, 10);
         if ((endptr == NULL || (*endptr == '\0' && endptr != usn_value))
@@ -620,7 +519,6 @@ static errno_t enum_users_recv(struct tevent_req *req)
 }
 
 /* =Group-Enumeration===================================================== */
-
 struct enum_groups_state {
     struct tevent_context *ev;
     struct sdap_id_ctx *ctx;
@@ -631,7 +529,7 @@ struct enum_groups_state {
     const char **attrs;
 };
 
-static void enum_groups_op_done(struct tevent_req *subreq);
+static void enum_groups_done(struct tevent_req *subreq);
 
 static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
                                           struct tevent_context *ev,
@@ -654,14 +552,14 @@ static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
     state->op = op;
 
     use_mapping = sdap_idmap_domain_has_algorithmic_mapping(
-                                                          ctx->opts->idmap_ctx,
-                                                          sdom->dom->domain_id);
+                                                        ctx->opts->idmap_ctx,
+                                                        sdom->dom->domain_id);
 
     /* We always want to filter on objectclass and an available name */
     state->filter = talloc_asprintf(state,
-                                    "(&(objectclass=%s)(%s=*)",
-                                    ctx->opts->group_map[SDAP_OC_GROUP].name,
-                                    ctx->opts->group_map[SDAP_AT_GROUP_NAME].name);
+                               "(&(objectclass=%s)(%s=*)",
+                               ctx->opts->group_map[SDAP_OC_GROUP].name,
+                               ctx->opts->group_map[SDAP_AT_GROUP_NAME].name);
     if (!state->filter) {
         DEBUG(SSSDBG_MINOR_FAILURE,
               ("Failed to build base filter\n"));
@@ -736,7 +634,7 @@ static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
         ret = ENOMEM;
         goto fail;
     }
-    tevent_req_set_callback(subreq, enum_groups_op_done, req);
+    tevent_req_set_callback(subreq, enum_groups_done, req);
 
     return req;
 
@@ -746,7 +644,7 @@ fail:
     return req;
 }
 
-static void enum_groups_op_done(struct tevent_req *subreq)
+static void enum_groups_done(struct tevent_req *subreq)
 {
     struct tevent_req *req = tevent_req_callback_data(subreq,
                                                       struct tevent_req);
diff --git a/src/providers/ldap/sdap_async_enum.h b/src/providers/ldap/sdap_async_enum.h
new file mode 100644
index 0000000000000000000000000000000000000000..04ec8c6dcbec4bcce0de67b9e10acc857c9e9416
--- /dev/null
+++ b/src/providers/ldap/sdap_async_enum.h
@@ -0,0 +1,38 @@
+/*
+    SSSD
+
+    LDAP Enumeration Module
+
+    Authors:
+        Simo Sorce <ssorce at redhat.com>
+        Jakub Hrozek <jhrozek at redhat.com>
+
+    Copyright (C) 2013 Red Hat
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SDAP_ASYNC_ENUM_H_
+#define _SDAP_ASYNC_ENUM_H_
+
+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);
+
+errno_t sdap_dom_enum_recv(struct tevent_req *req);
+
+#endif /* _SDAP_ASYNC_ENUM_H_ */
diff --git a/src/providers/ldap/sdap_reinit.c b/src/providers/ldap/sdap_reinit.c
index b273c1a66cca5e78ab3c281c684feab93f476471..d7b50bbbd61b98abd6a7c50d237544df32a991c3 100644
--- a/src/providers/ldap/sdap_reinit.c
+++ b/src/providers/ldap/sdap_reinit.c
@@ -25,6 +25,7 @@
 
 #include "util/util.h"
 #include "providers/ldap/ldap_common.h"
+#include "providers/ldap/sdap_async_enum.h"
 #include "db/sysdb.h"
 #include "db/sysdb_services.h"
 
@@ -79,7 +80,8 @@ struct tevent_req* sdap_reinit_cleanup_send(TALLOC_CTX *mem_ctx,
         goto immediately;
     }
 
-    subreq = ldap_id_enumerate_send(be_ctx->ev, id_ctx);
+    subreq = sdap_dom_enum_send(id_ctx, be_ctx->ev, id_ctx,
+                                id_ctx->opts->sdom, id_ctx->conn);
     if (subreq == NULL) {
         DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to issue enumeration request\n"));
         ret = ENOMEM;
@@ -199,17 +201,16 @@ static void sdap_reinit_cleanup_done(struct tevent_req *subreq)
 {
     struct tevent_req *req = NULL;
     struct sdap_reinit_cleanup_state *state = NULL;
-    enum tevent_req_state tstate;
-    uint64_t err;
     errno_t ret;
 
     req = tevent_req_callback_data(subreq, struct tevent_req);
     state = tevent_req_data(req, struct sdap_reinit_cleanup_state);
 
-    if (tevent_req_is_error(subreq, &tstate, &err)) {
-        ret = err;
+    ret = sdap_dom_enum_recv(subreq);
+    talloc_zfree(subreq);
+    if (ret != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE, ("Domain enumeration failed [%d]: %s\n",
-                                    err, strerror(err)));
+                                    ret, strerror(ret)));
         goto fail;
     }
 
-- 
1.8.3.1

-------------- next part --------------
>From 696f0cc005d70329c6727a5c13610f77d6d45c88 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Wed, 21 Aug 2013 01:41:16 +0200
Subject: [PATCH 04/12] LDAP: Convert enumeration to the ptask API

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

Identity providers other than LDAP need to customize the enumeration in
different ways while sharing the way the task is scheduled etc. The
easiest way to accomplish it is to leverage the recently introduced
ptask framework.
---
 src/providers/ldap/ldap_common.c  |  30 +----
 src/providers/ldap/ldap_common.h  |   4 +-
 src/providers/ldap/ldap_id_enum.c | 255 ++++++++++++++++++++------------------
 src/providers/ldap/sdap.h         |   1 +
 4 files changed, 143 insertions(+), 147 deletions(-)

diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
index 9aa98173c865d0b032f02bd6a0ec80b93682af6d..05e487a1e8f57da338c9949b9f1a75688a6595e7 100644
--- a/src/providers/ldap/ldap_common.c
+++ b/src/providers/ldap/ldap_common.c
@@ -941,37 +941,11 @@ int sdap_id_setup_tasks(struct sdap_id_ctx *ctx)
     struct timeval tv;
     int ret = EOK;
     int delay;
-    bool has_enumerated;
 
     /* set up enumeration task */
     if (ctx->be->domain->enumerate) {
-        /* If this is the first startup, we need to kick off
-         * an enumeration immediately, to close a window where
-         * clients requesting get*ent information won't get an
-         * immediate reply with no entries
-         */
-        ret = sysdb_has_enumerated(ctx->be->domain->sysdb, ctx->be->domain,
-                                   &has_enumerated);
-        if (ret != EOK) {
-            return ret;
-        }
-        if (has_enumerated) {
-            /* At least one enumeration has previously run,
-             * so clients will get cached data. We will delay
-             * starting to enumerate by 10s so we don't slow
-             * down the startup process if this is happening
-             * during system boot.
-             */
-            tv = tevent_timeval_current_ofs(10, 0);
-        } else {
-            /* This is our first startup. Schedule the
-             * enumeration to start immediately once we
-             * enter the mainloop.
-             */
-            tv = tevent_timeval_current();
-        }
-
-        ret = ldap_id_enumerate_set_timer(ctx, tv);
+        DEBUG(SSSDBG_TRACE_FUNC, ("Setting up enumeration for %s\n", ctx->be->domain->name));
+        ret = ldap_setup_enumeration(ctx, ctx->conn, ctx->opts->sdom);
     } 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 c9b2f663b72658c9cdcd4d54ec32b1dd74f31326..7ba8e95571854dfbb2e1eb4faf24c992f41b68f4 100644
--- a/src/providers/ldap/ldap_common.h
+++ b/src/providers/ldap/ldap_common.h
@@ -165,7 +165,9 @@ int ldap_get_autofs_options(TALLOC_CTX *memctx,
                             const char *conf_path,
                             struct sdap_options *opts);
 
-int ldap_id_enumerate_set_timer(struct sdap_id_ctx *ctx, struct timeval tv);
+errno_t ldap_setup_enumeration(struct sdap_id_ctx *ctx,
+                               struct sdap_id_conn_ctx *conn,
+                               struct sdap_domain *sdom);
 int ldap_id_cleanup_set_timer(struct sdap_id_ctx *ctx, struct timeval tv);
 
 void sdap_mark_offline(struct sdap_id_ctx *ctx);
diff --git a/src/providers/ldap/ldap_id_enum.c b/src/providers/ldap/ldap_id_enum.c
index 43eb4c9972bb7383435e2e130f01646af46c0c38..961c72f3d888fa92d1002ca483776319d007b679 100644
--- a/src/providers/ldap/ldap_id_enum.c
+++ b/src/providers/ldap/ldap_id_enum.c
@@ -22,143 +22,162 @@
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-#include <errno.h>
-#include <time.h>
-#include <sys/time.h>
-
 #include "util/util.h"
 #include "db/sysdb.h"
 #include "providers/ldap/ldap_common.h"
-#include "providers/ldap/sdap_async.h"
-#include "providers/ldap/sdap_idmap.h"
 #include "providers/ldap/sdap_async_enum.h"
 
-extern struct tevent_req *ldap_id_cleanup_send(TALLOC_CTX *memctx,
-                                               struct tevent_context *ev,
-                                               struct sdap_id_ctx *ctx);
-
-/* ==Enumeration-Task===================================================== */
-
-static void ldap_id_enumerate_reschedule(struct tevent_req *req);
-
-static void ldap_id_enumerate_timeout(struct tevent_context *ev,
-                                      struct tevent_timer *te,
-                                      struct timeval tv, void *pvt);
-
-static void ldap_id_enumerate_timer(struct tevent_context *ev,
-                                    struct tevent_timer *tt,
-                                    struct timeval tv, void *pvt)
-{
-    struct sdap_id_ctx *ctx = talloc_get_type(pvt, struct sdap_id_ctx);
-    struct tevent_timer *timeout;
-    struct tevent_req *req;
-    int delay;
-    errno_t ret;
-
-    if (be_is_offline(ctx->be)) {
-        DEBUG(4, ("Backend is marked offline, retry later!\n"));
-        /* schedule starting from now, not the last run */
-        delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
-        tv = tevent_timeval_current_ofs(delay, 0);
-        ldap_id_enumerate_set_timer(ctx, tv);
-        return;
-    }
-
-    req = sdap_dom_enum_send(ctx, ev, ctx, ctx->opts->sdom, ctx->conn);
-    if (!req) {
-        DEBUG(1, ("Failed to schedule enumeration, retrying later!\n"));
-        /* schedule starting from now, not the last run */
-        delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
-        tv = tevent_timeval_current_ofs(delay, 0);
-        ret = ldap_id_enumerate_set_timer(ctx, tv);
-        if (ret != EOK) {
-            DEBUG(1, ("Error setting up enumerate timer\n"));
-        }
-        return;
-    }
-    tevent_req_set_callback(req, ldap_id_enumerate_reschedule, ctx);
-
-    /* if enumeration takes so long, either we try to enumerate too
-     * frequently, or something went seriously wrong */
-    delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
-    tv = tevent_timeval_current_ofs(delay, 0);
-    timeout = tevent_add_timer(ctx->be->ev, req, tv,
-                               ldap_id_enumerate_timeout, req);
-    if (timeout == NULL) {
-        /* If we can't guarantee a timeout, we
-         * need to cancel the request, to avoid
-         * the possibility of starting another
-         * concurrently
-         */
-        talloc_zfree(req);
-
-        DEBUG(1, ("Failed to schedule enumeration, retrying later!\n"));
-        /* schedule starting from now, not the last run */
-        delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
-        tv = tevent_timeval_current_ofs(delay, 0);
-        ret = ldap_id_enumerate_set_timer(ctx, tv);
-        if (ret != EOK) {
-            DEBUG(1, ("Error setting up enumerate timer\n"));
-        }
-        return;
-    }
-    return;
-}
-
-static void ldap_id_enumerate_timeout(struct tevent_context *ev,
-                                      struct tevent_timer *te,
-                                      struct timeval tv, void *pvt)
-{
-    struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
-    struct sdap_id_ctx *ctx = tevent_req_callback_data(req,
-                                                       struct sdap_id_ctx);
-    int delay;
-
-    delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
-    DEBUG(1, ("Enumeration timed out! Timeout too small? (%ds)!\n", delay));
-
-    tv = tevent_timeval_current_ofs(delay, 0);
-    ldap_id_enumerate_set_timer(ctx, tv);
-
-    talloc_zfree(req);
-}
-
-static void ldap_id_enumerate_reschedule(struct tevent_req *req)
+static struct tevent_req *
+ldap_enumeration_send(TALLOC_CTX *mem_ctx,
+                      struct tevent_context *ev,
+                      struct be_ctx *be_ctx,
+                      struct be_ptask *be_ptask,
+                      void *pvt);
+errno_t ldap_enumeration_recv(struct tevent_req *req);
+
+struct ldap_enum_ctx {
+    struct sdap_id_ctx *ctx;
+    struct sdap_domain *sdom;
+    struct sdap_id_conn_ctx *conn;
+};
+
+errno_t ldap_setup_enumeration(struct sdap_id_ctx *ctx,
+                               struct sdap_id_conn_ctx *conn,
+                               struct sdap_domain *sdom)
 {
-    struct sdap_id_ctx *ctx = tevent_req_callback_data(req,
-                                                       struct sdap_id_ctx);
-    struct timeval tv;
-    int delay;
     errno_t ret;
+    time_t first_delay;
+    time_t period;
+    bool has_enumerated;
+    struct ldap_enum_ctx *ectx;
 
-    ret = sdap_dom_enum_recv(req);
-    talloc_zfree(req);
+    ret = sysdb_has_enumerated(sdom->dom->sysdb, sdom->dom, &has_enumerated);
     if (ret != EOK) {
-        /* On error schedule starting from now, not the last run */
-        tv = tevent_timeval_current();
+        return ret;
+    }
+
+    if (has_enumerated) {
+        /* At least one enumeration has previously run,
+         * so clients will get cached data. We will delay
+         * starting to enumerate by 10s so we don't slow
+         * down the startup process if this is happening
+         * during system boot.
+         */
+        first_delay = 10;
     } else {
-        tv = ctx->opts->sdom->last_enum;
+        /* This is our first startup. Schedule the
+         * enumeration to start immediately once we
+         * enter the mainloop.
+         */
+        first_delay = 0;
+    }
+
+    period = dp_opt_get_int(ctx->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;
 
+    ret = be_ptask_create(sdom, ctx->be,
+                          period,                   /* period */
+                          first_delay,              /* first_delay */
+                          5,                        /* enabled delay */
+                          period,                   /* timeout */
+                          BE_PTASK_OFFLINE_SKIP,
+                          ldap_enumeration_send, ldap_enumeration_recv,
+                          ectx, "enumeration", &sdom->enum_task);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_FATAL_FAILURE,
+              ("Unable to initialize enumeration periodic task\n"));
+        talloc_free(ectx);
+        return ret;
     }
 
-    delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
-    tv = tevent_timeval_add(&tv, delay, 0);
-    ldap_id_enumerate_set_timer(ctx, tv);
+    talloc_steal(sdom->enum_task, ectx);
+    return EOK;
 }
 
-int ldap_id_enumerate_set_timer(struct sdap_id_ctx *ctx, struct timeval tv)
+
+struct ldap_enumeration_state {
+    struct ldap_enum_ctx *ectx;
+    struct sss_domain_info *dom;
+};
+
+static void ldap_enumeration_done(struct tevent_req *subreq);
+
+static struct tevent_req *
+ldap_enumeration_send(TALLOC_CTX *mem_ctx,
+                      struct tevent_context *ev,
+                      struct be_ctx *be_ctx,
+                      struct be_ptask *be_ptask,
+                      void *pvt)
 {
-    struct tevent_timer *enum_task;
+    struct ldap_enumeration_state *state;
+    struct tevent_req *req;
+    struct tevent_req *subreq;
+    struct ldap_enum_ctx *ectx;
+    errno_t ret;
+
+    req = tevent_req_create(mem_ctx, &state,
+                            struct ldap_enumeration_state);
+    if (req == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("tevent_req_create() failed\n"));
+        return NULL;
+    }
+
+    ectx = talloc_get_type(pvt, struct ldap_enum_ctx);
+    if (ectx == NULL) {
+        ret = EFAULT;
+        goto fail;
+    }
+    state->ectx = ectx;
+    state->dom = ectx->sdom->dom;
+
+    subreq = sdap_dom_enum_send(ectx, ev, ectx->ctx, ectx->sdom,
+                                ectx->conn);
+    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 = EIO;
+        goto fail;
+    }
 
-    DEBUG(6, ("Scheduling next enumeration at %ld.%ld\n",
-              (long)tv.tv_sec, (long)tv.tv_usec));
+    tevent_req_set_callback(subreq, ldap_enumeration_done, req);
+    return req;
 
-    enum_task = tevent_add_timer(ctx->be->ev, ctx,
-                                 tv, ldap_id_enumerate_timer, ctx);
-    if (!enum_task) {
-        DEBUG(0, ("FATAL: failed to setup enumeration task!\n"));
-        return EFAULT;
+fail:
+    tevent_req_error(req, ret);
+    tevent_req_post(req, ev);
+    return req;
+}
+
+static void
+ldap_enumeration_done(struct tevent_req *subreq)
+{
+    errno_t ret;
+    struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                      struct tevent_req);
+
+    ret = sdap_dom_enum_recv(subreq);
+    talloc_zfree(subreq);
+    if (ret != EOK) {
+        tevent_req_error(req, ret);
+        return;
     }
 
+    tevent_req_done(req);
+}
+
+errno_t
+ldap_enumeration_recv(struct tevent_req *req)
+{
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
     return EOK;
 }
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index f5f6d90aa075b5e7cffa4445cda87b1757dd3ca3..5da27fe87ff5900857ec89e6084ab4d766944327 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -384,6 +384,7 @@ struct sdap_domain {
     /* Need to modify the list from a talloc destructor */
     struct sdap_domain **head;
 
+    struct be_ptask *enum_task;
     /* enumeration loop timer */
     struct timeval last_enum;
 };
-- 
1.8.3.1

-------------- next part --------------
>From ed10a190a5705b9b2b095afd65758f177356de9d Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Wed, 21 Aug 2013 03:37:47 +0200
Subject: [PATCH 05/12] LDAP: Make cleanup synchronous

The LDAP cleanup request was asynchronous for no good reason, probably a
leftover from the days of async sysdb. This patch makes it sychronous
again, removing a lot of uneeded code.
---
 src/providers/ldap/ldap_common.h     |   1 +
 src/providers/ldap/ldap_id_cleanup.c | 157 ++++++-----------------------------
 src/providers/ldap/sdap_async_enum.c |  26 ++----
 3 files changed, 34 insertions(+), 150 deletions(-)

diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
index 7ba8e95571854dfbb2e1eb4faf24c992f41b68f4..1dd69f4e253f9bcf1162b8e0212eeac59ec621fe 100644
--- a/src/providers/ldap/ldap_common.h
+++ b/src/providers/ldap/ldap_common.h
@@ -168,6 +168,7 @@ int ldap_get_autofs_options(TALLOC_CTX *memctx,
 errno_t ldap_setup_enumeration(struct sdap_id_ctx *ctx,
                                struct sdap_id_conn_ctx *conn,
                                struct sdap_domain *sdom);
+errno_t ldap_id_cleanup(struct sdap_id_ctx *ctx);
 int ldap_id_cleanup_set_timer(struct sdap_id_ctx *ctx, struct timeval tv);
 
 void sdap_mark_offline(struct sdap_id_ctx *ctx);
diff --git a/src/providers/ldap/ldap_id_cleanup.c b/src/providers/ldap/ldap_id_cleanup.c
index 534e2ee015d157a26798c5b14fdd3e8d9a156b63..85c0139dbb9ff2d72b4e132b73b3bd4c8d56aab0 100644
--- a/src/providers/ldap/ldap_id_cleanup.c
+++ b/src/providers/ldap/ldap_id_cleanup.c
@@ -33,23 +33,11 @@
 #include "providers/ldap/sdap_async.h"
 
 /* ==Cleanup-Task========================================================= */
-
-struct tevent_req *ldap_id_cleanup_send(TALLOC_CTX *memctx,
-                                        struct tevent_context *ev,
-                                        struct sdap_id_ctx *ctx);
-static void ldap_id_cleanup_reschedule(struct tevent_req *req);
-
-static void ldap_id_cleanup_timeout(struct tevent_context *ev,
-                                      struct tevent_timer *te,
-                                      struct timeval tv, void *pvt);
-
 static void ldap_id_cleanup_timer(struct tevent_context *ev,
                                   struct tevent_timer *tt,
                                   struct timeval tv, void *pvt)
 {
     struct sdap_id_ctx *ctx = talloc_get_type(pvt, struct sdap_id_ctx);
-    struct tevent_timer *timeout;
-    struct tevent_req *req;
     int delay;
     errno_t ret;
 
@@ -62,89 +50,20 @@ static void ldap_id_cleanup_timer(struct tevent_context *ev,
         return;
     }
 
-    req = ldap_id_cleanup_send(ctx, ev, ctx);
-    if (!req) {
-        DEBUG(1, ("Failed to schedule cleanup, retrying later!\n"));
-        /* schedule starting from now, not the last run */
-        delay = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT);
-        tv = tevent_timeval_current_ofs(delay, 0);
-        ret = ldap_id_cleanup_set_timer(ctx, tv);
-        if (ret != EOK) {
-            DEBUG(1, ("Error setting up cleanup timer\n"));
-        }
-        return;
-    }
-    tevent_req_set_callback(req, ldap_id_cleanup_reschedule, ctx);
-
-    /* if cleanup takes so long, either we try to cleanup too
-     * frequently, or something went seriously wrong */
-    delay = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT);
-    tv = tevent_timeval_current_ofs(delay, 0);
-    timeout = tevent_add_timer(ctx->be->ev, req, tv,
-                               ldap_id_cleanup_timeout, req);
-    if (timeout == NULL) {
-        /* If we can't guarantee a timeout, we
-         * need to cancel the request, to avoid
-         * the possibility of starting another
-         * concurrently
-         */
-        talloc_zfree(req);
-
-        DEBUG(1, ("Failed to schedule cleanup, retrying later!\n"));
-        /* schedule starting from now, not the last run */
-        delay = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT);
-        tv = tevent_timeval_current_ofs(delay, 0);
-        ret = ldap_id_cleanup_set_timer(ctx, tv);
-        if (ret != EOK) {
-            DEBUG(1, ("Error setting up cleanup timer\n"));
-        }
-        return;
-    }
-    return;
-}
-
-static void ldap_id_cleanup_timeout(struct tevent_context *ev,
-                                      struct tevent_timer *te,
-                                      struct timeval tv, void *pvt)
-{
-    struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
-    struct sdap_id_ctx *ctx = tevent_req_callback_data(req,
-                                                       struct sdap_id_ctx);
-    int delay;
-
-    delay = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT);
-    DEBUG(1, ("Cleanup timed out! Timeout too small? (%ds)!\n", delay));
-
-    tv = tevent_timeval_current_ofs(delay, 0);
-    ldap_id_cleanup_set_timer(ctx, tv);
-
-    talloc_zfree(req);
-}
-
-static void ldap_id_cleanup_reschedule(struct tevent_req *req)
-{
-    struct sdap_id_ctx *ctx = tevent_req_callback_data(req,
-                                                       struct sdap_id_ctx);
-    enum tevent_req_state tstate;
-    uint64_t err;
-    struct timeval tv;
-    int delay;
-
-    if (tevent_req_is_error(req, &tstate, &err)) {
+    ret = ldap_id_cleanup(ctx);
+    if (ret != EOK) {
         /* On error schedule starting from now, not the last run */
         tv = tevent_timeval_current();
     } else {
         tv = ctx->last_purge;
     }
-    talloc_zfree(req);
 
     delay = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT);
     tv = tevent_timeval_add(&tv, delay, 0);
     ldap_id_cleanup_set_timer(ctx, tv);
+    ctx->last_purge = tevent_timeval_current();
 }
 
-
-
 int ldap_id_cleanup_set_timer(struct sdap_id_ctx *ctx, struct timeval tv)
 {
     struct tevent_timer *cleanup_task;
@@ -162,80 +81,58 @@ int ldap_id_cleanup_set_timer(struct sdap_id_ctx *ctx, struct timeval tv)
     return EOK;
 }
 
-
-
-struct global_cleanup_state {
-    struct tevent_context *ev;
-    struct sdap_id_ctx *ctx;
-};
-
 static int cleanup_users(TALLOC_CTX *memctx, struct sdap_id_ctx *ctx);
 static int cleanup_groups(TALLOC_CTX *memctx,
                           struct sysdb_ctx *sysdb,
                           struct sss_domain_info *domain);
 
-struct tevent_req *ldap_id_cleanup_send(TALLOC_CTX *memctx,
-                                        struct tevent_context *ev,
-                                        struct sdap_id_ctx *ctx)
+errno_t ldap_id_cleanup(struct sdap_id_ctx *ctx)
 {
-    struct global_cleanup_state *state;
-    struct tevent_req *req;
-    int ret;
+    int ret, tret;
     bool in_transaction = false;
+    TALLOC_CTX *tmp_ctx;
 
-    req = tevent_req_create(memctx, &state, struct global_cleanup_state);
-    if (!req) return NULL;
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        return ENOMEM;
+    }
 
-    state->ev = ev;
-    state->ctx = ctx;
-
-    ctx->last_purge = tevent_timeval_current();
-
-    ret = sysdb_transaction_start(state->ctx->be->domain->sysdb);
+    ret = sysdb_transaction_start(ctx->be->domain->sysdb);
     if (ret != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to start transaction\n"));
-        goto fail;
+        goto done;
     }
     in_transaction = true;
 
-    ret = cleanup_users(state, state->ctx);
+    ret = cleanup_users(tmp_ctx, ctx);
     if (ret && ret != ENOENT) {
-        goto fail;
+        goto done;
     }
 
-    ret = cleanup_groups(state,
-                         state->ctx->be->domain->sysdb,
-                         state->ctx->be->domain);
+    ret = cleanup_groups(tmp_ctx,
+                         ctx->be->domain->sysdb,
+                         ctx->be->domain);
     if (ret) {
-        goto fail;
+        goto done;
     }
 
-    ret = sysdb_transaction_commit(state->ctx->be->domain->sysdb);
+    ret = sysdb_transaction_commit(ctx->be->domain->sysdb);
     if (ret != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to commit transaction\n"));
-        goto fail;
+        goto done;
     }
     in_transaction = false;
 
-    tevent_req_done(req);
-    tevent_req_post(req, ev);
-    return req;
-
-fail:
-    DEBUG(1, ("Failed to cleanup caches (%d [%s]), retrying later!\n",
-              (int)ret, strerror(ret)));
+    ret = EOK;
+done:
     if (in_transaction) {
-        ret = sysdb_transaction_cancel(state->ctx->be->domain->sysdb);
-        if (ret != EOK) {
-            DEBUG(1, ("Could not cancel transaction\n"));
-            tevent_req_error(req, ret);
-            tevent_req_post(req, ev);
-            return req;
+        tret = sysdb_transaction_cancel(ctx->be->domain->sysdb);
+        if (tret != EOK) {
+            DEBUG(SSSDBG_CRIT_FAILURE, ("Could not cancel transaction\n"));
         }
     }
-    tevent_req_done(req);
-    tevent_req_post(req, ev);
-    return req;
+    talloc_free(tmp_ctx);
+    return ret;
 }
 
 
diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c
index ab6ae0773141157743977aba36a9115ce02be3cb..b34b801a3a6257ebc6f53d4b1970dba95ec2bb9f 100644
--- a/src/providers/ldap/sdap_async_enum.c
+++ b/src/providers/ldap/sdap_async_enum.c
@@ -31,10 +31,6 @@
 #include "providers/ldap/sdap_async.h"
 #include "providers/ldap/sdap_idmap.h"
 
-extern struct tevent_req *ldap_id_cleanup_send(TALLOC_CTX *memctx,
-                                               struct tevent_context *ev,
-                                               struct sdap_id_ctx *ctx);
-
 static struct tevent_req *enum_users_send(TALLOC_CTX *memctx,
                                           struct tevent_context *ev,
                                           struct sdap_id_ctx *ctx,
@@ -67,7 +63,6 @@ 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 void sdap_dom_enum_cleanup_done(struct tevent_req *subreq);
 
 struct tevent_req *
 sdap_dom_enum_send(TALLOC_CTX *memctx,
@@ -316,27 +311,18 @@ static void sdap_dom_enum_services_done(struct tevent_req *subreq)
     }
 
     if (state->purge) {
-        subreq = ldap_id_cleanup_send(state, state->ev, state->ctx);
-        if (!subreq) {
-            tevent_req_error(req, ENOMEM);
-            return;
+        ret = ldap_id_cleanup(state->ctx);
+        if (ret != EOK) {
+            /* Not fatal, worst case we'll have stale entries that would be
+             * removed on a subsequent online lookup
+             */
+            DEBUG(SSSDBG_MINOR_FAILURE, ("Cleanup failed: %d\n", ret));
         }
-
-        tevent_req_set_callback(subreq, sdap_dom_enum_cleanup_done, req);
-        return;
     }
 
     tevent_req_done(req);
 }
 
-static void sdap_dom_enum_cleanup_done(struct tevent_req *subreq)
-{
-    struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                      struct tevent_req);
-    talloc_zfree(subreq);
-    tevent_req_done(req);
-}
-
 errno_t sdap_dom_enum_recv(struct tevent_req *req)
 {
     TEVENT_REQ_RETURN_ON_ERROR(req);
-- 
1.8.3.1

-------------- next part --------------
>From 5c350304191aac074138ed2f8caee4d59f472665 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Thu, 22 Aug 2013 11:02:32 +0200
Subject: [PATCH 06/12] LDAP: Make the cleanup task reusable for subdomains

Instead of always performing the cleanup on the main domain, the task
now accepts a sdap_domain structure to perform the cleanup on. This
change will make the cleanup task reusable for subdomains.
---
 src/providers/ldap/ldap_common.c     |  2 +-
 src/providers/ldap/ldap_common.h     | 10 ++--
 src/providers/ldap/ldap_id_cleanup.c | 96 +++++++++++++++++++++++-------------
 src/providers/ldap/sdap.h            |  3 ++
 src/providers/ldap/sdap_async_enum.c |  4 +-
 5 files changed, 73 insertions(+), 42 deletions(-)

diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
index 05e487a1e8f57da338c9949b9f1a75688a6595e7..ffa8aae59130258b3346e9071ea8d0c867942fca 100644
--- a/src/providers/ldap/ldap_common.c
+++ b/src/providers/ldap/ldap_common.c
@@ -960,7 +960,7 @@ int sdap_id_setup_tasks(struct sdap_id_ctx *ctx)
         /* run the first one in a couple of seconds so that we have time to
          * finish initializations first*/
         tv = tevent_timeval_current_ofs(10, 0);
-        ret = ldap_id_cleanup_set_timer(ctx, tv);
+        ret = ldap_id_cleanup_create_timer(ctx, ctx->opts->sdom, tv);
     }
 
     return ret;
diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
index 1dd69f4e253f9bcf1162b8e0212eeac59ec621fe..fb45845eff805ef1359caf5aa3ea509f6fcd5cd9 100644
--- a/src/providers/ldap/ldap_common.h
+++ b/src/providers/ldap/ldap_common.h
@@ -63,9 +63,6 @@ struct sdap_id_ctx {
     /* connection to a server */
     struct sdap_id_conn_ctx *conn;
 
-    /* cleanup loop timer */
-    struct timeval last_purge;
-
     struct sdap_server_opts *srv_opts;
 };
 
@@ -168,8 +165,11 @@ int ldap_get_autofs_options(TALLOC_CTX *memctx,
 errno_t ldap_setup_enumeration(struct sdap_id_ctx *ctx,
                                struct sdap_id_conn_ctx *conn,
                                struct sdap_domain *sdom);
-errno_t ldap_id_cleanup(struct sdap_id_ctx *ctx);
-int ldap_id_cleanup_set_timer(struct sdap_id_ctx *ctx, struct timeval tv);
+errno_t ldap_id_cleanup(struct sdap_options *opts,
+                        struct sss_domain_info *dom);
+int ldap_id_cleanup_create_timer(struct sdap_id_ctx *ctx,
+                                 struct sdap_domain *sdom,
+                                 struct timeval tv);
 
 void sdap_mark_offline(struct sdap_id_ctx *ctx);
 
diff --git a/src/providers/ldap/ldap_id_cleanup.c b/src/providers/ldap/ldap_id_cleanup.c
index 85c0139dbb9ff2d72b4e132b73b3bd4c8d56aab0..1fd2ff49fe7e80fc9856eb7fadb9017145fb4b45 100644
--- a/src/providers/ldap/ldap_id_cleanup.c
+++ b/src/providers/ldap/ldap_id_cleanup.c
@@ -33,60 +33,90 @@
 #include "providers/ldap/sdap_async.h"
 
 /* ==Cleanup-Task========================================================= */
+struct ldap_id_cleanup_ctx {
+    struct sdap_id_ctx *ctx;
+    struct sdap_domain *sdom;
+};
+
+static errno_t ldap_id_cleanup_set_timer(struct ldap_id_cleanup_ctx *cctx,
+                                         struct timeval tv);
+
 static void ldap_id_cleanup_timer(struct tevent_context *ev,
                                   struct tevent_timer *tt,
                                   struct timeval tv, void *pvt)
 {
-    struct sdap_id_ctx *ctx = talloc_get_type(pvt, struct sdap_id_ctx);
+    struct ldap_id_cleanup_ctx *cctx = talloc_get_type(pvt,
+                                                struct ldap_id_cleanup_ctx);
     int delay;
     errno_t ret;
 
-    if (be_is_offline(ctx->be)) {
-        DEBUG(4, ("Backend is marked offline, retry later!\n"));
+    if (be_is_offline(cctx->ctx->be)) {
+        DEBUG(SSSDBG_TRACE_FUNC, ("Backend is marked offline, retry later!\n"));
         /* schedule starting from now, not the last run */
-        delay = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT);
+        delay = dp_opt_get_int(cctx->ctx->opts->basic,
+                               SDAP_CACHE_PURGE_TIMEOUT);
         tv = tevent_timeval_current_ofs(delay, 0);
-        ldap_id_cleanup_set_timer(ctx, tv);
+        ldap_id_cleanup_set_timer(cctx, tv);
         return;
     }
 
-    ret = ldap_id_cleanup(ctx);
+    ret = ldap_id_cleanup(cctx->ctx->opts, cctx->sdom->dom);
     if (ret != EOK) {
         /* On error schedule starting from now, not the last run */
         tv = tevent_timeval_current();
     } else {
-        tv = ctx->last_purge;
+        tv = cctx->sdom->last_purge;
     }
 
-    delay = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT);
+    delay = dp_opt_get_int(cctx->ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT);
     tv = tevent_timeval_add(&tv, delay, 0);
-    ldap_id_cleanup_set_timer(ctx, tv);
-    ctx->last_purge = tevent_timeval_current();
+    ldap_id_cleanup_set_timer(cctx, tv);
+    cctx->sdom->last_purge = tevent_timeval_current();
 }
 
-int ldap_id_cleanup_set_timer(struct sdap_id_ctx *ctx, struct timeval tv)
+static errno_t ldap_id_cleanup_set_timer(struct ldap_id_cleanup_ctx *cctx,
+                                         struct timeval tv)
 {
     struct tevent_timer *cleanup_task;
 
-    DEBUG(6, ("Scheduling next cleanup at %ld.%ld\n",
-              (long)tv.tv_sec, (long)tv.tv_usec));
-
-    cleanup_task = tevent_add_timer(ctx->be->ev, ctx,
-                                    tv, ldap_id_cleanup_timer, ctx);
-    if (!cleanup_task) {
-        DEBUG(0, ("FATAL: failed to setup cleanup task!\n"));
+    cleanup_task = tevent_add_timer(cctx->ctx->be->ev, cctx->ctx,
+                                    tv, ldap_id_cleanup_timer, cctx);
+    if (cleanup_task == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("FATAL: failed to setup cleanup task!\n"));
         return EFAULT;
     }
 
     return EOK;
 }
 
-static int cleanup_users(TALLOC_CTX *memctx, struct sdap_id_ctx *ctx);
+int ldap_id_cleanup_create_timer(struct sdap_id_ctx *ctx,
+                                 struct sdap_domain *sdom,
+                                 struct timeval tv)
+{
+    struct ldap_id_cleanup_ctx *cctx;
+
+    DEBUG(SSSDBG_FUNC_DATA,
+          ("Scheduling next cleanup at %ld.%ld\n",
+          (long)tv.tv_sec, (long)tv.tv_usec));
+
+    cctx = talloc(ctx, struct ldap_id_cleanup_ctx);
+    if (cctx == NULL) {
+        return ENOMEM;
+    }
+    cctx->ctx = ctx;
+    cctx->sdom = sdom;
+
+    return ldap_id_cleanup_set_timer(cctx, tv);
+}
+
+static int cleanup_users(struct sdap_options *opts,
+                         struct sss_domain_info *dom);
 static int cleanup_groups(TALLOC_CTX *memctx,
                           struct sysdb_ctx *sysdb,
                           struct sss_domain_info *domain);
 
-errno_t ldap_id_cleanup(struct sdap_id_ctx *ctx)
+errno_t ldap_id_cleanup(struct sdap_options *opts,
+                        struct sss_domain_info *dom)
 {
     int ret, tret;
     bool in_transaction = false;
@@ -97,26 +127,24 @@ errno_t ldap_id_cleanup(struct sdap_id_ctx *ctx)
         return ENOMEM;
     }
 
-    ret = sysdb_transaction_start(ctx->be->domain->sysdb);
+    ret = sysdb_transaction_start(dom->sysdb);
     if (ret != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to start transaction\n"));
         goto done;
     }
     in_transaction = true;
 
-    ret = cleanup_users(tmp_ctx, ctx);
+    ret = cleanup_users(opts, dom);
     if (ret && ret != ENOENT) {
         goto done;
     }
 
-    ret = cleanup_groups(tmp_ctx,
-                         ctx->be->domain->sysdb,
-                         ctx->be->domain);
+    ret = cleanup_groups(tmp_ctx, dom->sysdb, dom);
     if (ret) {
         goto done;
     }
 
-    ret = sysdb_transaction_commit(ctx->be->domain->sysdb);
+    ret = sysdb_transaction_commit(dom->sysdb);
     if (ret != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to commit transaction\n"));
         goto done;
@@ -126,7 +154,7 @@ errno_t ldap_id_cleanup(struct sdap_id_ctx *ctx)
     ret = EOK;
 done:
     if (in_transaction) {
-        tret = sysdb_transaction_cancel(ctx->be->domain->sysdb);
+        tret = sysdb_transaction_cancel(dom->sysdb);
         if (tret != EOK) {
             DEBUG(SSSDBG_CRIT_FAILURE, ("Could not cancel transaction\n"));
         }
@@ -141,10 +169,11 @@ done:
 static int cleanup_users_logged_in(hash_table_t *table,
                                    const struct ldb_message *msg);
 
-static int cleanup_users(TALLOC_CTX *memctx, struct sdap_id_ctx *ctx)
+static int cleanup_users(struct sdap_options *opts,
+                         struct sss_domain_info *dom)
 {
     TALLOC_CTX *tmpctx;
-    struct sysdb_ctx *sysdb = ctx->be->domain->sysdb;
+    struct sysdb_ctx *sysdb = dom->sysdb;
     const char *attrs[] = { SYSDB_NAME, SYSDB_UIDNUM, NULL };
     time_t now = time(NULL);
     char *subfilter = NULL;
@@ -156,13 +185,12 @@ static int cleanup_users(TALLOC_CTX *memctx, struct sdap_id_ctx *ctx)
     int ret;
     int i;
 
-    tmpctx = talloc_new(memctx);
+    tmpctx = talloc_new(NULL);
     if (!tmpctx) {
         return ENOMEM;
     }
 
-    account_cache_expiration = dp_opt_get_int(ctx->opts->basic,
-                                           SDAP_ACCOUNT_CACHE_EXPIRATION);
+    account_cache_expiration = dp_opt_get_int(opts->basic, SDAP_ACCOUNT_CACHE_EXPIRATION);
     DEBUG(9, ("Cache expiration is set to %d days\n",
               account_cache_expiration));
 
@@ -189,7 +217,7 @@ static int cleanup_users(TALLOC_CTX *memctx, struct sdap_id_ctx *ctx)
         goto done;
     }
 
-    ret = sysdb_search_users(tmpctx, sysdb, ctx->be->domain,
+    ret = sysdb_search_users(tmpctx, sysdb, dom,
                              subfilter, attrs, &count, &msgs);
     if (ret) {
         if (ret == ENOENT) {
@@ -236,7 +264,7 @@ static int cleanup_users(TALLOC_CTX *memctx, struct sdap_id_ctx *ctx)
 
         /* If not logged in or cannot check the table, delete him */
         DEBUG(9, ("About to delete user %s\n", name));
-        ret = sysdb_delete_user(sysdb, ctx->be->domain, name, 0);
+        ret = sysdb_delete_user(sysdb, dom, name, 0);
         if (ret) {
             goto done;
         }
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index 5da27fe87ff5900857ec89e6084ab4d766944327..441ac904bd2d03618376f6770304dc5c4db75923 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -384,9 +384,12 @@ struct sdap_domain {
     /* Need to modify the list from a talloc destructor */
     struct sdap_domain **head;
 
+    /* Enumeration and cleanup periodic task */
     struct be_ptask *enum_task;
     /* enumeration loop timer */
     struct timeval last_enum;
+    /* cleanup loop timer */
+    struct timeval last_purge;
 };
 
 struct sdap_options {
diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c
index b34b801a3a6257ebc6f53d4b1970dba95ec2bb9f..625db645f3061d0b5b6538b7193e997e22bf3429 100644
--- a/src/providers/ldap/sdap_async_enum.c
+++ b/src/providers/ldap/sdap_async_enum.c
@@ -93,7 +93,7 @@ sdap_dom_enum_send(TALLOC_CTX *memctx,
     sdom->last_enum = tevent_timeval_current();
 
     t = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT);
-    if ((ctx->last_purge.tv_sec + t) < sdom->last_enum.tv_sec) {
+    if ((sdom->last_purge.tv_sec + t) < sdom->last_enum.tv_sec) {
         state->purge = true;
     }
 
@@ -311,7 +311,7 @@ static void sdap_dom_enum_services_done(struct tevent_req *subreq)
     }
 
     if (state->purge) {
-        ret = ldap_id_cleanup(state->ctx);
+        ret = ldap_id_cleanup(state->ctx->opts, state->sdom->dom);
         if (ret != EOK) {
             /* Not fatal, worst case we'll have stale entries that would be
              * removed on a subsequent online lookup
-- 
1.8.3.1

-------------- next part --------------
>From ac57ac67eb54643f491608b6a1a2eb23fe7c9327 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Thu, 22 Aug 2013 11:03:01 +0200
Subject: [PATCH 07/12] LDAP: Make sdap_id_setup_tasks reusable for subdomains

Instead of always performing the setup for the main domain, the setup
can now be performed for subdomains as well.
---
 src/providers/ad/ad_init.c       |  2 +-
 src/providers/ipa/ipa_init.c     |  2 +-
 src/providers/ldap/ldap_common.c | 17 ++++++++++++-----
 src/providers/ldap/ldap_common.h |  7 ++++++-
 src/providers/ldap/ldap_init.c   |  2 +-
 5 files changed, 21 insertions(+), 9 deletions(-)

diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
index 816d12f062f0331e6f69256d121ef6776eaa89c5..f181afe6e37ace4cd0d7fba83923129b3161aad3 100644
--- a/src/providers/ad/ad_init.c
+++ b/src/providers/ad/ad_init.c
@@ -204,7 +204,7 @@ sssm_ad_id_init(struct be_ctx *bectx,
         goto done;
     }
 
-    ret = sdap_id_setup_tasks(ad_ctx->sdap_id_ctx);
+    ret = ldap_id_setup_tasks(ad_ctx->sdap_id_ctx);
     if (ret != EOK) {
         goto done;
     }
diff --git a/src/providers/ipa/ipa_init.c b/src/providers/ipa/ipa_init.c
index 407ab166918c5ff5599382c8281502380aa179fe..36ef702a3af81a739f000cb3a0c9e824eba0d872 100644
--- a/src/providers/ipa/ipa_init.c
+++ b/src/providers/ipa/ipa_init.c
@@ -191,7 +191,7 @@ int sssm_ipa_id_init(struct be_ctx *bectx,
     ret = ipa_idmap_init(sdap_ctx, sdap_ctx, &sdap_ctx->opts->idmap_ctx);
     if (ret != EOK) goto done;
 
-    ret = sdap_id_setup_tasks(sdap_ctx);
+    ret = ldap_id_setup_tasks(sdap_ctx);
     if (ret != EOK) {
         goto done;
     }
diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
index ffa8aae59130258b3346e9071ea8d0c867942fca..f7ad71182a4f46a20386e70ffda129347c5e3d87 100644
--- a/src/providers/ldap/ldap_common.c
+++ b/src/providers/ldap/ldap_common.c
@@ -936,16 +936,23 @@ void sdap_mark_offline(struct sdap_id_ctx *ctx)
     be_mark_offline(ctx->be);
 }
 
-int sdap_id_setup_tasks(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);
+}
+
+int sdap_id_setup_tasks(struct sdap_id_ctx *ctx,
+                        struct sdap_id_conn_ctx *conn,
+                        struct sdap_domain *sdom)
 {
     struct timeval tv;
     int ret = EOK;
     int delay;
 
     /* set up enumeration task */
-    if (ctx->be->domain->enumerate) {
-        DEBUG(SSSDBG_TRACE_FUNC, ("Setting up enumeration for %s\n", ctx->be->domain->name));
-        ret = ldap_setup_enumeration(ctx, ctx->conn, ctx->opts->sdom);
+    if (sdom->dom->enumerate) {
+        DEBUG(SSSDBG_TRACE_FUNC, ("Setting up enumeration for %s\n", sdom->dom->name));
+        ret = ldap_setup_enumeration(ctx, conn, sdom);
     } else {
         /* the enumeration task, runs the cleanup process by itself,
          * but if enumeration is not running we need to schedule it */
@@ -960,7 +967,7 @@ int sdap_id_setup_tasks(struct sdap_id_ctx *ctx)
         /* run the first one in a couple of seconds so that we have time to
          * finish initializations first*/
         tv = tevent_timeval_current_ofs(10, 0);
-        ret = ldap_id_cleanup_create_timer(ctx, ctx->opts->sdom, tv);
+        ret = ldap_id_cleanup_create_timer(ctx, sdom, tv);
     }
 
     return ret;
diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
index fb45845eff805ef1359caf5aa3ea509f6fcd5cd9..e5b7f1151e57fd22bce856c81801c2df7a60f0c3 100644
--- a/src/providers/ldap/ldap_common.h
+++ b/src/providers/ldap/ldap_common.h
@@ -90,7 +90,12 @@ errno_t sdap_reinit_cleanup_recv(struct tevent_req *req);
 void sdap_account_info_handler(struct be_req *breq);
 void sdap_handle_account_info(struct be_req *breq, struct sdap_id_ctx *ctx,
                               struct sdap_id_conn_ctx *conn);
-int sdap_id_setup_tasks(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,
+                        struct sdap_domain *sdom);
 
 struct tevent_req *
 sdap_handle_acct_req_send(TALLOC_CTX *mem_ctx,
diff --git a/src/providers/ldap/ldap_init.c b/src/providers/ldap/ldap_init.c
index 38d4fa7178d65873665da08a572952cc2aeea8c0..341338ca491593d906cff1ee71b040c2d0dea38b 100644
--- a/src/providers/ldap/ldap_init.c
+++ b/src/providers/ldap/ldap_init.c
@@ -160,7 +160,7 @@ int sssm_ldap_id_init(struct be_ctx *bectx,
     ret = sdap_idmap_init(ctx, ctx, &ctx->opts->idmap_ctx);
     if (ret != EOK) goto done;
 
-    ret = sdap_id_setup_tasks(ctx);
+    ret = ldap_id_setup_tasks(ctx);
     if (ret != EOK) {
         goto done;
     }
-- 
1.8.3.1

-------------- next part --------------
>From ae3cee52a7ce062bd7c4b104f1b94bfa79ac7e24 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Wed, 21 Aug 2013 17:22:59 +0200
Subject: [PATCH 08/12] SYSDB: Store enumerate flag for subdomain

---
 src/db/sysdb.h                     |  3 ++-
 src/db/sysdb_subdomains.c          | 27 +++++++++++++++++++++++++--
 src/providers/ad/ad_subdomains.c   |  4 ++--
 src/providers/ipa/ipa_subdomains.c |  3 ++-
 src/tests/sysdb-tests.c            | 12 +++++++-----
 5 files changed, 38 insertions(+), 11 deletions(-)

diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 953b15d2309e1a57a0938c475f22e45111796046..b6d5abb10d08518b495f8a0b062cc188e3593fd8 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -126,6 +126,7 @@
 #define SYSDB_SUBDOMAIN_FLAT "flatName"
 #define SYSDB_SUBDOMAIN_ID "domainID"
 #define SYSDB_SUBDOMAIN_MPG "mpg"
+#define SYSDB_SUBDOMAIN_ENUM "enumerate"
 
 #define SYSDB_BASE_ID "baseID"
 #define SYSDB_ID_RANGE_SIZE "idRangeSize"
@@ -370,7 +371,7 @@ errno_t sysdb_domain_create(struct sysdb_ctx *sysdb, const char *domain_name);
 errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb,
                               const char *name, const char *realm,
                               const char *flat_name, const char *domain_id,
-                              bool mpg);
+                              bool mpg, bool enumerate);
 
 errno_t sysdb_update_subdomains(struct sss_domain_info *domain);
 
diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c
index 0e7514baa993a4d02402695bf51992488fc0ed1e..2b80b5b9e79a101ab030b4af1dfc5497e9b35bf6 100644
--- a/src/db/sysdb_subdomains.c
+++ b/src/db/sysdb_subdomains.c
@@ -342,7 +342,7 @@ done:
 errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb,
                               const char *name, const char *realm,
                               const char *flat_name, const char *domain_id,
-                              bool mpg)
+                              bool mpg, bool enumerate)
 {
     TALLOC_CTX *tmp_ctx;
     struct ldb_message *msg;
@@ -353,6 +353,7 @@ errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb,
                            SYSDB_SUBDOMAIN_FLAT,
                            SYSDB_SUBDOMAIN_ID,
                            SYSDB_SUBDOMAIN_MPG,
+                           SYSDB_SUBDOMAIN_ENUM,
                            NULL};
     const char *tmp_str;
     bool tmp_bool;
@@ -361,6 +362,7 @@ errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb,
     int flat_flags = 0;
     int id_flags = 0;
     int mpg_flags = 0;
+    int enum_flags = 0;
     int ret;
 
     tmp_ctx = talloc_new(NULL);
@@ -390,6 +392,7 @@ errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb,
         if (flat_name) flat_flags = LDB_FLAG_MOD_ADD;
         if (domain_id) id_flags = LDB_FLAG_MOD_ADD;
         mpg_flags = LDB_FLAG_MOD_ADD;
+        enum_flags = LDB_FLAG_MOD_ADD;
     } else if (res->count != 1) {
         ret = EINVAL;
         goto done;
@@ -421,10 +424,15 @@ errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb,
         if (tmp_bool != mpg) {
             mpg_flags = LDB_FLAG_MOD_REPLACE;
         }
+        tmp_bool = ldb_msg_find_attr_as_bool(res->msgs[0], SYSDB_SUBDOMAIN_ENUM,
+                                             !enumerate);
+        if (tmp_bool != enumerate) {
+            enum_flags = LDB_FLAG_MOD_REPLACE;
+        }
     }
 
     if (!store && realm_flags == 0 && flat_flags == 0 && id_flags == 0
-            && mpg_flags == 0) {
+            && mpg_flags == 0 && enum_flags == 0) {
         ret = EOK;
         goto done;
     }
@@ -507,6 +515,21 @@ errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb,
         }
     }
 
+    if (enum_flags) {
+        ret = ldb_msg_add_empty(msg, SYSDB_SUBDOMAIN_ENUM, enum_flags, NULL);
+        if (ret != LDB_SUCCESS) {
+            ret = sysdb_error_to_errno(ret);
+            goto done;
+        }
+
+        ret = ldb_msg_add_string(msg, SYSDB_SUBDOMAIN_ENUM,
+                                 enumerate ? "TRUE" : "FALSE");
+        if (ret != LDB_SUCCESS) {
+            ret = sysdb_error_to_errno(ret);
+            goto done;
+        }
+    }
+
     ret = ldb_modify(sysdb->ldb, msg);
     if (ret != LDB_SUCCESS) {
         DEBUG(SSSDBG_FATAL_FAILURE, ("Failed to add subdomain attributes to "
diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
index 0eebd4d98bb59ab1bdc65fabc2edef821b4d3b73..afd2031fe6be557f43555b6dd8b47731d9833585 100644
--- a/src/providers/ad/ad_subdomains.c
+++ b/src/providers/ad/ad_subdomains.c
@@ -156,9 +156,9 @@ ad_subdom_store(struct ad_subdomains_ctx *ctx,
         goto done;
     }
 
-    /* AD subdomains are currently all mpg */
+    /* AD subdomains are currently all mpg and do not enumerate */
     ret = sysdb_subdomain_store(domain->sysdb, name, realm, flat, sid_str,
-                                true);
+                                true, false);
     if (ret != EOK) {
         DEBUG(SSSDBG_OP_FAILURE, ("sysdb_subdomain_store failed.\n"));
         goto done;
diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
index 1a0c1c1bbf5f4e6fa44b352af4883f8624074ad5..6064f0407b0a98f795db52f216adb4d1ff539435 100644
--- a/src/providers/ipa/ipa_subdomains.c
+++ b/src/providers/ipa/ipa_subdomains.c
@@ -445,7 +445,8 @@ static errno_t ipa_subdom_store(struct sss_domain_info *domain,
 
     mpg = sdap_idmap_domain_has_algorithmic_mapping(sdap_idmap_ctx, id);
 
-    ret = sysdb_subdomain_store(domain->sysdb, name, realm, flat, id, mpg);
+    ret = sysdb_subdomain_store(domain->sysdb, name, realm, flat,
+                                id, mpg, false);
     if (ret) {
         DEBUG(SSSDBG_OP_FAILURE, ("sysdb_subdomain_store failed.\n"));
         goto done;
diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
index 60a20c8b4d1dcb8701286b1589bdcf351d2ccd95..31d2dd3dea7aaef94aad88e398fa779b8c85fce3 100644
--- a/src/tests/sysdb-tests.c
+++ b/src/tests/sysdb-tests.c
@@ -4524,7 +4524,8 @@ START_TEST(test_sysdb_subdomain_create)
     fail_if(ret != EOK, "Could not set up the test");
 
     ret = sysdb_subdomain_store(test_ctx->sysdb,
-                                dom1[0], dom1[1], dom1[2], dom1[3], false);
+                                dom1[0], dom1[1], dom1[2], dom1[3],
+                                false, false);
     fail_if(ret != EOK, "Could not set up the test (dom1)");
 
     ret = sysdb_update_subdomains(test_ctx->domain);
@@ -4537,7 +4538,8 @@ START_TEST(test_sysdb_subdomain_create)
             dom1[0], test_ctx->domain->subdomains->name);
 
     ret = sysdb_subdomain_store(test_ctx->sysdb,
-                                dom2[0], dom2[1], dom2[2], dom2[3], false);
+                                dom2[0], dom2[1], dom2[2], dom2[3],
+                                false, false);
     fail_if(ret != EOK, "Could not set up the test (dom2)");
 
     ret = sysdb_update_subdomains(test_ctx->domain);
@@ -4586,7 +4588,7 @@ START_TEST(test_sysdb_subdomain_store_user)
     fail_unless(subdomain != NULL, "Failed to create new subdomin.");
     ret = sysdb_subdomain_store(test_ctx->sysdb,
                                 testdom[0], testdom[1], testdom[2], testdom[3],
-                                false);
+                                false, false);
     fail_if(ret != EOK, "Could not set up the test (test subdom)");
 
     ret = sysdb_update_subdomains(test_ctx->domain);
@@ -4657,7 +4659,7 @@ START_TEST(test_sysdb_subdomain_user_ops)
     fail_unless(subdomain != NULL, "Failed to create new subdomin.");
     ret = sysdb_subdomain_store(test_ctx->sysdb,
                                 testdom[0], testdom[1], testdom[2], testdom[3],
-                                false);
+                                false, false);
     fail_if(ret != EOK, "Could not set up the test (test subdom)");
 
     ret = sysdb_update_subdomains(test_ctx->domain);
@@ -4712,7 +4714,7 @@ START_TEST(test_sysdb_subdomain_group_ops)
     fail_unless(subdomain != NULL, "Failed to create new subdomin.");
     ret = sysdb_subdomain_store(test_ctx->sysdb,
                                 testdom[0], testdom[1], testdom[2], testdom[3],
-                                false);
+                                false, false);
     fail_if(ret != EOK, "Could not set up the test (test subdom)");
 
     ret = sysdb_update_subdomains(test_ctx->domain);
-- 
1.8.3.1

-------------- next part --------------
>From 6ed480740036373c965537f6e3c822a931373ab6 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Wed, 21 Aug 2013 17:28:47 +0200
Subject: [PATCH 09/12] Read enumerate state for subdomains from cache

The enumerate flag will be read from the cache for subdomains and
the domain object will be created accordingly.
---
 src/db/sysdb_subdomains.c    | 16 +++++++++++++++-
 src/tests/sysdb-tests.c      |  6 +++---
 src/util/domain_info_utils.c |  5 +++--
 src/util/util.h              |  3 ++-
 4 files changed, 23 insertions(+), 7 deletions(-)

diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c
index 2b80b5b9e79a101ab030b4af1dfc5497e9b35bf6..5ef9aef73d8def1679b9c0a4ccef0360eb688827 100644
--- a/src/db/sysdb_subdomains.c
+++ b/src/db/sysdb_subdomains.c
@@ -34,6 +34,7 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain)
                            SYSDB_SUBDOMAIN_FLAT,
                            SYSDB_SUBDOMAIN_ID,
                            SYSDB_SUBDOMAIN_MPG,
+                           SYSDB_SUBDOMAIN_ENUM,
                            NULL};
     struct sss_domain_info *dom;
     struct ldb_dn *basedn;
@@ -42,6 +43,7 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain)
     const char *flat;
     const char *id;
     bool mpg;
+    bool enumerate;
 
     tmp_ctx = talloc_new(NULL);
     if (tmp_ctx == NULL) {
@@ -96,6 +98,9 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain)
         mpg = ldb_msg_find_attr_as_bool(res->msgs[i],
                                         SYSDB_SUBDOMAIN_MPG, false);
 
+        enumerate = ldb_msg_find_attr_as_bool(res->msgs[i],
+                                              SYSDB_SUBDOMAIN_ENUM, false);
+
         /* explicitly use dom->next as we need to check 'disabled' domains */
         for (dom = domain->subdomains; dom; dom = dom->next) {
             if (strcasecmp(dom->name, name) == 0) {
@@ -143,12 +148,21 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain)
                     dom->mpg = mpg;
                 }
 
+                if (dom->enumerate != enumerate) {
+                    DEBUG(SSSDBG_TRACE_INTERNAL,
+                          ("MPG state change from [%s] to [%s]!\n",
+                           dom->enumerate ? "true" : "false",
+                           enumerate ? "true" : "false"));
+                    dom->enumerate = enumerate;
+                }
+
                 break;
             }
         }
         /* If not found in loop it is a new subdomain */
         if (dom == NULL) {
-            dom = new_subdomain(domain, domain, name, realm, flat, id, mpg);
+            dom = new_subdomain(domain, domain, name, realm,
+                                flat, id, mpg, enumerate);
             if (dom == NULL) {
                 ret = ENOMEM;
                 goto done;
diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
index 31d2dd3dea7aaef94aad88e398fa779b8c85fce3..6f95d248b65fe832447268e4d9eb94ceb2af7c17 100644
--- a/src/tests/sysdb-tests.c
+++ b/src/tests/sysdb-tests.c
@@ -4584,7 +4584,7 @@ START_TEST(test_sysdb_subdomain_store_user)
 
     subdomain = new_subdomain(test_ctx, test_ctx->domain,
                               testdom[0], testdom[1], testdom[2], testdom[3],
-                              false);
+                              false, false);
     fail_unless(subdomain != NULL, "Failed to create new subdomin.");
     ret = sysdb_subdomain_store(test_ctx->sysdb,
                                 testdom[0], testdom[1], testdom[2], testdom[3],
@@ -4655,7 +4655,7 @@ START_TEST(test_sysdb_subdomain_user_ops)
 
     subdomain = new_subdomain(test_ctx, test_ctx->domain,
                               testdom[0], testdom[1], testdom[2], testdom[3],
-                              false);
+                              false, false);
     fail_unless(subdomain != NULL, "Failed to create new subdomin.");
     ret = sysdb_subdomain_store(test_ctx->sysdb,
                                 testdom[0], testdom[1], testdom[2], testdom[3],
@@ -4710,7 +4710,7 @@ START_TEST(test_sysdb_subdomain_group_ops)
 
     subdomain = new_subdomain(test_ctx, test_ctx->domain,
                               testdom[0], testdom[1], testdom[2], testdom[3],
-                              false);
+                              false, false);
     fail_unless(subdomain != NULL, "Failed to create new subdomin.");
     ret = sysdb_subdomain_store(test_ctx->sysdb,
                                 testdom[0], testdom[1], testdom[2], testdom[3],
diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c
index 6553927cfd07162dc7f901f022284a839d3ba4e1..be5185698a218797b5966902b2c86eecf1e7bb30 100644
--- a/src/util/domain_info_utils.c
+++ b/src/util/domain_info_utils.c
@@ -76,7 +76,8 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx,
                                       const char *realm,
                                       const char *flat_name,
                                       const char *id,
-                                      bool mpg)
+                                      bool mpg,
+                                      bool enumerate)
 {
     struct sss_domain_info *dom;
 
@@ -132,7 +133,7 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx,
         }
     }
 
-    dom->enumerate = false;
+    dom->enumerate = enumerate;
     dom->fqnames = true;
     dom->mpg = mpg;
     /* FIXME: get ranges from the server */
diff --git a/src/util/util.h b/src/util/util.h
index d8aeb733e4dbe2db414be5caa43712cecccca7f9..73d1fae60cb9aff88834a5cd565f4e9d67a07db6 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -544,7 +544,8 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx,
                                       const char *realm,
                                       const char *flat_name,
                                       const char *id,
-                                      bool mpg);
+                                      bool mpg,
+                                      bool enumerate);
 
 errno_t sssd_domain_init(TALLOC_CTX *mem_ctx,
                          struct confdb_ctx *cdb,
-- 
1.8.3.1

-------------- next part --------------
>From 1e279471889517ff81ad9907cc70f54fdda398e6 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Wed, 28 Aug 2013 10:49:32 +0200
Subject: [PATCH 10/12] Add a new option to control subdomain enumeration

---
 src/confdb/confdb.c                  | 13 +++++++++++++
 src/confdb/confdb.h                  |  3 +++
 src/config/SSSDConfig/__init__.py.in |  1 +
 src/config/SSSDConfigTest.py         |  2 ++
 src/config/etc/sssd.api.conf         |  1 +
 src/man/sssd.conf.5.xml              | 27 +++++++++++++++++++++++++++
 src/util/domain_info_utils.c         | 25 +++++++++++++++++++++++++
 src/util/util.h                      |  4 +++-
 8 files changed, 75 insertions(+), 1 deletion(-)

diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c
index 693118e79ae0e0b1a828c748b88e242b4fd02547..6527ede4bc6eeb964f9dd789d54184fb5514f149 100644
--- a/src/confdb/confdb.c
+++ b/src/confdb/confdb.c
@@ -1129,6 +1129,19 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb,
         goto done;
     }
 
+    tmp = ldb_msg_find_attr_as_string(res->msgs[0],
+                                      CONFDB_SUBDOMAIN_ENUMERATE,
+                                      CONFDB_DEFAULT_SUBDOMAIN_ENUMERATE);
+    if (tmp != NULL) {
+        ret = split_on_separator(domain, tmp, ',', true, true,
+                                 &domain->sd_enumerate, NULL);
+        if (ret != 0) {
+            DEBUG(SSSDBG_FATAL_FAILURE,
+                  ("Cannot parse %s\n", CONFDB_SUBDOMAIN_ENUMERATE));
+            goto done;
+        }
+    }
+
     *_domain = domain;
     ret = EOK;
 done:
diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
index ab7abe910c633e53e003a04231be3cdc2666f643..cb2a624254bd6a146ac91182412ced4f8cef2f5f 100644
--- a/src/confdb/confdb.h
+++ b/src/confdb/confdb.h
@@ -148,6 +148,8 @@
 #define CONFDB_DOMAIN_TIMEOUT "timeout"
 #define CONFDB_DOMAIN_ATTR "cn"
 #define CONFDB_DOMAIN_ENUMERATE "enumerate"
+#define CONFDB_SUBDOMAIN_ENUMERATE "subdomain_enumerate"
+#define CONFDB_DEFAULT_SUBDOMAIN_ENUMERATE "none"
 #define CONFDB_DOMAIN_MINID "min_id"
 #define CONFDB_DOMAIN_MAXID "max_id"
 #define CONFDB_DOMAIN_CACHE_CREDS "cache_credentials"
@@ -199,6 +201,7 @@ struct sss_domain_info {
     char *provider;
     int timeout;
     bool enumerate;
+    char **sd_enumerate;
     bool fqnames;
     bool mpg;
     bool ignore_group_members;
diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
index 1bc4f1bffeb757547d35f6064d9c36bf053d49f9..f073419e9c0aacdaad4343d05e58a6a2c9a732e2 100644
--- a/src/config/SSSDConfig/__init__.py.in
+++ b/src/config/SSSDConfig/__init__.py.in
@@ -133,6 +133,7 @@ option_strings = {
     'dyndns_update_ptr' : _("Whether the provider should explicitly update the PTR record as well"),
     'dyndns_force_tcp' : _("Whether the nsupdate utility should default to using TCP"),
     'dyndns_auth' : _("What kind of authentication should be used to perform the DNS update"),
+    'subdomain_enumerate' : _('Control enumeration of trusted domains'),
 
     # [provider/ipa]
     'ipa_domain' : _('IPA domain'),
diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py
index ca344ad4dea88919145a402bf1b0888afa78bb63..acec3e6f4a97933d6c3419350433360e88c63987 100755
--- a/src/config/SSSDConfigTest.py
+++ b/src/config/SSSDConfigTest.py
@@ -516,6 +516,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
             'dyndns_update_ptr',
             'dyndns_force_tcp',
             'dyndns_auth',
+            'subdomain_enumerate',
             'override_gid',
             'case_sensitive',
             'override_homedir',
@@ -870,6 +871,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
             'dyndns_update_ptr',
             'dyndns_force_tcp',
             'dyndns_auth',
+            'subdomain_enumerate',
             'override_gid',
             'case_sensitive',
             'override_homedir',
diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
index 5c095c188aca1a0a358848b350b3fc32e5a36a1e..4b8e97ba11f251dee6cd5d5cd44fc68c5ddf1931 100644
--- a/src/config/etc/sssd.api.conf
+++ b/src/config/etc/sssd.api.conf
@@ -94,6 +94,7 @@ max_id = int, None, false
 timeout = int, None, false
 try_inotify = bool, None, false
 enumerate = bool, None, false
+subdomain_enumerate = str, None, false
 force_timeout = int, None, false
 cache_credentials = bool, None, false
 store_legacy_passwords = bool, None, false
diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
index 31150a6aa6b4d68d291a8e3cd526fea2e7a78c67..a15f7288cc147b3f2944bb91cb861705279a3a37 100644
--- a/src/man/sssd.conf.5.xml
+++ b/src/man/sssd.conf.5.xml
@@ -972,6 +972,33 @@ override_homedir = /home/%u
                         </para>
                     </listitem>
                 </varlistentry>
+
+                <varlistentry>
+                    <term>subdomain_enumerate (string)</term>
+                    <listitem>
+                        <para>
+                            Whether any of autodetected trusted domains should
+                            be enumerated. The supported values are:
+                            <variablelist>
+                                <varlistentry>
+                                    <term>all</term>
+                                    <listitem><para>All discovered trusted domains will be enumerated</para></listitem>
+                                </varlistentry>
+                                <varlistentry>
+                                    <term>none</term>
+                                    <listitem><para>No discovered trusted domains will be enumerated</para></listitem>
+                                </varlistentry>
+                            </variablelist>
+                            Optionally, a list of one or more domain
+                            names can enable enumeration just for these
+                            trusted domains.
+                        </para>
+                        <para>
+                            Default: none
+                        </para>
+                    </listitem>
+                </varlistentry>
+
                 <varlistentry>
                     <term>force_timeout (integer)</term>
                     <listitem>
diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c
index be5185698a218797b5966902b2c86eecf1e7bb30..8b03e9a53fad8614ab0dccf14dceb30232ad84d4 100644
--- a/src/util/domain_info_utils.c
+++ b/src/util/domain_info_utils.c
@@ -49,6 +49,31 @@ struct sss_domain_info *get_next_domain(struct sss_domain_info *domain,
     return dom;
 }
 
+bool subdomain_enumerates(struct sss_domain_info *parent,
+                          const char *sd_name)
+{
+    if (parent->sd_enumerate == NULL
+            || parent->sd_enumerate[0] == NULL) {
+        DEBUG(SSSDBG_MINOR_FAILURE,
+              ("Subdomain_enumerate not set\n"));
+        return false;
+    }
+
+    if (strcasecmp(parent->sd_enumerate[0], "all") == 0) {
+        return true;
+    } else if (strcasecmp(parent->sd_enumerate[0], "none") == 0) {
+        return false;
+    } else {
+        for (int i=0; parent->sd_enumerate[i]; i++) {
+            if (strcasecmp(parent->sd_enumerate[i], sd_name) == 0) {
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
 struct sss_domain_info *find_subdomain_by_name(struct sss_domain_info *domain,
                                                const char *name,
                                                bool match_any)
diff --git a/src/util/util.h b/src/util/util.h
index 73d1fae60cb9aff88834a5cd565f4e9d67a07db6..f350bc76e671e00556e3044cc027be720c21364f 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -531,12 +531,14 @@ struct sized_string {
 
 void to_sized_string(struct sized_string *out, const char *in);
 
-/* form domain_info.c */
+/* from domain_info.c */
 struct sss_domain_info *get_next_domain(struct sss_domain_info *domain,
                                         bool descend);
 struct sss_domain_info *find_subdomain_by_name(struct sss_domain_info *domain,
                                                const char *name,
                                                bool match_any);
+bool subdomain_enumerates(struct sss_domain_info *parent,
+                          const char *sd_name);
 
 struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx,
                                       struct sss_domain_info *parent,
-- 
1.8.3.1

-------------- next part --------------
>From 09eb3b31851828be6aa653824033d378693b971f Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Wed, 21 Aug 2013 05:15:36 +0200
Subject: [PATCH 11/12] IPA: enable enumeration if parent domain enumerates in
 server mode

---
 src/providers/ipa/ipa_subdomains.c | 71 +++++++++++++++++++++++++++++++-------
 1 file changed, 59 insertions(+), 12 deletions(-)

diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
index 6064f0407b0a98f795db52f216adb4d1ff539435..742ca465fce86af0df7b6936280dbbc1841e823e 100644
--- a/src/providers/ipa/ipa_subdomains.c
+++ b/src/providers/ipa/ipa_subdomains.c
@@ -102,6 +102,7 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx,
     struct ad_options *ad_options;
     struct ad_id_ctx *ad_id_ctx;
     const char *gc_service_name;
+    struct sdap_domain *sdom;
     errno_t ret;
 
     ad_options = ad_create_default_options(id_ctx, id_ctx->server_mode->realm,
@@ -162,6 +163,18 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx,
         return ret;
     }
 
+    sdom = sdap_domain_get(ad_id_ctx->sdap_id_ctx->opts, subdom);
+    if (sdom == NULL) {
+        return EFAULT;
+    }
+
+    ret = sdap_id_setup_tasks(ad_id_ctx->sdap_id_ctx,
+                              ad_id_ctx->ldap_ctx, sdom);
+    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;
@@ -242,6 +255,7 @@ ipa_ad_subdom_remove(struct ipa_subdomains_ctx *ctx,
                      struct sss_domain_info *subdom)
 {
     struct ipa_ad_server_ctx *iter;
+    struct sdap_domain *sdom;
 
     if (dp_opt_get_bool(ctx->id_ctx->ipa_options->basic,
                         IPA_SERVER_MODE) == false) {
@@ -260,6 +274,10 @@ ipa_ad_subdom_remove(struct ipa_subdomains_ctx *ctx,
 
     sdap_domain_remove(iter->ad_id_ctx->sdap_id_ctx->opts, subdom);
     DLIST_REMOVE(ctx->id_ctx->server_mode->trusts, iter);
+
+    sdom = sdap_domain_get(iter->ad_id_ctx->sdap_id_ctx->opts, subdom);
+    if (sdom == NULL) return;
+    be_ptask_destroy(&sdom->enum_task);
 }
 
 const char *get_flat_name_from_subdomain_name(struct be_ctx *be_ctx,
@@ -402,9 +420,27 @@ done:
     return ret;
 }
 
-static errno_t ipa_subdom_store(struct sss_domain_info *domain,
+static errno_t ipa_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, IPA_CN, &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 ipa_subdom_store(struct sss_domain_info *parent,
                                 struct sdap_idmap_ctx *sdap_idmap_ctx,
-                                struct sysdb_attrs *attrs)
+                                struct sysdb_attrs *attrs,
+                                bool enumerate)
 {
     TALLOC_CTX *tmp_ctx;
     const char *name;
@@ -414,7 +450,7 @@ static errno_t ipa_subdom_store(struct sss_domain_info *domain,
     int ret;
     bool mpg;
 
-    tmp_ctx = talloc_new(domain);
+    tmp_ctx = talloc_new(parent);
     if (tmp_ctx == NULL) {
         return ENOMEM;
     }
@@ -445,8 +481,8 @@ static errno_t ipa_subdom_store(struct sss_domain_info *domain,
 
     mpg = sdap_idmap_domain_has_algorithmic_mapping(sdap_idmap_ctx, id);
 
-    ret = sysdb_subdomain_store(domain->sysdb, name, realm, flat,
-                                id, mpg, false);
+    ret = sysdb_subdomain_store(parent->sysdb, name, realm, flat,
+                                id, mpg, enumerate);
     if (ret) {
         DEBUG(SSSDBG_OP_FAILURE, ("sysdb_subdomain_store failed.\n"));
         goto done;
@@ -462,18 +498,19 @@ static errno_t ipa_subdomains_refresh(struct ipa_subdomains_ctx *ctx,
                                       int count, struct sysdb_attrs **reply,
                                       bool *changes)
 {
-    struct sss_domain_info *domain, *dom;
+    struct sss_domain_info *parent, *dom;
     bool handled[count];
     const char *value;
     int c, h;
     int ret;
+    bool enumerate;
 
-    domain = ctx->be_ctx->domain;
+    parent = ctx->be_ctx->domain;
     memset(handled, 0, sizeof(bool) * count);
     h = 0;
 
     /* check existing subdomains */
-    for (dom = get_next_domain(domain, true);
+    for (dom = get_next_domain(parent, true);
          dom && IS_SUBDOMAIN(dom); /* if we get back to a parent, stop */
          dom = get_next_domain(dom, false)) {
         for (c = 0; c < count; c++) {
@@ -502,8 +539,13 @@ static errno_t ipa_subdomains_refresh(struct ipa_subdomains_ctx *ctx,
             ipa_ad_subdom_remove(ctx, dom);
         } else {
             /* ok let's try to update it */
-            ret = ipa_subdom_store(domain, ctx->sdap_id_ctx->opts->idmap_ctx,
-                                   reply[c]);
+            ret = ipa_subdom_enumerates(parent, reply[c], &enumerate);
+            if (ret != EOK) {
+                goto done;
+            }
+
+            ret = ipa_subdom_store(parent, ctx->sdap_id_ctx->opts->idmap_ctx,
+                                   reply[c], enumerate);
             if (ret) {
                 /* Nothing we can do about the errorr. Let's at least try
                  * to reuse the existing domain
@@ -532,8 +574,13 @@ static errno_t ipa_subdomains_refresh(struct ipa_subdomains_ctx *ctx,
         /* Nothing we can do about the errorr. Let's at least try
          * to reuse the existing domain.
          */
-        ret = ipa_subdom_store(domain, ctx->sdap_id_ctx->opts->idmap_ctx,
-                               reply[c]);
+        ret = ipa_subdom_enumerates(parent, reply[c], &enumerate);
+        if (ret != EOK) {
+            goto done;
+        }
+
+        ret = ipa_subdom_store(parent, ctx->sdap_id_ctx->opts->idmap_ctx,
+                               reply[c], enumerate);
         if (ret) {
             DEBUG(SSSDBG_MINOR_FAILURE, ("Failed to parse subdom data, "
                   "will try to use cached subdomain\n"));
-- 
1.8.3.1

-------------- next part --------------
>From aca947cee4089406e38e02bd2d87c293ee74e6b0 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Wed, 21 Aug 2013 16:27:50 +0200
Subject: [PATCH 12/12] NSS: Descend into subdomains if enumerate=true

Since we now store the enumerate flag in sysdb for subdomains, we can
always descend to all available subdomains and if they do not allow
enumeration, simply skip them.
---
 src/responder/nss/nsssrv_cmd.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
index 7c35a7b3121dae9ba53135d79d1f7619be1e810b..18ccdeacca0d3a0314526e7728b3ffe42e42245a 100644
--- a/src/responder/nss/nsssrv_cmd.c
+++ b/src/responder/nss/nsssrv_cmd.c
@@ -1597,8 +1597,8 @@ struct tevent_req *nss_cmd_setpwent_send(TALLOC_CTX *mem_ctx,
     }
 
     /* check if enumeration is enabled in any domain */
-    for (dom = client->rctx->domains; dom; dom = get_next_domain(dom, false)) {
-        if (dom->enumerate != 0) break;
+    for (dom = client->rctx->domains; dom; dom = get_next_domain(dom, true)) {
+        if (dom->enumerate == true) break;
     }
     state->dctx->domain = dom;
 
@@ -1710,7 +1710,7 @@ static errno_t nss_cmd_setpwent_step(struct setent_step_ctx *step_ctx)
 
     while (dom) {
         while (dom && dom->enumerate == 0) {
-            dom = get_next_domain(dom, false);
+            dom = get_next_domain(dom, true);
         }
 
         if (!dom) break;
@@ -1768,13 +1768,13 @@ static errno_t nss_cmd_setpwent_step(struct setent_step_ctx *step_ctx)
         if (ret != EOK) {
             DEBUG(1, ("Enum from cache failed, skipping domain [%s]\n",
                       dom->name));
-            dom = get_next_domain(dom, false);
+            dom = get_next_domain(dom, true);
             continue;
         }
 
         if (res->count == 0) {
             DEBUG(4, ("Domain [%s] has no users, skipping.\n", dom->name));
-            dom = get_next_domain(dom, false);
+            dom = get_next_domain(dom, true);
             continue;
         }
 
@@ -1792,7 +1792,7 @@ static errno_t nss_cmd_setpwent_step(struct setent_step_ctx *step_ctx)
         nctx->pctx->num++;
 
         /* do not reply until all domain searches are done */
-        dom = get_next_domain(dom, false);
+        dom = get_next_domain(dom, true);
     }
 
     /* We've finished all our lookups
@@ -2818,8 +2818,8 @@ struct tevent_req *nss_cmd_setgrent_send(TALLOC_CTX *mem_ctx,
     }
 
     /* check if enumeration is enabled in any domain */
-    for (dom = client->rctx->domains; dom; dom = get_next_domain(dom, false)) {
-        if (dom->enumerate != 0) break;
+    for (dom = client->rctx->domains; dom; dom = get_next_domain(dom, true)) {
+        if (dom->enumerate == true) break;
     }
     state->dctx->domain = dom;
 
@@ -2931,7 +2931,7 @@ static errno_t nss_cmd_setgrent_step(struct setent_step_ctx *step_ctx)
 
     while (dom) {
         while (dom && dom->enumerate == 0) {
-            dom = get_next_domain(dom, false);
+            dom = get_next_domain(dom, true);
         }
 
         if (!dom) break;
@@ -2989,13 +2989,13 @@ static errno_t nss_cmd_setgrent_step(struct setent_step_ctx *step_ctx)
         if (ret != EOK) {
             DEBUG(1, ("Enum from cache failed, skipping domain [%s]\n",
                       dom->name));
-            dom = get_next_domain(dom, false);
+            dom = get_next_domain(dom, true);
             continue;
         }
 
         if (res->count == 0) {
             DEBUG(4, ("Domain [%s] has no groups, skipping.\n", dom->name));
-            dom = get_next_domain(dom, false);
+            dom = get_next_domain(dom, true);
             continue;
         }
 
@@ -3013,7 +3013,7 @@ static errno_t nss_cmd_setgrent_step(struct setent_step_ctx *step_ctx)
         nctx->gctx->num++;
 
         /* do not reply until all domain searches are done */
-        dom = get_next_domain(dom, false);
+        dom = get_next_domain(dom, true);
     }
 
     /* We've finished all our lookups
-- 
1.8.3.1



More information about the sssd-devel mailing list