From e81deec535d11912b87954c81a1edd768c1386c9 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Feb 12 2014 14:26:27 +0000 Subject: LDAP: Detect the presence of POSIX attributes When the schema is set to AD and ID mapping is not used, there is a one-time check ran when searching for users to detect the presence of POSIX attributes in LDAP. If this check fails, the search fails as if no entry was found and returns a special error code. The sdap_server_opts structure is filled every time a client connects to a server so the posix check boolean is reset to false again on connecting to the server. It might be better to move the check to where the rootDSE is retrieved, but the check depends on several features that are not known to the code that retrieves the rootDSE (or the connection code for example) such as what the attribute mappings are or the authentication method that should be used. Reviewed-by: Sumit Bose Reviewed-by: Pavel Březina --- diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c index db921b1..9e748a2 100644 --- a/src/providers/ad/ad_id.c +++ b/src/providers/ad/ad_id.c @@ -27,6 +27,28 @@ #include "providers/ldap/sdap_async_enum.h" #include "providers/ldap/sdap_idmap.h" +static void +disable_gc(struct ad_options *ad_options) +{ + errno_t ret; + + if (dp_opt_get_bool(ad_options->basic, AD_ENABLE_GC) == false) { + return; + } + + DEBUG(SSSDBG_IMPORTANT_INFO, ("POSIX attributes were requested " + "but are not present on the server side. Global Catalog " + "lookups will be disabled\n")); + + ret = dp_opt_set_bool(ad_options->basic, + AD_ENABLE_GC, false); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, + ("Could not turn off GC support\n")); + /* Not fatal */ + } +} + struct ad_handle_acct_info_state { struct be_req *breq; struct be_acct_req *ar; @@ -34,6 +56,7 @@ struct ad_handle_acct_info_state { struct sdap_id_conn_ctx **conn; struct sdap_domain *sdom; size_t cindex; + struct ad_options *ad_options; int dp_error; const char *err; @@ -47,6 +70,7 @@ ad_handle_acct_info_send(TALLOC_CTX *mem_ctx, struct be_req *breq, struct be_acct_req *ar, struct sdap_id_ctx *ctx, + struct ad_options *ad_options, struct sdap_domain *sdom, struct sdap_id_conn_ctx **conn) { @@ -64,6 +88,7 @@ ad_handle_acct_info_send(TALLOC_CTX *mem_ctx, state->ctx = ctx; state->sdom = sdom; state->conn = conn; + state->ad_options = ad_options; state->cindex = 0; ret = ad_handle_acct_info_step(req); @@ -137,12 +162,14 @@ ad_handle_acct_info_done(struct tevent_req *subreq) if (sdap_err == EOK) { tevent_req_done(req); return; + } else if (sdap_err == ERR_NO_POSIX) { + disable_gc(state->ad_options); } else if (sdap_err != ENOENT) { tevent_req_error(req, EIO); return; } - /* Ret is only ENOENT now. Try the next connection */ + /* Ret is only ENOENT or ERR_NO_POSIX now. Try the next connection */ state->cindex++; ret = ad_handle_acct_info_step(req); if (ret != EAGAIN) { @@ -356,7 +383,7 @@ ad_account_info_handler(struct be_req *be_req) } req = ad_handle_acct_info_send(be_req, be_req, ar, sdap_id_ctx, - sdom, clist); + ad_ctx->ad_options, sdom, clist); if (req == NULL) { ret = ENOMEM; goto fail; @@ -611,9 +638,24 @@ ad_enumeration_done(struct tevent_req *subreq) ret = sdap_dom_enum_ex_recv(subreq); talloc_zfree(subreq); - if (ret != EOK) { + if (ret == ERR_NO_POSIX) { + /* Retry enumerating the same domain again, this time w/o + * connecting to GC + */ + disable_gc(state->id_ctx->ad_options); + ret = ad_enum_sdom(req, state->sditer, state->id_ctx); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + ("Could not retry domain %s\n", state->sditer->dom->name)); + tevent_req_error(req, ret); + return; + } + + /* Execution will resume in ad_enumeration_done */ + return; + } else if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, - ("Could not enumerate domain %s\n", state->sdom->dom->name)); + ("Could not enumerate domain %s\n", state->sditer->dom->name)); tevent_req_error(req, ret); return; } diff --git a/src/providers/ad/ad_id.h b/src/providers/ad/ad_id.h index 74b8564..9eb0ac3 100644 --- a/src/providers/ad/ad_id.h +++ b/src/providers/ad/ad_id.h @@ -31,6 +31,7 @@ ad_handle_acct_info_send(TALLOC_CTX *mem_ctx, struct be_req *breq, struct be_acct_req *ar, struct sdap_id_ctx *ctx, + struct ad_options *ad_options, struct sdap_domain *sdom, struct sdap_id_conn_ctx **conn); errno_t diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c index 4c70545..91e0f29 100644 --- a/src/providers/ipa/ipa_subdomains_id.c +++ b/src/providers/ipa/ipa_subdomains_id.c @@ -323,7 +323,7 @@ ipa_get_ad_acct_send(TALLOC_CTX *mem_ctx, } subreq = ad_handle_acct_info_send(req, be_req, ar, sdap_id_ctx, - sdom, clist); + ad_id_ctx->ad_options, sdom, clist); if (subreq == NULL) { ret = ENOMEM; goto fail; diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c index 422a3b9..dd34c85 100644 --- a/src/providers/ldap/ldap_id.c +++ b/src/providers/ldap/ldap_id.c @@ -50,6 +50,7 @@ struct users_get_state { char *filter; const char **attrs; + bool use_id_mapping; int dp_error; int sdap_ret; @@ -58,6 +59,8 @@ struct users_get_state { static int users_get_retry(struct tevent_req *req); static void users_get_connect_done(struct tevent_req *subreq); +static void users_get_posix_check_done(struct tevent_req *subreq); +static void users_get_search(struct tevent_req *req); static void users_get_done(struct tevent_req *subreq); struct tevent_req *users_get_send(TALLOC_CTX *memctx, @@ -79,7 +82,6 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, uid_t uid; enum idmap_error_code err; char *sid; - bool use_id_mapping; req = tevent_req_create(memctx, &state, struct users_get_state); if (!req) return NULL; @@ -103,7 +105,7 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, state->name = name; state->filter_type = filter_type; - use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping( + state->use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping( ctx->opts->idmap_ctx, sdom->dom->name, sdom->dom->domain_id); @@ -116,7 +118,7 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, } break; case BE_FILTER_IDNUM: - if (use_id_mapping) { + if (state->use_id_mapping) { /* If we're ID-mapping, we need to use the objectSID * in the search filter. */ @@ -183,7 +185,7 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, goto fail; } - if (use_id_mapping || filter_type == BE_FILTER_SECID) { + if (state->use_id_mapping || filter_type == BE_FILTER_SECID) { /* When mapping IDs or looking for SIDs, we don't want to limit * ourselves to users with a UID value. But there must be a SID to map * from. @@ -268,6 +270,75 @@ static void users_get_connect_done(struct tevent_req *subreq) return; } + /* If POSIX attributes have been requested with an AD server and we + * have no idea about POSIX attributes support, run a one-time check + */ + if (state->use_id_mapping == false && + state->ctx->opts->schema_type == SDAP_SCHEMA_AD && + state->ctx->srv_opts && + state->ctx->srv_opts->posix_checked == false) { + subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts, + sdap_id_op_handle(state->op), + state->sdom->user_search_bases, + dp_opt_get_int(state->ctx->opts->basic, + SDAP_SEARCH_TIMEOUT)); + if (subreq == NULL) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, users_get_posix_check_done, req); + return; + } + + users_get_search(req); +} + +static void users_get_posix_check_done(struct tevent_req *subreq) +{ + errno_t ret; + bool has_posix; + int dp_error; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct users_get_state *state = tevent_req_data(req, + struct users_get_state); + + ret = sdap_posix_check_recv(subreq, &has_posix); + talloc_zfree(subreq); + if (ret != EOK) { + /* We can only finish the id_op on error as the connection + * is re-used by the user search + */ + ret = sdap_id_op_done(state->op, ret, &dp_error); + if (dp_error == DP_ERR_OK && ret != EOK) { + /* retry */ + ret = users_get_retry(req); + if (ret != EOK) { + tevent_req_error(req, ret); + } + return; + } + } + + state->ctx->srv_opts->posix_checked = true; + + /* If the check ran to completion, we know for certain about the attributes + */ + if (has_posix == false) { + state->sdap_ret = ERR_NO_POSIX; + tevent_req_done(req); + return; + } + + users_get_search(req); +} + +static void users_get_search(struct tevent_req *req) +{ + struct users_get_state *state = tevent_req_data(req, + struct users_get_state); + struct tevent_req *subreq; + subreq = sdap_get_users_send(state, state->ev, state->domain, state->sysdb, state->ctx->opts, @@ -431,6 +502,7 @@ struct groups_get_state { char *filter; const char **attrs; + bool use_id_mapping; int dp_error; int sdap_ret; @@ -439,6 +511,8 @@ struct groups_get_state { static int groups_get_retry(struct tevent_req *req); static void groups_get_connect_done(struct tevent_req *subreq); +static void groups_get_posix_check_done(struct tevent_req *subreq); +static void groups_get_search(struct tevent_req *req); static void groups_get_done(struct tevent_req *subreq); struct tevent_req *groups_get_send(TALLOC_CTX *memctx, @@ -460,7 +534,6 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx, gid_t gid; enum idmap_error_code err; char *sid; - bool use_id_mapping; const char *member_filter[2]; req = tevent_req_create(memctx, &state, struct groups_get_state); @@ -485,7 +558,7 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx, state->name = name; state->filter_type = filter_type; - use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping( + state->use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping( ctx->opts->idmap_ctx, sdom->dom->name, sdom->dom->domain_id); @@ -500,7 +573,7 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx, } break; case BE_FILTER_IDNUM: - if (use_id_mapping) { + if (state->use_id_mapping) { /* If we're ID-mapping, we need to use the objectSID * in the search filter. */ @@ -567,7 +640,7 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx, goto fail; } - if (use_id_mapping || filter_type == BE_FILTER_SECID) { + if (state->use_id_mapping || filter_type == BE_FILTER_SECID) { /* When mapping IDs or looking for SIDs, we don't want to limit * ourselves to groups with a GID value */ @@ -656,6 +729,75 @@ static void groups_get_connect_done(struct tevent_req *subreq) return; } + /* If POSIX attributes have been requested with an AD server and we + * have no idea about POSIX attributes support, run a one-time check + */ + if (state->use_id_mapping == false && + state->ctx->opts->schema_type == SDAP_SCHEMA_AD && + state->ctx->srv_opts && + state->ctx->srv_opts->posix_checked == false) { + subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts, + sdap_id_op_handle(state->op), + state->sdom->user_search_bases, + dp_opt_get_int(state->ctx->opts->basic, + SDAP_SEARCH_TIMEOUT)); + if (subreq == NULL) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, groups_get_posix_check_done, req); + return; + } + + groups_get_search(req); +} + +static void groups_get_posix_check_done(struct tevent_req *subreq) +{ + errno_t ret; + bool has_posix; + int dp_error; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct groups_get_state *state = tevent_req_data(req, + struct groups_get_state); + + ret = sdap_posix_check_recv(subreq, &has_posix); + talloc_zfree(subreq); + if (ret != EOK) { + /* We can only finish the id_op on error as the connection + * is re-used by the group search + */ + ret = sdap_id_op_done(state->op, ret, &dp_error); + if (dp_error == DP_ERR_OK && ret != EOK) { + /* retry */ + ret = groups_get_retry(req); + if (ret != EOK) { + tevent_req_error(req, ret); + } + return; + } + } + + state->ctx->srv_opts->posix_checked = true; + + /* If the check ran to completion, we know for certain about the attributes + */ + if (has_posix == false) { + state->sdap_ret = ERR_NO_POSIX; + tevent_req_done(req); + return; + } + + groups_get_search(req); +} + +static void groups_get_search(struct tevent_req *req) +{ + struct groups_get_state *state = tevent_req_data(req, + struct groups_get_state); + struct tevent_req *subreq; + subreq = sdap_get_groups_send(state, state->ev, state->sdom, state->ctx->opts, diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h index 73c7055..ad239a8 100644 --- a/src/providers/ldap/sdap.h +++ b/src/providers/ldap/sdap.h @@ -447,6 +447,7 @@ struct sdap_server_opts { char *max_group_value; char *max_service_value; char *max_sudo_value; + bool posix_checked; }; struct sdap_id_ctx; diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c index 367007b..1022a09 100644 --- a/src/providers/ldap/sdap_async.c +++ b/src/providers/ldap/sdap_async.c @@ -21,6 +21,7 @@ #include #include "util/util.h" +#include "util/strtonum.h" #include "providers/ldap/sdap_async_private.h" #define REALM_SEPARATOR '@' @@ -2083,6 +2084,205 @@ int sdap_asq_search_recv(struct tevent_req *req, return EOK; } +/* ==Posix attribute presence test================================= */ +static errno_t sdap_posix_check_next(struct tevent_req *req); +static void sdap_posix_check_done(struct tevent_req *subreq); +static errno_t sdap_posix_check_parse(struct sdap_handle *sh, + struct sdap_msg *msg, + void *pvt); + +struct sdap_posix_check_state { + struct tevent_context *ev; + struct sdap_options *opts; + struct sdap_handle *sh; + struct sdap_search_base **search_bases; + int timeout; + + const char **attrs; + const char *filter; + size_t base_iter; + + bool has_posix; +}; + +struct tevent_req * +sdap_posix_check_send(TALLOC_CTX *memctx, struct tevent_context *ev, + struct sdap_options *opts, struct sdap_handle *sh, + struct sdap_search_base **search_bases, + int timeout) +{ + struct tevent_req *req = NULL; + struct sdap_posix_check_state *state; + errno_t ret; + + req = tevent_req_create(memctx, &state, struct sdap_posix_check_state); + if (req == NULL) { + return NULL; + } + state->ev = ev; + state->sh = sh; + state->opts = opts; + state->search_bases = search_bases; + state->timeout = timeout; + + state->attrs = talloc_array(state, const char *, 4); + if (state->attrs == NULL) { + ret = ENOMEM; + goto fail; + } + state->attrs[0] = "objectclass"; + state->attrs[1] = opts->user_map[SDAP_AT_USER_UID].name; + state->attrs[2] = opts->group_map[SDAP_AT_GROUP_GID].name; + state->attrs[3] = NULL; + + state->filter = talloc_asprintf(state, "(|(%s=*)(%s=*))", + opts->user_map[SDAP_AT_USER_UID].name, + opts->group_map[SDAP_AT_GROUP_GID].name); + if (state->filter == NULL) { + ret = ENOMEM; + goto fail; + } + + ret = sdap_posix_check_next(req); + if (ret != EOK) { + goto fail; + } + + return req; + +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} + +static errno_t sdap_posix_check_next(struct tevent_req *req) +{ + struct tevent_req *subreq = NULL; + struct sdap_posix_check_state *state = + tevent_req_data(req, struct sdap_posix_check_state); + + DEBUG(SSSDBG_TRACE_FUNC, + ("Searching for POSIX attributes with base [%s]\n", + state->search_bases[state->base_iter]->basedn)); + + subreq = sdap_get_generic_ext_send(state, state->ev, state->opts, + state->sh, + state->search_bases[state->base_iter]->basedn, + LDAP_SCOPE_SUBTREE, state->filter, + state->attrs, false, + NULL, NULL, 1, state->timeout, + false, sdap_posix_check_parse, + state); + if (subreq == NULL) { + return ENOMEM; + } + tevent_req_set_callback(subreq, sdap_posix_check_done, req); + + return EOK; +} + +static errno_t sdap_posix_check_parse(struct sdap_handle *sh, + struct sdap_msg *msg, + void *pvt) +{ + struct berval **vals = NULL; + struct sdap_posix_check_state *state = + talloc_get_type(pvt, struct sdap_posix_check_state); + char *dn; + char *endptr; + + dn = ldap_get_dn(sh->ldap, msg->msg); + if (dn == NULL) { + DEBUG(SSSDBG_TRACE_LIBS, + ("Search did not find any entry with POSIX attributes\n")); + goto done; + } + DEBUG(SSSDBG_TRACE_LIBS, ("Found [%s] with POSIX attributes\n", dn)); + ldap_memfree(dn); + + vals = ldap_get_values_len(sh->ldap, msg->msg, + state->opts->user_map[SDAP_AT_USER_UID].name); + if (vals == NULL) { + vals = ldap_get_values_len(sh->ldap, msg->msg, + state->opts->group_map[SDAP_AT_GROUP_GID].name); + if (vals == NULL) { + DEBUG(SSSDBG_TRACE_LIBS, ("Entry does not have POSIX attrs?\n")); + goto done; + } + } + + if (vals[0] == NULL) { + DEBUG(SSSDBG_TRACE_LIBS, ("No value for POSIX attr\n")); + goto done; + } + + errno = 0; + strtouint32(vals[0]->bv_val, &endptr, 10); + if (errno || *endptr || (vals[0]->bv_val == endptr)) { + DEBUG(SSSDBG_OP_FAILURE, + ("POSIX attribute is not a number: %s\n", vals[0]->bv_val)); + goto done; + } + + state->has_posix = true; +done: + ldap_value_free_len(vals); + return EOK; +} + +static void sdap_posix_check_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sdap_posix_check_state *state = + tevent_req_data(req, struct sdap_posix_check_state); + errno_t ret; + + ret = sdap_get_generic_ext_recv(subreq); + talloc_zfree(subreq); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + ("sdap_get_generic_ext_recv failed [%d]: %s\n", + ret, strerror(ret))); + tevent_req_error(req, ret); + return; + } + + /* Positive hit is definitve, no need to search other bases */ + if (state->has_posix == true) { + DEBUG(SSSDBG_FUNC_DATA, ("Server has POSIX attributes\n")); + tevent_req_done(req); + return; + } + + state->base_iter++; + if (state->search_bases[state->base_iter]) { + /* There are more search bases to try */ + ret = sdap_posix_check_next(req); + if (ret != EOK) { + tevent_req_error(req, ret); + } + return; + } + + /* All bases done! */ + DEBUG(SSSDBG_TRACE_LIBS, ("Cycled through all bases\n")); + tevent_req_done(req); +} + +int sdap_posix_check_recv(struct tevent_req *req, + bool *_has_posix) +{ + struct sdap_posix_check_state *state = tevent_req_data(req, + struct sdap_posix_check_state); + + TEVENT_REQ_RETURN_ON_ERROR(req); + + *_has_posix = state->has_posix; + return EOK; +} + /* ==Generic Deref Search============================================ */ enum sdap_deref_type { SDAP_DEREF_OPENLDAP, diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h index 33e8708..593404a 100644 --- a/src/providers/ldap/sdap_async.h +++ b/src/providers/ldap/sdap_async.h @@ -210,6 +210,15 @@ int sdap_deref_search_recv(struct tevent_req *req, size_t *reply_count, struct sdap_deref_attrs ***reply); +struct tevent_req * +sdap_posix_check_send(TALLOC_CTX *memctx, struct tevent_context *ev, + struct sdap_options *opts, struct sdap_handle *sh, + struct sdap_search_base **search_bases, + int timeout); + +int sdap_posix_check_recv(struct tevent_req *req, + bool *_has_posix); + errno_t sdap_attrs_add_ldap_attr(struct sysdb_attrs *ldap_attrs, const char *attr_name, diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c index ad4fa89..cbee59e 100644 --- a/src/providers/ldap/sdap_async_enum.c +++ b/src/providers/ldap/sdap_async_enum.c @@ -69,6 +69,8 @@ static errno_t sdap_dom_enum_ex_retry(struct tevent_req *req, tevent_req_fn tcb); static bool sdap_dom_enum_ex_connected(struct tevent_req *subreq); static void sdap_dom_enum_ex_get_users(struct tevent_req *subreq); +static void sdap_dom_enum_ex_posix_check_done(struct tevent_req *subreq); +static errno_t sdap_dom_enum_search_users(struct tevent_req *req); static void sdap_dom_enum_ex_users_done(struct tevent_req *subreq); static void sdap_dom_enum_ex_get_groups(struct tevent_req *subreq); static void sdap_dom_enum_ex_groups_done(struct tevent_req *subreq); @@ -179,19 +181,109 @@ static void sdap_dom_enum_ex_get_users(struct tevent_req *subreq) struct tevent_req); struct sdap_dom_enum_ex_state *state = tevent_req_data(req, struct sdap_dom_enum_ex_state); + bool use_id_mapping; + errno_t ret; if (sdap_dom_enum_ex_connected(subreq) == false) { return; } + use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping( + state->ctx->opts->idmap_ctx, + state->sdom->dom->name, + state->sdom->dom->domain_id); + + /* If POSIX attributes have been requested with an AD server and we + * have no idea about POSIX attributes support, run a one-time check + */ + if (use_id_mapping == false && + state->ctx->opts->schema_type == SDAP_SCHEMA_AD && + state->ctx->srv_opts && + state->ctx->srv_opts->posix_checked == false) { + subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts, + sdap_id_op_handle(state->user_op), + state->sdom->user_search_bases, + dp_opt_get_int(state->ctx->opts->basic, + SDAP_SEARCH_TIMEOUT)); + if (subreq == NULL) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, + sdap_dom_enum_ex_posix_check_done, req); + return; + } + + + ret = sdap_dom_enum_search_users(req); + if (ret != EOK) { + tevent_req_error(req, ret); + return; + } + /* Execution resumes in sdap_dom_enum_ex_users_done */ +} + +static void sdap_dom_enum_ex_posix_check_done(struct tevent_req *subreq) +{ + errno_t ret; + bool has_posix; + int dp_error; + + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sdap_dom_enum_ex_state *state = tevent_req_data(req, + struct sdap_dom_enum_ex_state); + + ret = sdap_posix_check_recv(subreq, &has_posix); + talloc_zfree(subreq); + if (ret != EOK) { + /* We can only finish the id_op on error as the connection + * is re-used by the user search + */ + ret = sdap_id_op_done(state->user_op, ret, &dp_error); + if (dp_error == DP_ERR_OK && ret != EOK) { + /* retry */ + ret = sdap_dom_enum_ex_retry(req, state->user_op, + sdap_dom_enum_ex_get_users); + if (ret != EOK) { + tevent_req_error(req, ret); + } + return; + } + } + + state->ctx->srv_opts->posix_checked = true; + + /* If the check ran to completion, we know for certain about the attributes + */ + if (has_posix == false) { + tevent_req_error(req, ERR_NO_POSIX); + return; + } + + + ret = sdap_dom_enum_search_users(req); + if (ret != EOK) { + tevent_req_error(req, ret); + return; + } + /* Execution resumes in sdap_dom_enum_ex_users_done */ +} + +static errno_t sdap_dom_enum_search_users(struct tevent_req *req) +{ + struct sdap_dom_enum_ex_state *state = tevent_req_data(req, + struct sdap_dom_enum_ex_state); + struct tevent_req *subreq; + subreq = enum_users_send(state, state->ev, state->ctx, state->sdom, state->user_op, state->purge); if (subreq == NULL) { - tevent_req_error(req, ENOMEM); - return; + return ENOMEM; } tevent_req_set_callback(subreq, sdap_dom_enum_ex_users_done, req); + return EOK; } static void sdap_dom_enum_ex_users_done(struct tevent_req *subreq) diff --git a/src/util/util_errors.c b/src/util/util_errors.c index 633257e..c9b5075 100644 --- a/src/util/util_errors.c +++ b/src/util/util_errors.c @@ -52,6 +52,7 @@ struct err_string error_to_str[] = { { "Domain not found" }, /* ERR_DOMAIN_NOT_FOUND */ { "Missing configuration file" }, /* ERR_MISSING_CONF */ { "Malformed search filter" }, /* ERR_INVALID_FILTER, */ + { "No POSIX attributes detected" }, /* ERR_NO_POSIX */ }; diff --git a/src/util/util_errors.h b/src/util/util_errors.h index 1332085..3dd94af 100644 --- a/src/util/util_errors.h +++ b/src/util/util_errors.h @@ -74,6 +74,7 @@ enum sssd_errors { ERR_DOMAIN_NOT_FOUND, ERR_MISSING_CONF, ERR_INVALID_FILTER, + ERR_NO_POSIX, ERR_LAST /* ALWAYS LAST */ };