diff options
Diffstat (limited to 'src/providers/ldap')
-rw-r--r-- | src/providers/ldap/ldap_id.c | 158 | ||||
-rw-r--r-- | src/providers/ldap/sdap.h | 1 | ||||
-rw-r--r-- | src/providers/ldap/sdap_async.c | 200 | ||||
-rw-r--r-- | src/providers/ldap/sdap_async.h | 9 | ||||
-rw-r--r-- | src/providers/ldap/sdap_async_enum.c | 96 |
5 files changed, 454 insertions, 10 deletions
diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c index e36c1f697..b948ba9f3 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. */ @@ -184,7 +186,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. @@ -269,6 +271,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, @@ -434,6 +505,7 @@ struct groups_get_state { char *filter; const char **attrs; + bool use_id_mapping; int dp_error; int sdap_ret; @@ -442,6 +514,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, @@ -463,7 +537,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); @@ -488,7 +561,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); @@ -503,7 +576,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. */ @@ -571,7 +644,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 */ @@ -660,6 +733,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 d408be0a6..f3f13e9c7 100644 --- a/src/providers/ldap/sdap.h +++ b/src/providers/ldap/sdap.h @@ -446,6 +446,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 367007bde..1022a093f 100644 --- a/src/providers/ldap/sdap_async.c +++ b/src/providers/ldap/sdap_async.c @@ -21,6 +21,7 @@ #include <ctype.h> #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 33e8708ab..593404af3 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 cbc56be20..0c20afa9d 100644 --- a/src/providers/ldap/sdap_async_enum.c +++ b/src/providers/ldap/sdap_async_enum.c @@ -68,6 +68,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); @@ -178,19 +180,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) |