From 5f52283645fdc036d9d97abec379d9a0aceca5ed Mon Sep 17 00:00:00 2001
From: Samuel Cabrero <scabrero@suse.de>
Date: Fri, 12 Jul 2019 15:03:18 +0200
Subject: [PATCH 1/8] SYSDB: Convert cached domain 'enumerated' attribute from
 bool to uint

Currently only the 'id' provider setup enumeration tasks and uses this
attribute, but other providers (or future ones) should be able to enumerate
idependently from each other.

The has_enumerated attribute in the domain cache entry is converted to a uint
to store a bitmap indicating which provider has enumerated.

Signed-off-by: Samuel Cabrero <scabrero@suse.de>
---
 src/db/sysdb.c                       | 172 ++++++++++++++++++++++++++-
 src/db/sysdb.h                       |  16 ++-
 src/providers/ldap/ldap_id_enum.c    |   3 +-
 src/providers/ldap/sdap_async_enum.c |   3 +-
 src/providers/ldap/sdap_reinit.c     |   2 +-
 src/tests/sysdb-tests.c              |  63 +++++++++-
 6 files changed, 247 insertions(+), 12 deletions(-)

diff --git a/src/db/sysdb.c b/src/db/sysdb.c
index 6bbc6abb9b..f302a9ffef 100644
--- a/src/db/sysdb.c
+++ b/src/db/sysdb.c
@@ -1181,13 +1181,154 @@ errno_t sysdb_set_bool(struct sysdb_ctx *sysdb,
     return ret;
 }
 
+errno_t sysdb_get_uint(struct sysdb_ctx *sysdb,
+                       struct ldb_dn *dn,
+                       const char *attr_name,
+                       uint32_t *value)
+{
+    TALLOC_CTX *tmp_ctx;
+    struct ldb_result *res;
+    errno_t ret;
+    int lret;
+    const char *attrs[2] = {attr_name, NULL};
+    struct ldb_message_element *el;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        return ENOMEM;
+    }
+
+    lret = ldb_search(sysdb->ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE,
+                      attrs, NULL);
+    if (lret != LDB_SUCCESS) {
+        ret = sysdb_error_to_errno(lret);
+        goto done;
+    }
+
+    if (res->count == 0) {
+        /* This entry has not been populated in LDB
+         * This is a common case, as unlike LDAP,
+         * LDB does not need to have all of its parent
+         * objects actually exist.
+         * This object in the sysdb exists mostly just
+         * to contain this attribute.
+         */
+        *value = false;
+        ret = ENOENT;
+        goto done;
+    } else if (res->count != 1) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "Got more than one reply for base search!\n");
+        ret = EIO;
+        goto done;
+    }
+
+    el = ldb_msg_find_element(res->msgs[0], attr_name);
+    if (el == NULL || el->num_values == 0) {
+        ret = ENOENT;
+        goto done;
+    }
+
+    *value = ldb_msg_find_attr_as_uint(res->msgs[0], attr_name, false);
+
+    ret = EOK;
+
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
+errno_t sysdb_set_uint(struct sysdb_ctx *sysdb,
+                       struct ldb_dn *dn,
+                       const char *cn_value,
+                       const char *attr_name,
+                       uint32_t value)
+{
+    TALLOC_CTX *tmp_ctx = NULL;
+    struct ldb_message *msg = NULL;
+    struct ldb_result *res = NULL;
+    errno_t ret;
+    int lret;
+
+    if (dn == NULL || attr_name == NULL) {
+        return EINVAL;
+    }
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        return ENOMEM;
+    }
+
+    lret = ldb_search(sysdb->ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE,
+                      NULL, NULL);
+    if (lret != LDB_SUCCESS) {
+        ret = sysdb_error_to_errno(lret);
+        goto done;
+    }
+
+    msg = ldb_msg_new(tmp_ctx);
+    if (msg == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+    msg->dn = dn;
+
+    if (res->count == 0) {
+        if (cn_value == NULL) {
+            ret = ENOENT;
+            goto done;
+        }
+
+        lret = ldb_msg_add_string(msg, "cn", cn_value);
+        if (lret != LDB_SUCCESS) {
+            ret = sysdb_error_to_errno(lret);
+            goto done;
+        }
+    } else if (res->count != 1) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "Got more than one reply for base search!\n");
+        ret = EIO;
+        goto done;
+    } else {
+        lret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
+        if (lret != LDB_SUCCESS) {
+            ret = sysdb_error_to_errno(lret);
+            goto done;
+        }
+    }
+
+    lret = ldb_msg_add_fmt(msg, attr_name, "%u", value);
+    if (lret != LDB_SUCCESS) {
+        ret = sysdb_error_to_errno(lret);
+        goto done;
+    }
+
+    if (res->count) {
+        lret = ldb_modify(sysdb->ldb, msg);
+    } else {
+        lret = ldb_add(sysdb->ldb, msg);
+    }
+
+    if (lret != LDB_SUCCESS) {
+        DEBUG(SSSDBG_OP_FAILURE,
+              "ldb operation failed: [%s](%d)[%s]\n",
+              ldb_strerror(lret), lret, ldb_errstring(sysdb->ldb));
+    }
+    ret = sysdb_error_to_errno(lret);
+
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
 errno_t sysdb_has_enumerated(struct sss_domain_info *domain,
+                             uint32_t provider,
                              bool *has_enumerated)
 {
     errno_t ret;
     struct ldb_dn *dn;
     TALLOC_CTX *tmp_ctx;
-
+    uint32_t enumerated;
 
     tmp_ctx = talloc_new(NULL);
     if (!tmp_ctx) {
@@ -1201,8 +1342,14 @@ errno_t sysdb_has_enumerated(struct sss_domain_info *domain,
         goto done;
     }
 
-    ret = sysdb_get_bool(domain->sysdb, dn, SYSDB_HAS_ENUMERATED,
-                         has_enumerated);
+    ret = sysdb_get_uint(domain->sysdb, dn, SYSDB_HAS_ENUMERATED,
+                         &enumerated);
+
+    if (ret != EOK) {
+        return ret;
+    }
+
+    *has_enumerated = (enumerated & provider);
 
 done:
     talloc_free(tmp_ctx);
@@ -1210,11 +1357,13 @@ errno_t sysdb_has_enumerated(struct sss_domain_info *domain,
 }
 
 errno_t sysdb_set_enumerated(struct sss_domain_info *domain,
-                             bool enumerated)
+                             uint32_t provider,
+                             bool has_enumerated)
 {
     errno_t ret;
     TALLOC_CTX *tmp_ctx;
     struct ldb_dn *dn;
+    uint32_t enumerated = 0;
 
     tmp_ctx = talloc_new(NULL);
     if (!tmp_ctx) {
@@ -1228,7 +1377,20 @@ errno_t sysdb_set_enumerated(struct sss_domain_info *domain,
         goto done;
     }
 
-    ret = sysdb_set_bool(domain->sysdb, dn, domain->name,
+    ret = sysdb_get_uint(domain->sysdb, dn, SYSDB_HAS_ENUMERATED,
+                         &enumerated);
+
+    if (ret != EOK && ret != ENOENT) {
+        return ret;
+    }
+
+    if (has_enumerated) {
+        enumerated |= provider;
+    } else {
+        enumerated &= ~provider;
+    }
+
+    ret = sysdb_set_uint(domain->sysdb, dn, domain->name,
                          SYSDB_HAS_ENUMERATED, enumerated);
 
 done:
diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index c6a2389895..af86f6dce5 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -226,6 +226,7 @@
 #define SYSDB_USER_CERT_FILTER "(&("SYSDB_UC")%s)"
 
 #define SYSDB_HAS_ENUMERATED "has_enumerated"
+#define SYSDB_HAS_ENUMERATED_ID       0x00000001
 
 #define SYSDB_DEFAULT_ATTRS SYSDB_LAST_UPDATE, \
                             SYSDB_CACHE_EXPIRE, \
@@ -1284,11 +1285,24 @@ errno_t sysdb_set_bool(struct sysdb_ctx *sysdb,
                        const char *attr_name,
                        bool value);
 
+errno_t sysdb_get_uint(struct sysdb_ctx *sysdb,
+                       struct ldb_dn *dn,
+                       const char *attr_name,
+                       uint32_t *value);
+
+errno_t sysdb_set_uint(struct sysdb_ctx *sysdb,
+                       struct ldb_dn *dn,
+                       const char *cn_value,
+                       const char *attr_name,
+                       uint32_t value);
+
 errno_t sysdb_has_enumerated(struct sss_domain_info *domain,
+                             uint32_t provider,
                              bool *has_enumerated);
 
 errno_t sysdb_set_enumerated(struct sss_domain_info *domain,
-                             bool enumerated);
+                             uint32_t provider,
+                             bool has_enumerated);
 
 errno_t sysdb_remove_attrs(struct sss_domain_info *domain,
                            const char *name,
diff --git a/src/providers/ldap/ldap_id_enum.c b/src/providers/ldap/ldap_id_enum.c
index 009d9d275d..bbc2c14b39 100644
--- a/src/providers/ldap/ldap_id_enum.c
+++ b/src/providers/ldap/ldap_id_enum.c
@@ -43,7 +43,8 @@ errno_t ldap_setup_enumeration(struct be_ctx *be_ctx,
     bool has_enumerated;
     struct ldap_enum_ctx *ectx;
 
-    ret = sysdb_has_enumerated(sdom->dom, &has_enumerated);
+    ret = sysdb_has_enumerated(sdom->dom, SYSDB_HAS_ENUMERATED_ID,
+                               &has_enumerated);
     if (ret == ENOENT) {
         /* default value */
         has_enumerated = false;
diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c
index 899d59d383..a8b1286f30 100644
--- a/src/providers/ldap/sdap_async_enum.c
+++ b/src/providers/ldap/sdap_async_enum.c
@@ -372,7 +372,8 @@ static void sdap_dom_enum_ex_svcs_done(struct tevent_req *subreq)
      * process on the next SSSD service restart (to avoid
      * slowing down system boot-up
      */
-    ret = sysdb_set_enumerated(state->sdom->dom, true);
+    ret = sysdb_set_enumerated(state->sdom->dom, SYSDB_HAS_ENUMERATED_ID,
+                               true);
     if (ret != EOK) {
         DEBUG(SSSDBG_MINOR_FAILURE,
               "Could not mark domain as having enumerated.\n");
diff --git a/src/providers/ldap/sdap_reinit.c b/src/providers/ldap/sdap_reinit.c
index d5c896774f..1764ecd6ba 100644
--- a/src/providers/ldap/sdap_reinit.c
+++ b/src/providers/ldap/sdap_reinit.c
@@ -216,7 +216,7 @@ static void sdap_reinit_cleanup_done(struct tevent_req *subreq)
      * process on the next SSSD service restart (to avoid
      * slowing down system boot-up
      */
-    ret = sysdb_set_enumerated(state->domain, true);
+    ret = sysdb_set_enumerated(state->domain, SYSDB_HAS_ENUMERATED_ID, true);
     if (ret != EOK) {
         DEBUG(SSSDBG_MINOR_FAILURE, "Could not mark domain as having "
                                      "enumerated.\n");
diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
index 87f518baf4..338182de9e 100644
--- a/src/tests/sysdb-tests.c
+++ b/src/tests/sysdb-tests.c
@@ -3815,6 +3815,59 @@ START_TEST (test_sysdb_set_get_bool)
 }
 END_TEST
 
+
+START_TEST (test_sysdb_set_get_uint)
+{
+    struct sysdb_test_ctx *test_ctx;
+    struct ldb_dn *dn, *ne_dn;
+    uint32_t value;
+    int ret;
+    const char *attr_val = "UINT_VALUE";
+
+    /* Setup */
+    ret = setup_sysdb_tests(&test_ctx);
+    if (ret != EOK) {
+        fail("Could not set up the test");
+        return;
+    }
+
+    dn = sysdb_domain_dn(test_ctx, test_ctx->domain);
+    fail_unless(dn != NULL);
+
+    /* attribute is not created yet */
+    ret = sysdb_get_uint(test_ctx->sysdb, dn, attr_val,
+                         &value);
+    fail_unless(ret == ENOENT,
+                "sysdb_get_uint returned %d:[%s], but ENOENT is expected",
+                ret, sss_strerror(ret));
+
+    /* add attribute */
+    ret = sysdb_set_uint(test_ctx->sysdb, dn, test_ctx->domain->name,
+                         attr_val, 0xCAFEBABE);
+    fail_unless(ret == EOK);
+
+    /* successfully obtain attribute */
+    ret = sysdb_get_uint(test_ctx->sysdb, dn, attr_val,
+                         &value);
+    fail_unless(ret == EOK, "sysdb_get_uint failed %d:[%s]",
+                ret, sss_strerror(ret));
+    fail_unless(value == 0xCAFEBABE);
+
+    /* use non-existing DN */
+    ne_dn = ldb_dn_new_fmt(test_ctx, test_ctx->sysdb->ldb, SYSDB_DOM_BASE,
+                        "non-existing domain");
+    fail_unless(ne_dn != NULL);
+    ret = sysdb_get_uint(test_ctx->sysdb, ne_dn, attr_val,
+                         &value);
+    fail_unless(ret == ENOENT,
+                "sysdb_get_uint returned %d:[%s], but ENOENT is expected",
+                ret, sss_strerror(ret));
+
+    /* free ctx */
+    talloc_free(test_ctx);
+}
+END_TEST
+
 START_TEST (test_sysdb_attrs_to_list)
 {
     struct sysdb_attrs *attrs_list[3];
@@ -5652,17 +5705,20 @@ START_TEST(test_sysdb_has_enumerated)
     ret = setup_sysdb_tests(&test_ctx);
     fail_if(ret != EOK, "Could not set up the test");
 
-    ret = sysdb_has_enumerated(test_ctx->domain, &enumerated);
+    ret = sysdb_has_enumerated(test_ctx->domain, SYSDB_HAS_ENUMERATED_ID,
+                               &enumerated);
     fail_if(ret != ENOENT,
             "Error [%d][%s] checking enumeration ENOENT is expected",
             ret, strerror(ret));
 
-    ret = sysdb_set_enumerated(test_ctx->domain, true);
+    ret = sysdb_set_enumerated(test_ctx->domain, SYSDB_HAS_ENUMERATED_ID,
+                               true);
     fail_if(ret != EOK, "Error [%d][%s] setting enumeration",
                         ret, strerror(ret));
 
     /* Recheck enumeration status */
-    ret = sysdb_has_enumerated(test_ctx->domain, &enumerated);
+    ret = sysdb_has_enumerated(test_ctx->domain, SYSDB_HAS_ENUMERATED_ID,
+                               &enumerated);
     fail_if(ret != EOK, "Error [%d][%s] checking enumeration",
                         ret, strerror(ret));
 
@@ -7572,6 +7628,7 @@ Suite *create_sysdb_suite(void)
 
 /* ===== Misc ===== */
     tcase_add_test(tc_sysdb, test_sysdb_set_get_bool);
+    tcase_add_test(tc_sysdb, test_sysdb_set_get_uint);
     tcase_add_test(tc_sysdb, test_sysdb_mark_entry_as_expired_ldb_dn);
 
 /* Add all test cases to the test suite */

From 5f0d2c26b8beea91fcb57e367538c78fc75847f8 Mon Sep 17 00:00:00 2001
From: Samuel Cabrero <scabrero@suse.de>
Date: Fri, 12 Jul 2019 17:00:36 +0200
Subject: [PATCH 2/8] SDAP: Add provider name to enumeration and cleanup tasks

If multiple providers are enumerating it is convenient to add the
provider name to debug messages.

Signed-off-by: Samuel Cabrero <scabrero@suse.de>
---
 src/providers/ldap/ldap_id_cleanup.c |  2 +-
 src/providers/ldap/ldap_id_enum.c    | 11 ++++++++++-
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/src/providers/ldap/ldap_id_cleanup.c b/src/providers/ldap/ldap_id_cleanup.c
index a62060337c..cd6206ee90 100644
--- a/src/providers/ldap/ldap_id_cleanup.c
+++ b/src/providers/ldap/ldap_id_cleanup.c
@@ -80,7 +80,7 @@ errno_t ldap_setup_cleanup(struct sdap_id_ctx *id_ctx,
     cleanup_ctx->ctx = id_ctx;
     cleanup_ctx->sdom = sdom;
 
-    name = talloc_asprintf(cleanup_ctx, "Cleanup of %s", sdom->dom->name);
+    name = talloc_asprintf(cleanup_ctx, "Cleanup [id] of %s", sdom->dom->name);
     if (name == NULL) {
         return ENOMEM;
     }
diff --git a/src/providers/ldap/ldap_id_enum.c b/src/providers/ldap/ldap_id_enum.c
index bbc2c14b39..ab1704721a 100644
--- a/src/providers/ldap/ldap_id_enum.c
+++ b/src/providers/ldap/ldap_id_enum.c
@@ -42,6 +42,7 @@ errno_t ldap_setup_enumeration(struct be_ctx *be_ctx,
     time_t cleanup;
     bool has_enumerated;
     struct ldap_enum_ctx *ectx;
+    char *name = NULL;
 
     ret = sysdb_has_enumerated(sdom->dom, SYSDB_HAS_ENUMERATED_ID,
                                &has_enumerated);
@@ -93,6 +94,12 @@ errno_t ldap_setup_enumeration(struct be_ctx *be_ctx,
     ectx->sdom = sdom;
     ectx->pvt = pvt;
 
+    name = talloc_asprintf(NULL, "Enumeration [id] of %s",
+                           sdom->dom->name);
+    if (name == NULL) {
+        return ENOMEM;
+    }
+
     ret = be_ptask_create(sdom, be_ctx,
                           period,                   /* period */
                           first_delay,              /* first_delay */
@@ -101,7 +108,7 @@ errno_t ldap_setup_enumeration(struct be_ctx *be_ctx,
                           period,                   /* timeout */
                           0,                        /* max_backoff */
                           send_fn, recv_fn,
-                          ectx, "enumeration",
+                          ectx, name,
                           BE_PTASK_OFFLINE_SKIP | BE_PTASK_SCHEDULE_FROM_LAST,
                           &sdom->enum_task);
     if (ret != EOK) {
@@ -112,6 +119,8 @@ errno_t ldap_setup_enumeration(struct be_ctx *be_ctx,
     }
 
     talloc_steal(sdom->enum_task, ectx);
+    talloc_free(name);
+
     return EOK;
 }
 

From 949085a8537e6dac028ca4a02e6c4d2a35292dd3 Mon Sep 17 00:00:00 2001
From: Samuel Cabrero <scabrero@suse.de>
Date: Wed, 17 Jul 2019 12:20:18 +0200
Subject: [PATCH 3/8] LDAP: Return errno_t for ldap id enumeration task setup
 functions

Signed-off-by: Samuel Cabrero <scabrero@suse.de>
---
 src/providers/ldap/ldap_common.c | 14 +++++++-------
 src/providers/ldap/ldap_common.h | 14 +++++++-------
 2 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
index 5574fdc51d..afdf3e74fd 100644
--- a/src/providers/ldap/ldap_common.c
+++ b/src/providers/ldap/ldap_common.c
@@ -38,7 +38,7 @@
 /* a fd the child process would log into */
 int ldap_child_debug_fd = -1;
 
-int ldap_id_setup_tasks(struct sdap_id_ctx *ctx)
+errno_t ldap_id_setup_tasks(struct sdap_id_ctx *ctx)
 {
     return sdap_id_setup_tasks(ctx->be, ctx, ctx->opts->sdom,
                                ldap_enumeration_send,
@@ -46,12 +46,12 @@ int ldap_id_setup_tasks(struct sdap_id_ctx *ctx)
                                ctx);
 }
 
-int sdap_id_setup_tasks(struct be_ctx *be_ctx,
-                        struct sdap_id_ctx *ctx,
-                        struct sdap_domain *sdom,
-                        be_ptask_send_t send_fn,
-                        be_ptask_recv_t recv_fn,
-                        void *pvt)
+errno_t sdap_id_setup_tasks(struct be_ctx *be_ctx,
+                            struct sdap_id_ctx *ctx,
+                            struct sdap_domain *sdom,
+                            be_ptask_send_t send_fn,
+                            be_ptask_recv_t recv_fn,
+                            void *pvt)
 {
     int ret;
 
diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
index f91d420931..2ed455252f 100644
--- a/src/providers/ldap/ldap_common.h
+++ b/src/providers/ldap/ldap_common.h
@@ -108,13 +108,13 @@ errno_t sdap_account_info_handler_recv(TALLOC_CTX *mem_ctx,
                                        struct dp_reply_std *data);
 
 /* Set up enumeration and/or cleanup */
-int ldap_id_setup_tasks(struct sdap_id_ctx *ctx);
-int sdap_id_setup_tasks(struct be_ctx *be_ctx,
-                        struct sdap_id_ctx *ctx,
-                        struct sdap_domain *sdom,
-                        be_ptask_send_t send_fn,
-                        be_ptask_recv_t recv_fn,
-                        void *pvt);
+errno_t ldap_id_setup_tasks(struct sdap_id_ctx *ctx);
+errno_t sdap_id_setup_tasks(struct be_ctx *be_ctx,
+                            struct sdap_id_ctx *ctx,
+                            struct sdap_domain *sdom,
+                            be_ptask_send_t send_fn,
+                            be_ptask_recv_t recv_fn,
+                            void *pvt);
 
 /* Allow shortcutting an enumeration request */
 bool sdap_is_enum_request(struct dp_id_data *ar);

From 5e7d11c1141cb743c481d3d807bcce95ed88cf9a Mon Sep 17 00:00:00 2001
From: Samuel Cabrero <scabrero@suse.de>
Date: Wed, 17 Jul 2019 12:24:15 +0200
Subject: [PATCH 4/8] LDAP: Rename enumeration and cleanup functions to contain
 the provider

This way it is clearer these functions belong to ID provider enumeration
code.

Signed-off-by: Samuel Cabrero <scabrero@suse.de>
---
 src/providers/ipa/ipa_subdomains_server.c |  4 +--
 src/providers/ldap/ldap_common.c          | 10 +++----
 src/providers/ldap/ldap_common.h          | 32 +++++++++++------------
 src/providers/ldap/ldap_id_cleanup.c      |  4 +--
 src/providers/ldap/ldap_id_enum.c         | 24 ++++++++---------
 5 files changed, 37 insertions(+), 37 deletions(-)

diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c
index d0e89a4f96..08672b0860 100644
--- a/src/providers/ipa/ipa_subdomains_server.c
+++ b/src/providers/ipa/ipa_subdomains_server.c
@@ -380,8 +380,8 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx,
     ret = sdap_id_setup_tasks(be_ctx,
                               ad_id_ctx->sdap_id_ctx,
                               sdom,
-                              ldap_enumeration_send,
-                              ldap_enumeration_recv,
+                              ldap_id_enumeration_send,
+                              ldap_id_enumeration_recv,
                               ad_id_ctx->sdap_id_ctx);
     if (ret != EOK) {
         talloc_free(ad_options);
diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
index afdf3e74fd..8d38aeefc4 100644
--- a/src/providers/ldap/ldap_common.c
+++ b/src/providers/ldap/ldap_common.c
@@ -41,8 +41,8 @@ int ldap_child_debug_fd = -1;
 errno_t ldap_id_setup_tasks(struct sdap_id_ctx *ctx)
 {
     return sdap_id_setup_tasks(ctx->be, ctx, ctx->opts->sdom,
-                               ldap_enumeration_send,
-                               ldap_enumeration_recv,
+                               ldap_id_enumeration_send,
+                               ldap_id_enumeration_recv,
                                ctx);
 }
 
@@ -59,14 +59,14 @@ errno_t sdap_id_setup_tasks(struct be_ctx *be_ctx,
     if (sdom->dom->enumerate) {
         DEBUG(SSSDBG_TRACE_FUNC, "Setting up enumeration for %s\n",
                                   sdom->dom->name);
-        ret = ldap_setup_enumeration(be_ctx, ctx->opts, sdom,
-                                     send_fn, recv_fn, pvt);
+        ret = ldap_id_setup_enumeration(be_ctx, ctx->opts, sdom,
+                                        send_fn, recv_fn, pvt);
     } else {
         /* the enumeration task, runs the cleanup process by itself,
          * but if enumeration is not running we need to schedule it */
         DEBUG(SSSDBG_TRACE_FUNC, "Setting up cleanup task for %s\n",
                                   sdom->dom->name);
-        ret = ldap_setup_cleanup(ctx, sdom);
+        ret = ldap_id_setup_cleanup(ctx, sdom);
     }
 
     return ret;
diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
index 2ed455252f..43df4fb497 100644
--- a/src/providers/ldap/ldap_common.h
+++ b/src/providers/ldap/ldap_common.h
@@ -231,7 +231,7 @@ int ldap_get_autofs_options(TALLOC_CTX *memctx,
                             const char *conf_path,
                             struct sdap_options *opts);
 
-/* Calling ldap_setup_enumeration will set up a periodic task
+/* Calling ldap_id_setup_enumeration will set up a periodic task
  * that would periodically call send_fn/recv_fn request. The
  * send_fn's pvt parameter will be a pointer to ldap_enum_ctx
  * structure that contains the request data
@@ -241,22 +241,22 @@ struct ldap_enum_ctx {
     void *pvt;
 };
 
-errno_t ldap_setup_enumeration(struct be_ctx *be_ctx,
-                               struct sdap_options *opts,
-                               struct sdap_domain *sdom,
-                               be_ptask_send_t send_fn,
-                               be_ptask_recv_t recv_fn,
-                               void *pvt);
+errno_t ldap_id_setup_enumeration(struct be_ctx *be_ctx,
+                                  struct sdap_options *opts,
+                                  struct sdap_domain *sdom,
+                                  be_ptask_send_t send_fn,
+                                  be_ptask_recv_t recv_fn,
+                                  void *pvt);
 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);
-
-errno_t ldap_setup_cleanup(struct sdap_id_ctx *id_ctx,
-                           struct sdap_domain *sdom);
+ldap_id_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_id_enumeration_recv(struct tevent_req *req);
+
+errno_t ldap_id_setup_cleanup(struct sdap_id_ctx *id_ctx,
+                              struct sdap_domain *sdom);
 
 errno_t ldap_id_cleanup(struct sdap_options *opts,
                         struct sdap_domain *sdom);
diff --git a/src/providers/ldap/ldap_id_cleanup.c b/src/providers/ldap/ldap_id_cleanup.c
index cd6206ee90..a952aeb92f 100644
--- a/src/providers/ldap/ldap_id_cleanup.c
+++ b/src/providers/ldap/ldap_id_cleanup.c
@@ -50,8 +50,8 @@ static errno_t ldap_cleanup_task(TALLOC_CTX *mem_ctx,
     return ldap_id_cleanup(cleanup_ctx->ctx->opts, cleanup_ctx->sdom);
 }
 
-errno_t ldap_setup_cleanup(struct sdap_id_ctx *id_ctx,
-                           struct sdap_domain *sdom)
+errno_t ldap_id_setup_cleanup(struct sdap_id_ctx *id_ctx,
+                              struct sdap_domain *sdom)
 {
     errno_t ret;
     time_t first_delay;
diff --git a/src/providers/ldap/ldap_id_enum.c b/src/providers/ldap/ldap_id_enum.c
index ab1704721a..b1c2d5ef64 100644
--- a/src/providers/ldap/ldap_id_enum.c
+++ b/src/providers/ldap/ldap_id_enum.c
@@ -29,12 +29,12 @@
 
 #define LDAP_ENUM_PURGE_TIMEOUT 10800
 
-errno_t ldap_setup_enumeration(struct be_ctx *be_ctx,
-                               struct sdap_options *opts,
-                               struct sdap_domain *sdom,
-                               be_ptask_send_t send_fn,
-                               be_ptask_recv_t recv_fn,
-                               void *pvt)
+errno_t ldap_id_setup_enumeration(struct be_ctx *be_ctx,
+                                  struct sdap_options *opts,
+                                  struct sdap_domain *sdom,
+                                  be_ptask_send_t send_fn,
+                                  be_ptask_recv_t recv_fn,
+                                  void *pvt)
 {
     errno_t ret;
     time_t first_delay;
@@ -133,11 +133,11 @@ struct ldap_enumeration_state {
 static void ldap_enumeration_done(struct tevent_req *subreq);
 
 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)
+ldap_id_enumeration_send(TALLOC_CTX *mem_ctx,
+                         struct tevent_context *ev,
+                         struct be_ctx *be_ctx,
+                         struct be_ptask *be_ptask,
+                         void *pvt)
 {
     struct ldap_enumeration_state *state;
     struct tevent_req *req;
@@ -200,7 +200,7 @@ ldap_enumeration_done(struct tevent_req *subreq)
 }
 
 errno_t
-ldap_enumeration_recv(struct tevent_req *req)
+ldap_id_enumeration_recv(struct tevent_req *req)
 {
     TEVENT_REQ_RETURN_ON_ERROR(req);
 

From 8a66c93f7fe3a0d16a4b15bb7a4b02a32a8ec0be Mon Sep 17 00:00:00 2001
From: Samuel Cabrero <scabrero@suse.de>
Date: Wed, 17 Jul 2019 13:30:17 +0200
Subject: [PATCH 5/8] AD: Rename enumeration functions to contain the provider
 name

Makes clearer these functions belong to AD's ID provider enumeration
code.

Signed-off-by: Samuel Cabrero <scabrero@suse.de>
---
 src/providers/ad/ad_id.c   | 12 ++++++------
 src/providers/ad/ad_id.h   | 12 ++++++------
 src/providers/ad/ad_init.c |  2 +-
 3 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
index eb6e36824a..84e5c42acd 100644
--- a/src/providers/ad/ad_id.c
+++ b/src/providers/ad/ad_id.c
@@ -578,11 +578,11 @@ static errno_t ad_enum_sdom(struct tevent_req *req, struct sdap_domain *sd,
 static void ad_enumeration_done(struct tevent_req *subreq);
 
 struct tevent_req *
-ad_enumeration_send(TALLOC_CTX *mem_ctx,
-                    struct tevent_context *ev,
-                    struct be_ctx *be_ctx,
-                    struct be_ptask *be_ptask,
-                    void *pvt)
+ad_id_enumeration_send(TALLOC_CTX *mem_ctx,
+                       struct tevent_context *ev,
+                       struct be_ctx *be_ctx,
+                       struct be_ptask *be_ptask,
+                       void *pvt)
 {
     struct tevent_req *req;
     struct tevent_req *subreq;
@@ -1112,7 +1112,7 @@ ad_group_add_member(struct sdap_options *opts,
 }
 
 errno_t
-ad_enumeration_recv(struct tevent_req *req)
+ad_id_enumeration_recv(struct tevent_req *req)
 {
     TEVENT_REQ_RETURN_ON_ERROR(req);
     return EOK;
diff --git a/src/providers/ad/ad_id.h b/src/providers/ad/ad_id.h
index 19cc54eec9..d102643229 100644
--- a/src/providers/ad/ad_id.h
+++ b/src/providers/ad/ad_id.h
@@ -55,14 +55,14 @@ ad_handle_acct_info_recv(struct tevent_req *req,
                          int *_dp_error, const char **_err);
 
 struct tevent_req *
-ad_enumeration_send(TALLOC_CTX *mem_ctx,
-                    struct tevent_context *ev,
-                    struct be_ctx *be_ctx,
-                    struct be_ptask *be_ptask,
-                    void *pvt);
+ad_id_enumeration_send(TALLOC_CTX *mem_ctx,
+                       struct tevent_context *ev,
+                       struct be_ctx *be_ctx,
+                       struct be_ptask *be_ptask,
+                       void *pvt);
 
 errno_t
-ad_enumeration_recv(struct tevent_req *req);
+ad_id_enumeration_recv(struct tevent_req *req);
 
 struct tevent_req *
 ad_get_account_domain_send(TALLOC_CTX *mem_ctx,
diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
index 42c17de00f..290d5b5c1f 100644
--- a/src/providers/ad/ad_init.c
+++ b/src/providers/ad/ad_init.c
@@ -384,7 +384,7 @@ static errno_t ad_init_misc(struct be_ctx *be_ctx,
     }
 
     ret = sdap_id_setup_tasks(be_ctx, sdap_id_ctx, sdap_id_ctx->opts->sdom,
-                              ad_enumeration_send, ad_enumeration_recv,
+                              ad_id_enumeration_send, ad_id_enumeration_recv,
                               ad_id_ctx);
     if (ret != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup background tasks "

From 749ce63c6601586ab61a7afb76d0433cd6ece8ab Mon Sep 17 00:00:00 2001
From: Samuel Cabrero <scabrero@suse.de>
Date: Wed, 17 Jul 2019 13:54:27 +0200
Subject: [PATCH 6/8] LDAP: Improve ldap_id_setup_enumeration error logic

Signed-off-by: Samuel Cabrero <scabrero@suse.de>
---
 src/providers/ldap/ldap_id_enum.c | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/src/providers/ldap/ldap_id_enum.c b/src/providers/ldap/ldap_id_enum.c
index b1c2d5ef64..c9d67ec839 100644
--- a/src/providers/ldap/ldap_id_enum.c
+++ b/src/providers/ldap/ldap_id_enum.c
@@ -41,7 +41,7 @@ errno_t ldap_id_setup_enumeration(struct be_ctx *be_ctx,
     time_t period;
     time_t cleanup;
     bool has_enumerated;
-    struct ldap_enum_ctx *ectx;
+    struct ldap_enum_ctx *ectx = NULL;
     char *name = NULL;
 
     ret = sysdb_has_enumerated(sdom->dom, SYSDB_HAS_ENUMERATED_ID,
@@ -97,7 +97,8 @@ errno_t ldap_id_setup_enumeration(struct be_ctx *be_ctx,
     name = talloc_asprintf(NULL, "Enumeration [id] of %s",
                            sdom->dom->name);
     if (name == NULL) {
-        return ENOMEM;
+        ret = ENOMEM;
+        goto done;
     }
 
     ret = be_ptask_create(sdom, be_ctx,
@@ -114,14 +115,19 @@ errno_t ldap_id_setup_enumeration(struct be_ctx *be_ctx,
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE,
               "Unable to initialize enumeration periodic task\n");
-        talloc_free(ectx);
-        return ret;
+        goto done;
     }
 
     talloc_steal(sdom->enum_task, ectx);
-    talloc_free(name);
 
-    return EOK;
+    ret = EOK;
+
+done:
+    talloc_free(name);
+    if (ret != EOK) {
+        talloc_free(ectx);
+    }
+    return ret;
 }
 
 struct ldap_enumeration_state {

From 12afbe9ea9bfc1cab00b35ad3a902f860eda2a41 Mon Sep 17 00:00:00 2001
From: Samuel Cabrero <scabrero@suse.de>
Date: Wed, 17 Jul 2019 14:35:50 +0200
Subject: [PATCH 7/8] LDAP: Remove unnecessary task pointer

The cleanup and enumeration tasks of the id provider are never created
at the same time, only one task is started depending on the domain
'enumerate' value.

Signed-off-by: Samuel Cabrero <scabrero@suse.de>
---
 src/providers/ad/ad_subdomains.c          | 3 +--
 src/providers/ipa/ipa_subdomains_server.c | 3 +--
 src/providers/ldap/ldap_id_cleanup.c      | 4 ++--
 src/providers/ldap/ldap_id_enum.c         | 4 ++--
 src/providers/ldap/sdap.h                 | 3 +--
 5 files changed, 7 insertions(+), 10 deletions(-)

diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
index 36feafa2cc..feb02e5ec2 100644
--- a/src/providers/ad/ad_subdomains.c
+++ b/src/providers/ad/ad_subdomains.c
@@ -720,8 +720,7 @@ static errno_t ad_subdomains_refresh(struct be_ctx *be_ctx,
             /* Remove the subdomain from the list of LDAP domains */
             sdap_domain_remove(opts, dom);
 
-            be_ptask_destroy(&sdom->enum_task);
-            be_ptask_destroy(&sdom->cleanup_task);
+            be_ptask_destroy(&sdom->task);
 
             /* terminate all requests for this subdomain so we can free it */
             dp_terminate_domain_requests(be_ctx->provider, dom->name);
diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c
index 08672b0860..789b908284 100644
--- a/src/providers/ipa/ipa_subdomains_server.c
+++ b/src/providers/ipa/ipa_subdomains_server.c
@@ -1054,8 +1054,7 @@ void ipa_ad_subdom_remove(struct be_ctx *be_ctx,
 
     sdom = sdap_domain_get(iter->ad_id_ctx->sdap_id_ctx->opts, subdom);
     if (sdom == NULL) return;
-    be_ptask_destroy(&sdom->enum_task);
-    be_ptask_destroy(&sdom->cleanup_task);
+    be_ptask_destroy(&sdom->task);
 
     sdap_domain_remove(iter->ad_id_ctx->sdap_id_ctx->opts, subdom);
     DLIST_REMOVE(id_ctx->server_mode->trusts, iter);
diff --git a/src/providers/ldap/ldap_id_cleanup.c b/src/providers/ldap/ldap_id_cleanup.c
index a952aeb92f..b127ab084d 100644
--- a/src/providers/ldap/ldap_id_cleanup.c
+++ b/src/providers/ldap/ldap_id_cleanup.c
@@ -90,14 +90,14 @@ errno_t ldap_id_setup_cleanup(struct sdap_id_ctx *id_ctx,
                                period /* timeout */, 0,
                                ldap_cleanup_task, cleanup_ctx, name,
                                BE_PTASK_OFFLINE_SKIP,
-                               &sdom->cleanup_task);
+                               &sdom->task);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE, "Unable to initialize cleanup periodic "
                                      "task for %s\n", sdom->dom->name);
         goto done;
     }
 
-    talloc_steal(sdom->cleanup_task, cleanup_ctx);
+    talloc_steal(sdom->task, cleanup_ctx);
     ret = EOK;
 
 done:
diff --git a/src/providers/ldap/ldap_id_enum.c b/src/providers/ldap/ldap_id_enum.c
index c9d67ec839..3e13ed2cf9 100644
--- a/src/providers/ldap/ldap_id_enum.c
+++ b/src/providers/ldap/ldap_id_enum.c
@@ -111,14 +111,14 @@ errno_t ldap_id_setup_enumeration(struct be_ctx *be_ctx,
                           send_fn, recv_fn,
                           ectx, name,
                           BE_PTASK_OFFLINE_SKIP | BE_PTASK_SCHEDULE_FROM_LAST,
-                          &sdom->enum_task);
+                          &sdom->task);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE,
               "Unable to initialize enumeration periodic task\n");
         goto done;
     }
 
-    talloc_steal(sdom->enum_task, ectx);
+    talloc_steal(sdom->task, ectx);
 
     ret = EOK;
 
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index 1ae1f04e3a..4facccca65 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -431,8 +431,7 @@ struct sdap_domain {
     struct sdap_domain **head;
 
     /* Enumeration and cleanup periodic task */
-    struct be_ptask *enum_task;
-    struct be_ptask *cleanup_task;
+    struct be_ptask *task;
 
     /* enumeration loop timer */
     struct timeval last_enum;

From b633e8492e1e5e290ed937dbc5f847310ad630f2 Mon Sep 17 00:00:00 2001
From: Samuel Cabrero <scabrero@suse.de>
Date: Wed, 17 Jul 2019 18:53:58 +0200
Subject: [PATCH 8/8] LDAP: Move enum fields to id provider context

Move the enumeration-related struct members from "struct sdap_domain" to
"struct sdap_id_ctx". These fields are used by the ID provider
enumeration/cleanup tasks and other providers could also run enumeration
tasks.

Also use a talloc destructor to destroy the task as it is allocated in
the "struct sdap_id_ctx" context.

Signed-off-by: Samuel Cabrero <scabrero@suse.de>
---
 src/providers/ad/ad_subdomains.c          |  2 --
 src/providers/ipa/ipa_subdomains_server.c |  1 -
 src/providers/ldap/ldap_common.c          | 10 +++++++++-
 src/providers/ldap/ldap_common.h          | 14 ++++++++++++--
 src/providers/ldap/ldap_id_cleanup.c      | 13 ++++++-------
 src/providers/ldap/ldap_id_enum.c         | 14 ++++++--------
 src/providers/ldap/sdap.h                 |  8 --------
 src/providers/ldap/sdap_async_enum.c      |  6 +++---
 src/tests/cmocka/test_ldap_id_cleanup.c   | 10 ++++++++--
 9 files changed, 44 insertions(+), 34 deletions(-)

diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
index feb02e5ec2..2ce34489f6 100644
--- a/src/providers/ad/ad_subdomains.c
+++ b/src/providers/ad/ad_subdomains.c
@@ -720,8 +720,6 @@ static errno_t ad_subdomains_refresh(struct be_ctx *be_ctx,
             /* Remove the subdomain from the list of LDAP domains */
             sdap_domain_remove(opts, dom);
 
-            be_ptask_destroy(&sdom->task);
-
             /* terminate all requests for this subdomain so we can free it */
             dp_terminate_domain_requests(be_ctx->provider, dom->name);
             talloc_zfree(sdom);
diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c
index 789b908284..fd998877b3 100644
--- a/src/providers/ipa/ipa_subdomains_server.c
+++ b/src/providers/ipa/ipa_subdomains_server.c
@@ -1054,7 +1054,6 @@ void ipa_ad_subdom_remove(struct be_ctx *be_ctx,
 
     sdom = sdap_domain_get(iter->ad_id_ctx->sdap_id_ctx->opts, subdom);
     if (sdom == NULL) return;
-    be_ptask_destroy(&sdom->task);
 
     sdap_domain_remove(iter->ad_id_ctx->sdap_id_ctx->opts, subdom);
     DLIST_REMOVE(id_ctx->server_mode->trusts, iter);
diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
index 8d38aeefc4..b579ca1896 100644
--- a/src/providers/ldap/ldap_common.c
+++ b/src/providers/ldap/ldap_common.c
@@ -59,7 +59,7 @@ errno_t sdap_id_setup_tasks(struct be_ctx *be_ctx,
     if (sdom->dom->enumerate) {
         DEBUG(SSSDBG_TRACE_FUNC, "Setting up enumeration for %s\n",
                                   sdom->dom->name);
-        ret = ldap_id_setup_enumeration(be_ctx, ctx->opts, sdom,
+        ret = ldap_id_setup_enumeration(be_ctx, ctx, sdom,
                                         send_fn, recv_fn, pvt);
     } else {
         /* the enumeration task, runs the cleanup process by itself,
@@ -838,6 +838,12 @@ sdap_id_ctx_conn_add(struct sdap_id_ctx *id_ctx,
     return conn;
 }
 
+static int sdap_id_ctx_destructor(struct sdap_id_ctx *id_ctx)
+{
+    be_ptask_destroy(&id_ctx->task);
+    return 0;
+}
+
 struct sdap_id_ctx *
 sdap_id_ctx_new(TALLOC_CTX *mem_ctx, struct be_ctx *bectx,
                 struct sdap_service *sdap_service)
@@ -848,6 +854,8 @@ sdap_id_ctx_new(TALLOC_CTX *mem_ctx, struct be_ctx *bectx,
     if (sdap_ctx == NULL) {
         return NULL;
     }
+    talloc_set_destructor(sdap_ctx, sdap_id_ctx_destructor);
+
     sdap_ctx->be = bectx;
 
     /* There should be at least one connection context */
diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
index 43df4fb497..ac2c5d33e8 100644
--- a/src/providers/ldap/ldap_common.h
+++ b/src/providers/ldap/ldap_common.h
@@ -71,6 +71,16 @@ struct sdap_id_ctx {
     struct sdap_id_conn_ctx *conn;
 
     struct sdap_server_opts *srv_opts;
+
+    /* Enumeration/cleanup periodic task. Only the enumeration or the cleanup
+     * task is started depending on the value of the domain's enumeration
+     * setting, this is why there is only one task pointer for both tasks. */
+    struct be_ptask *task;
+
+    /* enumeration loop timer */
+    struct timeval last_enum;
+    /* cleanup loop timer */
+    struct timeval last_purge;
 };
 
 struct sdap_auth_ctx {
@@ -242,7 +252,7 @@ struct ldap_enum_ctx {
 };
 
 errno_t ldap_id_setup_enumeration(struct be_ctx *be_ctx,
-                                  struct sdap_options *opts,
+                                  struct sdap_id_ctx *id_ctx,
                                   struct sdap_domain *sdom,
                                   be_ptask_send_t send_fn,
                                   be_ptask_recv_t recv_fn,
@@ -258,7 +268,7 @@ errno_t ldap_id_enumeration_recv(struct tevent_req *req);
 errno_t ldap_id_setup_cleanup(struct sdap_id_ctx *id_ctx,
                               struct sdap_domain *sdom);
 
-errno_t ldap_id_cleanup(struct sdap_options *opts,
+errno_t ldap_id_cleanup(struct sdap_id_ctx *id_ctx,
                         struct sdap_domain *sdom);
 
 struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
diff --git a/src/providers/ldap/ldap_id_cleanup.c b/src/providers/ldap/ldap_id_cleanup.c
index b127ab084d..b6aece9989 100644
--- a/src/providers/ldap/ldap_id_cleanup.c
+++ b/src/providers/ldap/ldap_id_cleanup.c
@@ -47,7 +47,7 @@ static errno_t ldap_cleanup_task(TALLOC_CTX *mem_ctx,
     struct ldap_id_cleanup_ctx *cleanup_ctx = NULL;
 
     cleanup_ctx = talloc_get_type(pvt, struct ldap_id_cleanup_ctx);
-    return ldap_id_cleanup(cleanup_ctx->ctx->opts, cleanup_ctx->sdom);
+    return ldap_id_cleanup(cleanup_ctx->ctx, cleanup_ctx->sdom);
 }
 
 errno_t ldap_id_setup_cleanup(struct sdap_id_ctx *id_ctx,
@@ -85,19 +85,18 @@ errno_t ldap_id_setup_cleanup(struct sdap_id_ctx *id_ctx,
         return ENOMEM;
     }
 
-    ret = be_ptask_create_sync(sdom, id_ctx->be, period, first_delay,
+    ret = be_ptask_create_sync(id_ctx, id_ctx->be, period, first_delay,
                                5 /* enabled delay */, 0 /* random offset */,
                                period /* timeout */, 0,
                                ldap_cleanup_task, cleanup_ctx, name,
                                BE_PTASK_OFFLINE_SKIP,
-                               &sdom->task);
+                               &id_ctx->task);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE, "Unable to initialize cleanup periodic "
                                      "task for %s\n", sdom->dom->name);
         goto done;
     }
 
-    talloc_steal(sdom->task, cleanup_ctx);
     ret = EOK;
 
 done:
@@ -115,7 +114,7 @@ static int cleanup_groups(TALLOC_CTX *memctx,
                           struct sysdb_ctx *sysdb,
                           struct sss_domain_info *domain);
 
-errno_t ldap_id_cleanup(struct sdap_options *opts,
+errno_t ldap_id_cleanup(struct sdap_id_ctx *ctx,
                         struct sdap_domain *sdom)
 {
     int ret, tret;
@@ -134,7 +133,7 @@ errno_t ldap_id_cleanup(struct sdap_options *opts,
     }
     in_transaction = true;
 
-    ret = cleanup_users(opts, sdom->dom);
+    ret = cleanup_users(ctx->opts, sdom->dom);
     if (ret && ret != ENOENT) {
         goto done;
     }
@@ -151,7 +150,7 @@ errno_t ldap_id_cleanup(struct sdap_options *opts,
     }
     in_transaction = false;
 
-    sdom->last_purge = tevent_timeval_current();
+    ctx->last_purge = tevent_timeval_current();
     ret = EOK;
 done:
     if (in_transaction) {
diff --git a/src/providers/ldap/ldap_id_enum.c b/src/providers/ldap/ldap_id_enum.c
index 3e13ed2cf9..a1e53ace66 100644
--- a/src/providers/ldap/ldap_id_enum.c
+++ b/src/providers/ldap/ldap_id_enum.c
@@ -30,7 +30,7 @@
 #define LDAP_ENUM_PURGE_TIMEOUT 10800
 
 errno_t ldap_id_setup_enumeration(struct be_ctx *be_ctx,
-                                  struct sdap_options *opts,
+                                  struct sdap_id_ctx *id_ctx,
                                   struct sdap_domain *sdom,
                                   be_ptask_send_t send_fn,
                                   be_ptask_recv_t recv_fn,
@@ -69,13 +69,13 @@ errno_t ldap_id_setup_enumeration(struct be_ctx *be_ctx,
         first_delay = 0;
     }
 
-    cleanup = dp_opt_get_int(opts->basic, SDAP_PURGE_CACHE_TIMEOUT);
+    cleanup = dp_opt_get_int(id_ctx->opts->basic, SDAP_PURGE_CACHE_TIMEOUT);
     if (cleanup == 0) {
         /* We need to cleanup the cache once in a while when enumerating, otherwise
          * enumeration would only download deltas since the previous lastUSN and would
          * not detect removed entries
          */
-        ret = dp_opt_set_int(opts->basic, SDAP_PURGE_CACHE_TIMEOUT,
+        ret = dp_opt_set_int(id_ctx->opts->basic, SDAP_PURGE_CACHE_TIMEOUT,
                              LDAP_ENUM_PURGE_TIMEOUT);
         if (ret != EOK) {
             DEBUG(SSSDBG_CRIT_FAILURE,
@@ -85,7 +85,7 @@ errno_t ldap_id_setup_enumeration(struct be_ctx *be_ctx,
         }
     }
 
-    period = dp_opt_get_int(opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
+    period = dp_opt_get_int(id_ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
 
     ectx = talloc(sdom, struct ldap_enum_ctx);
     if (ectx == NULL) {
@@ -101,7 +101,7 @@ errno_t ldap_id_setup_enumeration(struct be_ctx *be_ctx,
         goto done;
     }
 
-    ret = be_ptask_create(sdom, be_ctx,
+    ret = be_ptask_create(id_ctx, be_ctx,
                           period,                   /* period */
                           first_delay,              /* first_delay */
                           5,                        /* enabled delay */
@@ -111,15 +111,13 @@ errno_t ldap_id_setup_enumeration(struct be_ctx *be_ctx,
                           send_fn, recv_fn,
                           ectx, name,
                           BE_PTASK_OFFLINE_SKIP | BE_PTASK_SCHEDULE_FROM_LAST,
-                          &sdom->task);
+                          &id_ctx->task);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE,
               "Unable to initialize enumeration periodic task\n");
         goto done;
     }
 
-    talloc_steal(sdom->task, ectx);
-
     ret = EOK;
 
 done:
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index 4facccca65..8b2d3f0163 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -430,14 +430,6 @@ struct sdap_domain {
     /* Need to modify the list from a talloc destructor */
     struct sdap_domain **head;
 
-    /* Enumeration and cleanup periodic task */
-    struct be_ptask *task;
-
-    /* enumeration loop timer */
-    struct timeval last_enum;
-    /* cleanup loop timer */
-    struct timeval last_purge;
-
     void *pvt;
 };
 
diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c
index a8b1286f30..2a12e59b74 100644
--- a/src/providers/ldap/sdap_async_enum.c
+++ b/src/providers/ldap/sdap_async_enum.c
@@ -98,10 +98,10 @@ sdap_dom_enum_ex_send(TALLOC_CTX *memctx,
     state->user_conn = user_conn;
     state->group_conn = group_conn;
     state->svc_conn = svc_conn;
-    sdom->last_enum = tevent_timeval_current();
+    ctx->last_enum = tevent_timeval_current();
 
     t = dp_opt_get_int(ctx->opts->basic, SDAP_PURGE_CACHE_TIMEOUT);
-    if ((sdom->last_purge.tv_sec + t) < sdom->last_enum.tv_sec) {
+    if ((ctx->last_purge.tv_sec + t) < ctx->last_enum.tv_sec) {
         state->purge = true;
     }
 
@@ -381,7 +381,7 @@ static void sdap_dom_enum_ex_svcs_done(struct tevent_req *subreq)
     }
 
     if (state->purge) {
-        ret = ldap_id_cleanup(state->ctx->opts, state->sdom);
+        ret = ldap_id_cleanup(state->ctx, state->sdom);
         if (ret != EOK) {
             /* Not fatal, worst case we'll have stale entries that would be
              * removed on a subsequent online lookup
diff --git a/src/tests/cmocka/test_ldap_id_cleanup.c b/src/tests/cmocka/test_ldap_id_cleanup.c
index d8956f2c80..40030cd529 100644
--- a/src/tests/cmocka/test_ldap_id_cleanup.c
+++ b/src/tests/cmocka/test_ldap_id_cleanup.c
@@ -45,6 +45,7 @@ struct sysdb_test_ctx {
     struct tevent_context *ev;
     struct sss_domain_info *domain;
     struct sdap_options *opts;
+    struct sdap_id_ctx *id_ctx;
 };
 
 static int _setup_sysdb_tests(struct sysdb_test_ctx **ctx, bool enumerate)
@@ -102,6 +103,9 @@ static int _setup_sysdb_tests(struct sysdb_test_ctx **ctx, bool enumerate)
                            TESTS_PATH, &test_ctx->domain);
     assert_int_equal(ret, EOK);
 
+    test_ctx->id_ctx = talloc_zero(test_ctx, struct sdap_id_ctx);
+    assert_non_null(test_ctx->id_ctx);
+
     test_ctx->domain->has_views = true;
     test_ctx->sysdb = test_ctx->domain->sysdb;
 
@@ -137,6 +141,8 @@ static int test_sysdb_setup(void **state)
 
     dp_opt_set_int(test_ctx->opts->basic, SDAP_ACCOUNT_CACHE_EXPIRATION, 1);
 
+    test_ctx->id_ctx->opts = test_ctx->opts;
+
     *state = (void *) test_ctx;
     return 0;
 }
@@ -249,7 +255,7 @@ static void test_id_cleanup_exp_group(void **state)
     sdom.dom = test_ctx->domain;
 
     /* not expired */
-    ret = ldap_id_cleanup(test_ctx->opts, &sdom);
+    ret = ldap_id_cleanup(test_ctx->id_ctx, &sdom);
     assert_int_equal(ret, EOK);
 
     ret = sysdb_search_group_by_name(test_ctx, test_ctx->domain,
@@ -274,7 +280,7 @@ static void test_id_cleanup_exp_group(void **state)
     invalidate_group(test_ctx, test_ctx->domain, grp);
     invalidate_group(test_ctx, test_ctx->domain, empty_grp);
 
-    ret = ldap_id_cleanup(test_ctx->opts, &sdom);
+    ret = ldap_id_cleanup(test_ctx->id_ctx, &sdom);
     assert_int_equal(ret, EOK);
 
     ret = sysdb_search_group_by_name(test_ctx, test_ctx->domain,
