summaryrefslogtreecommitdiff
path: root/src/providers
diff options
context:
space:
mode:
Diffstat (limited to 'src/providers')
-rw-r--r--src/providers/ldap/ldap_common.h5
-rw-r--r--src/providers/ldap/ldap_id_enum.c637
-rw-r--r--src/providers/ldap/sdap.h3
-rw-r--r--src/providers/ldap/sdap_async_enum.c687
-rw-r--r--src/providers/ldap/sdap_async_enum.h38
-rw-r--r--src/providers/ldap/sdap_reinit.c13
6 files changed, 741 insertions, 642 deletions
diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
index db2466ad..c9b2f663 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 7d9ff3be..43eb4c99 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 6d24982b..f5f6d90a 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/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c
new file mode 100644
index 00000000..ab6ae077
--- /dev/null
+++ b/src/providers/ldap/sdap_async_enum.c
@@ -0,0 +1,687 @@
+/*
+ SSSD
+
+ LDAP Enumeration Module
+
+ Authors:
+ Simo Sorce <ssorce@redhat.com>
+ Jakub Hrozek <jhrozek@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/>.
+*/
+
+#include <errno.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"
+
+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,
+ struct sdap_domain *sdom,
+ struct sdap_id_op *op,
+ bool purge);
+static errno_t enum_users_recv(struct tevent_req *req);
+
+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);
+
+/* ==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 tevent_req *req;
+ struct sdap_dom_enum_state *state;
+ int t;
+ errno_t ret;
+
+ 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(SSSDBG_CRIT_FAILURE, ("sdap_id_op_create failed\n"));
+ ret = EIO;
+ goto fail;
+ }
+
+ 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) {
+ state->purge = true;
+ }
+
+ ret = sdap_dom_enum_retry(req);
+ if (ret != EOK) {
+ 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 errno_t sdap_dom_enum_retry(struct tevent_req *req)
+{
+ struct sdap_dom_enum_state *state = tevent_req_data(req,
+ struct sdap_dom_enum_state);
+ struct tevent_req *subreq;
+ errno_t ret;
+
+ subreq = sdap_id_op_connect_send(state->op, state, &ret);
+ if (subreq == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ ("sdap_id_op_connect_send failed: %d\n", ret));
+ return ret;
+ }
+
+ tevent_req_set_callback(subreq, sdap_dom_enum_conn_done, req);
+ return EOK;
+}
+
+static void sdap_dom_enum_conn_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct sdap_dom_enum_state *state = tevent_req_data(req,
+ struct sdap_dom_enum_state);
+ 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(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->sdom,
+ state->op, state->purge);
+ if (subreq == NULL) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(subreq, sdap_dom_enum_users_done, req);
+}
+
+static void sdap_dom_enum_users_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct sdap_dom_enum_state *state = tevent_req_data(req,
+ struct sdap_dom_enum_state);
+ uint64_t err = 0;
+ int ret, dp_error = DP_ERR_FATAL;
+
+ 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 = sdap_dom_enum_retry(req);
+ if (ret == EOK) {
+ return;
+ }
+
+ dp_error = DP_ERR_FATAL;
+ }
+
+ if (dp_error == DP_ERR_OFFLINE) {
+ tevent_req_done(req);
+ } else {
+ DEBUG(SSSDBG_OP_FAILURE,
+ ("User enumeration failed with: (%d)[%s]\n",
+ ret, strerror(ret)));
+ tevent_req_error(req, ret);
+ }
+ return;
+ }
+
+ subreq = enum_groups_send(state, state->ev, state->ctx,
+ state->sdom,
+ state->op, state->purge);
+ if (subreq == NULL) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(subreq, sdap_dom_enum_groups_done, req);
+}
+
+static void sdap_dom_enum_groups_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct sdap_dom_enum_state *state = tevent_req_data(req,
+ struct sdap_dom_enum_state);
+ uint64_t err = 0;
+ int ret, dp_error = DP_ERR_FATAL;
+
+ 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 = sdap_dom_enum_retry(req);
+ if (ret == EOK) {
+ return;
+ }
+
+ dp_error = DP_ERR_FATAL;
+ }
+
+ if (ret != EOK) {
+ if (dp_error == DP_ERR_OFFLINE) {
+ tevent_req_done(req);
+ } else {
+ DEBUG(SSSDBG_OP_FAILURE,
+ ("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, sdap_dom_enum_services_done, req);
+}
+
+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 sdap_dom_enum_state *state = tevent_req_data(req,
+ struct sdap_dom_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 = sdap_dom_enum_retry(req);
+ if (ret == EOK) {
+ return;
+ }
+
+ dp_error = DP_ERR_FATAL;
+ }
+
+ if (ret != EOK) {
+ if (dp_error == DP_ERR_OFFLINE) {
+ tevent_req_done(req);
+ } else {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ ("Service enumeration failed with: (%d)[%s]\n",
+ ret, strerror(ret)));
+ tevent_req_error(req, ret);
+ }
+
+ 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, 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);
+
+ return EOK;
+}
+
+/* ==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_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_done, req);
+
+ return req;
+
+fail:
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void enum_users_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_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_done, req);
+
+ return req;
+
+fail:
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void enum_groups_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_async_enum.h b/src/providers/ldap/sdap_async_enum.h
new file mode 100644
index 00000000..04ec8c6d
--- /dev/null
+++ b/src/providers/ldap/sdap_async_enum.h
@@ -0,0 +1,38 @@
+/*
+ SSSD
+
+ LDAP Enumeration Module
+
+ Authors:
+ Simo Sorce <ssorce@redhat.com>
+ Jakub Hrozek <jhrozek@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 b273c1a6..d7b50bbb 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;
}