From 755aee449c6311518200c2f11c1aae329a19b038 Mon Sep 17 00:00:00 2001 From: Pavel Březina Date: Apr 02 2013 13:33:03 +0000 Subject: refactor nested group processing: replace old code https://fedorahosted.org/sssd/ticket/1784 --- diff --git a/Makefile.am b/Makefile.am index 39e6e07..fd7eb27 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1339,6 +1339,7 @@ libsss_ldap_common_la_SOURCES = \ src/providers/ldap/sdap_async.c \ src/providers/ldap/sdap_async_users.c \ src/providers/ldap/sdap_async_groups.c \ + src/providers/ldap/sdap_async_nested_groups.c \ src/providers/ldap/sdap_async_groups_ad.c \ src/providers/ldap/sdap_async_initgroups.c \ src/providers/ldap/sdap_async_initgroups_ad.c \ diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c index 4d1ece8..9d4a848 100644 --- a/src/providers/ldap/sdap_async_groups.c +++ b/src/providers/ldap/sdap_async_groups.c @@ -1544,15 +1544,7 @@ static errno_t sdap_get_groups_next_base(struct tevent_req *req) return EOK; } -static struct tevent_req *sdap_nested_group_process_send( - TALLOC_CTX *mem_ctx, struct tevent_context *ev, - struct sss_domain_info *domain, - struct sysdb_ctx *sysdb, struct sysdb_attrs *group, - hash_table_t *users, hash_table_t *groups, - struct sdap_options *opts, struct sdap_handle *sh, - bool enable_deref, uint32_t nesting); static void sdap_nested_done(struct tevent_req *req); -static errno_t sdap_nested_group_process_recv(struct tevent_req *req); static void sdap_ad_match_rule_members_process(struct tevent_req *subreq); static void sdap_get_groups_process(struct tevent_req *subreq) @@ -1566,7 +1558,6 @@ static void sdap_get_groups_process(struct tevent_req *subreq) bool next_base = false; size_t count; struct sysdb_attrs **groups; - bool enable_deref = true; ret = sdap_get_generic_recv(subreq, state, &count, &groups); @@ -1645,57 +1636,9 @@ static void sdap_get_groups_process(struct tevent_req *subreq) if ((state->opts->schema_type != SDAP_SCHEMA_RFC2307) && (dp_opt_get_int(state->opts->basic, SDAP_NESTING_LEVEL) != 0) && !dp_opt_get_bool(state->opts->basic, SDAP_AD_MATCHING_RULE_GROUPS)) { - - /* Prepare hashes for nested user processing */ - ret = sss_hash_create(state, 32, &state->user_hash); - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } - - ret = sss_hash_create(state, 32, &state->group_hash); - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } - - /* - * If any search base contains filter, disable dereference. - */ - enable_deref = true; - for (i = 0; state->opts->user_search_bases[i] != NULL; i++) { - if (state->opts->user_search_bases[i]->filter != NULL) { - DEBUG(SSSDBG_TRACE_FUNC, - ("User search base contains filter, " - "dereference will be disabled\n")); - enable_deref = false; - break; - } - } - - if (enable_deref) { - for (i = 0; state->opts->group_search_bases[i] != NULL; i++) { - if (state->opts->group_search_bases[i]->filter != NULL) { - DEBUG(SSSDBG_TRACE_FUNC, - ("Group search base contains filter, " - "dereference will be disabled\n")); - enable_deref = false; - break; - } - } - } - - subreq = sdap_nested_group_process_send(state, - state->ev, - state->dom, - state->sysdb, - state->groups[0], - state->user_hash, - state->group_hash, - state->opts, - state->sh, - enable_deref, - 0); + subreq = sdap_nested_group_send(state, state->ev, state->dom, + state->opts, state->sh, + state->groups[0]); if (!subreq) { tevent_req_error(req, EIO); return; @@ -1960,11 +1903,8 @@ int sdap_get_groups_recv(struct tevent_req *req, static void sdap_nested_done(struct tevent_req *subreq) { errno_t ret, tret; - int hret; - unsigned long i; unsigned long user_count; unsigned long group_count; - hash_value_t *values; bool in_transaction = false; struct sysdb_attrs **users = NULL; struct sysdb_attrs **groups = NULL; @@ -1974,7 +1914,8 @@ static void sdap_nested_done(struct tevent_req *subreq) struct sdap_get_groups_state *state = tevent_req_data(req, struct sdap_get_groups_state); - ret = sdap_nested_group_process_recv(subreq); + ret = sdap_nested_group_recv(state, subreq, &user_count, &users, + &group_count, &groups); talloc_zfree(subreq); if (ret != EOK) { DEBUG(1, ("Nested group processing failed: [%d][%s]\n", @@ -1982,45 +1923,6 @@ static void sdap_nested_done(struct tevent_req *subreq) goto fail; } - hret = hash_values(state->user_hash, &user_count, &values); - if (hret != HASH_SUCCESS) { - ret = EIO; - goto fail; - } - - if (user_count) { - users = talloc_array(state, struct sysdb_attrs *, user_count); - if (!users) { - talloc_free(values); - ret = ENOMEM; - goto fail; - } - - for (i = 0; i < user_count; i++) { - users[i] = talloc_get_type(values[i].ptr, struct sysdb_attrs); - } - talloc_zfree(values); - } - - /* Users are all retrieved. Now retrieve groups */ - hret = hash_values(state->group_hash, &group_count, &values); - if (hret != HASH_SUCCESS) { - ret = EIO; - goto fail; - } - - groups = talloc_array(state, struct sysdb_attrs *, group_count); - if (!groups) { - talloc_free(values); - ret = ENOMEM; - goto fail; - } - - for (i = 0; i < group_count; i++) { - groups[i] = talloc_get_type(values[i].ptr, struct sysdb_attrs); - } - talloc_zfree(values); - /* Save all of the users first so that they are in * place for the groups to add them. */ @@ -2222,1621 +2124,3 @@ done: talloc_zfree(tmp_ctx); return ret; } - -/* - * Get user based on a user DN. Optimized for environments where the containers - * are strictly defined, such as IPA. - */ -static void -sdap_nested_get_user_done(struct tevent_req *subreq); -static errno_t -sdap_nested_get_ipa_user(TALLOC_CTX *mem_ctx, const char *user_dn, - struct sysdb_ctx *sysdb, struct sysdb_attrs ***_reply); - -struct sdap_nested_get_user_state { - size_t count; - struct sysdb_attrs **replies; -}; - -static struct tevent_req * -sdap_nested_get_user_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, - struct sss_domain_info *domain, - struct sysdb_ctx *sysdb, - struct sdap_options *opts, - struct sdap_handle *sh, - const char *user_dn, - const char *search_bases_filter) -{ - errno_t ret; - struct tevent_req *req; - struct tevent_req *subreq; - const char **sdap_attrs; - const char *filter; - struct sdap_nested_get_user_state *state; - - req = tevent_req_create(mem_ctx, &state, - struct sdap_nested_get_user_state); - if (!req) { - return NULL; - } - - if (opts->schema_type == SDAP_SCHEMA_IPA_V1) { - /* If the schema is IPA, then just shortcut and guess the name */ - ret = sdap_nested_get_ipa_user(state, user_dn, sysdb, &state->replies); - if (ret == EOK) { - state->count = 1; - goto immediate; - } else { - DEBUG(SSSDBG_MINOR_FAILURE, ("Couldn't parse out user information " - "based on DN %s, falling back to an LDAP lookup\n", user_dn)); - } - } - - /* Only pull down username and originalDN */ - sdap_attrs = talloc_array(state, const char *, 3); - if (!sdap_attrs) { - ret = ENOMEM; - goto immediate; - } - sdap_attrs[0] = "objectClass"; - sdap_attrs[1] = opts->user_map[SDAP_AT_USER_NAME].name; - sdap_attrs[2] = NULL; - - if (search_bases_filter != NULL) { - filter = talloc_asprintf(sdap_attrs, "(&%s(objectclass=%s))", - search_bases_filter, - opts->user_map[SDAP_OC_USER].name); - } else { - filter = talloc_asprintf(sdap_attrs, "(objectclass=%s)", - opts->user_map[SDAP_OC_USER].name); - } - if (!filter) { - ret = ENOMEM; - goto immediate; - } - - subreq = sdap_get_generic_send(state, ev, opts, sh, user_dn, - LDAP_SCOPE_BASE, filter, sdap_attrs, - opts->user_map, SDAP_OPTS_USER, - dp_opt_get_int(opts->basic, - SDAP_SEARCH_TIMEOUT), - false); - if (!subreq) { - ret = EIO; - goto immediate; - } - talloc_steal(subreq, sdap_attrs); - - tevent_req_set_callback(subreq, sdap_nested_get_user_done, req); - return req; - -immediate: - if (ret) { - tevent_req_error(req, ret); - } else { - tevent_req_done(req); - } - tevent_req_post(req, ev); - return req; -} - -/* This should be a function pointer set from the IPA provider */ -static errno_t -sdap_nested_get_ipa_user(TALLOC_CTX *mem_ctx, const char *user_dn, - struct sysdb_ctx *sysdb, struct sysdb_attrs ***_reply) -{ - errno_t ret; - struct sysdb_attrs **reply = NULL; - struct sysdb_attrs *user = NULL; - char *name; - struct ldb_dn *dn = NULL; - const char *rdn_name; - const char *users_comp_name; - const char *acct_comp_name; - const struct ldb_val *rdn_val; - const struct ldb_val *users_comp_val; - const struct ldb_val *acct_comp_val; - TALLOC_CTX *tmp_ctx; - - tmp_ctx = talloc_new(NULL); - if (!tmp_ctx) return ENOMEM; - - dn = ldb_dn_new(tmp_ctx, sysdb_ctx_get_ldb(sysdb), user_dn); - if (dn == NULL) { - ret = ENOMEM; - goto done; - } - - if (ldb_dn_get_comp_num(dn) < 4) { - /* RDN, users, accounts, and at least one DC= - * For example: - * uid=admin,cn=users,cn=accounts,dc=example,dc=com */ - /* If it's fewer, it's not a user DN */ - ret = ENOENT; - goto done; - } - - /* If the RDN attribute name is 'uid' */ - rdn_name = ldb_dn_get_rdn_name(dn); - if (rdn_name == NULL) { - /* Shouldn't happen if ldb_dn_validate() - * passed, but we'll be careful. - */ - ret = EINVAL; - goto done; - } - - if (strcasecmp("uid", rdn_name) != 0) { - /* RDN has the wrong attribute name. - * It's not a service. - */ - ret = ENOENT; - goto done; - } - - /* and the second component is "cn=users" */ - users_comp_name = ldb_dn_get_component_name(dn, 1); - if (strcasecmp("cn", users_comp_name) != 0) { - /* The second component name is not "cn" */ - ret = ENOENT; - goto done; - } - - users_comp_val = ldb_dn_get_component_val(dn, 1); - if (strncasecmp("users", - (const char *) users_comp_val->data, - users_comp_val->length) != 0) { - /* The second component value is not "users" */ - ret = ENOENT; - goto done; - } - - /* and the third component is "cn=accounts" */ - acct_comp_name = ldb_dn_get_component_name(dn, 2); - if (strcasecmp("cn", acct_comp_name) != 0) { - /* The third component name is not "cn" */ - ret = ENOENT; - goto done; - } - - acct_comp_val = ldb_dn_get_component_val(dn, 2); - if (strncasecmp("accounts", - (const char *) acct_comp_val->data, - acct_comp_val->length) != 0) { - /* The third component value is not "accounts" */ - ret = ENOENT; - goto done; - } - - /* Then the value of the RDN is the group name */ - reply = talloc_zero_array(tmp_ctx, struct sysdb_attrs *, 2); - if (!reply) { - ret = ENOMEM; - goto done; - } - - reply[0] = sysdb_new_attrs(reply); - if (!reply[0]) { - ret = ENOMEM; - goto done; - } - user = reply[0]; - - rdn_val = ldb_dn_get_rdn_val(dn); - name = talloc_strndup(user, (const char *)rdn_val->data, - rdn_val->length); - if (name == NULL) { - ret = ENOMEM; - goto done; - } - - ret = sysdb_attrs_add_string(user, SYSDB_NAME, name); - if (ret != EOK) { - goto done; - } - - ret = sysdb_attrs_add_string(user, SYSDB_ORIG_DN, user_dn); - if (ret != EOK) { - goto done; - } - - ret = sysdb_attrs_add_string(user, SYSDB_OBJECTCLASS, SYSDB_USER_CLASS); - if (ret != EOK) { - goto done; - } - - ret = EOK; - *_reply = talloc_steal(mem_ctx, reply); -done: - talloc_free(tmp_ctx); - return ret; -} - -static void -sdap_nested_get_user_done(struct tevent_req *subreq) -{ - errno_t ret; - struct tevent_req *req = - tevent_req_callback_data(subreq, struct tevent_req); - struct sdap_nested_get_user_state *state = tevent_req_data(req, - struct sdap_nested_get_user_state); - - ret = sdap_get_generic_recv(subreq, state, &state->count, &state->replies); - talloc_zfree(subreq); - if (ret != EOK && ret != ENOENT) { - tevent_req_error(req, ret); - return; - } - - tevent_req_done(req); -} - -static errno_t -sdap_nested_get_user_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, - size_t *_count, struct sysdb_attrs ***_replies) -{ - struct sdap_nested_get_user_state *state = tevent_req_data(req, - struct sdap_nested_get_user_state); - - TEVENT_REQ_RETURN_ON_ERROR(req); - - if (_count) { - *_count = state->count; - } - - if (_replies) { - *_replies = talloc_steal(mem_ctx, state->replies); - } - - return EOK; -} - -struct sdap_deref_ctx { - const char *orig_dn; - - size_t expired_users_num; - uint32_t expired_users_index; - char **expired_users; - - size_t expired_groups_num; - uint32_t expired_groups_index; - char **expired_groups; - - size_t missing_dns_num; - uint32_t missing_dns_index; - char **missing_dns; - - struct sdap_deref_attrs **deref_result; - size_t num_results; - uint32_t result_index; - - int deref_threshold; -}; - -struct sdap_nested_group_ctx { - struct tevent_context *ev; - struct sysdb_ctx *sysdb; - struct sss_domain_info *domain; - - hash_table_t *users; - hash_table_t *groups; - - struct sdap_options *opts; - struct sdap_handle *sh; - - uint32_t nesting_level; - - struct ldb_message_element *members; - uint32_t member_index; - char *member_dn; - - bool enable_deref; - struct sdap_deref_ctx *derefctx; - - /** - * FIXME: Remove me! - */ - bool send_finished; -}; - -static errno_t sdap_nested_group_process_deref_step(struct tevent_req *req); -static errno_t sdap_nested_group_process_step(struct tevent_req *req); - -static struct tevent_req *sdap_nested_group_process_send( - TALLOC_CTX *mem_ctx, struct tevent_context *ev, - struct sss_domain_info *domain, - struct sysdb_ctx *sysdb, struct sysdb_attrs *group, - hash_table_t *users, hash_table_t *groups, - struct sdap_options *opts, struct sdap_handle *sh, - bool enable_deref, uint32_t nesting) -{ - errno_t ret; - int hret; - struct tevent_req *req; - struct sdap_nested_group_ctx *state; - const char *groupname; - hash_key_t key; - hash_value_t value; - gid_t gid; - - req = tevent_req_create(mem_ctx, &state, struct sdap_nested_group_ctx); - if (!req) { - return NULL; - } - - state->ev = ev; - state->sysdb = sysdb; - state->domain = domain; - state->users = users; - state->groups = groups; - state->opts = opts; - state->sh = sh; - state->enable_deref = enable_deref; - state->nesting_level = nesting; - state->send_finished = false; - - /* If this is too many levels deep, just return success */ - if (nesting > dp_opt_get_int(opts->basic, SDAP_NESTING_LEVEL)) { - ret = EOK; - goto immediate; - } - - /* Add the current group to the groups hash so we don't - * look it up more than once - */ - key.type = HASH_KEY_STRING; - - ret = sysdb_attrs_primary_name(sysdb, group, - opts->group_map[SDAP_AT_GROUP_NAME].sys_name, - &groupname); - if (ret != EOK) { - goto immediate; - } - - key.str = talloc_strdup(state, groupname); - if (!key.str) { - ret = ENOMEM; - goto immediate; - } - - if (hash_has_key(groups, &key)) { - /* This group has already been processed - * (or is in progress) - * Skip it and just return success - */ - ret = EOK; - goto immediate; - } - - ret = sysdb_attrs_get_uint32_t(group, - opts->group_map[SDAP_AT_GROUP_GID].sys_name, - &gid); - if (ret == ENOENT || (ret == EOK && gid == 0)) { - DEBUG(9, ("The group's gid was %s\n", ret == ENOENT ? "missing" : "zero")); - DEBUG(8, ("Marking group as non-posix and setting GID=0!\n")); - - if (ret == ENOENT) { - ret = sysdb_attrs_add_uint32(group, - opts->group_map[SDAP_AT_GROUP_GID].sys_name, - 0); - if (ret != EOK) { - DEBUG(1, ("Failed to add a GID to non-posix group!\n")); - goto immediate; - } - } - - ret = sysdb_attrs_add_bool(group, SYSDB_POSIX, false); - if (ret != EOK) { - DEBUG(2, ("Error: Failed to mark group as non-posix!\n")); - goto immediate; - } - } else if (ret) { - goto immediate; - } - - value.type = HASH_VALUE_PTR; - value.ptr = talloc_steal(groups, group); - - hret = hash_enter(groups, &key, &value); - if (hret != HASH_SUCCESS) { - ret = EIO; - goto immediate; - } - talloc_free(key.str); - - /* Process group memberships */ - - /* TODO: future enhancement, check for memberuid as well - * See https://fedorahosted.org/sssd/ticket/445 - */ - - ret = sysdb_attrs_get_el( - group, - opts->group_map[SDAP_AT_GROUP_MEMBER].sys_name, - &state->members); - if (ret != EOK) { - if (ret == ENOENT) { - /* No members to process */ - ret = EOK; - } - goto immediate; - } - - state->member_index = 0; - - if (enable_deref && sdap_has_deref_support(state->sh, state->opts)) { - state->derefctx = talloc_zero(state, struct sdap_deref_ctx); - if (!state->derefctx) { - ret = ENOMEM; - goto immediate; - } - - ret = sysdb_attrs_get_string(group, SYSDB_ORIG_DN, - &state->derefctx->orig_dn); - if (ret != EOK) goto immediate; - - ret = sdap_nested_group_process_deref_step(req); - if (ret != EAGAIN) goto immediate; - } else { - ret = sdap_nested_group_process_step(req); - if (ret != EAGAIN) goto immediate; - } - - state->send_finished = true; - return req; - -immediate: - if (ret == EOK) { - tevent_req_done(req); - } else { - tevent_req_error(req, ret); - } - tevent_req_post(req, ev); - state->send_finished = true; - return req; -} - -static errno_t sdap_nested_group_check_hash(struct sdap_nested_group_ctx *); -static errno_t sdap_nested_group_check_cache(TALLOC_CTX *mem_ctx, - struct sysdb_ctx *sysdb, - struct sss_domain_info *dom, - struct sdap_options *opts, - char *member_dn, - struct ldb_message ***_msgs, - enum sysdb_member_type *_mtype); - -static void sdap_nested_group_process_ldap_user(struct tevent_req *subreq); -static void sdap_nested_group_process_user(struct tevent_req *subreq); -static errno_t sdap_nested_group_lookup_user(struct tevent_req *req, - tevent_req_fn fn); -static errno_t sdap_nested_group_lookup_group(struct tevent_req *req); -static errno_t sdap_nested_group_process_deref_call(struct tevent_req *req); -static errno_t sdap_nested_group_process_noderef(struct tevent_req *req); - -static errno_t sdap_nested_group_process_deref_step(struct tevent_req *req) -{ - errno_t ret; - struct sdap_nested_group_ctx *state = - tevent_req_data(req, struct sdap_nested_group_ctx); - size_t missing = 0; - struct ldb_message **msgs = NULL; - enum sysdb_member_type mtype; - struct sdap_deref_ctx *dctx = state->derefctx; - - dctx->deref_threshold = dp_opt_get_int(state->opts->basic, - SDAP_DEREF_THRESHOLD); - - dctx->expired_users = talloc_array(dctx, char *, - state->members->num_values + 1); - dctx->expired_groups = talloc_array(dctx, char *, - state->members->num_values + 1); - dctx->missing_dns = talloc_array(dctx, char *, - state->members->num_values + 1); - if (!dctx->expired_users || - !dctx->expired_groups || - !dctx->missing_dns) return ENOMEM; - - while (true) { - if (state->member_index >= state->members->num_values) { - /* No more entries to check. Return success */ - talloc_zfree(state->member_dn); - ret = EOK; - break; - } - - /* Continue to loop through until all entries have been - * processed. - */ - ret = sdap_nested_group_check_hash(state); - if (ret == EOK) { - talloc_zfree(state->member_dn); - break; /* All remaining members in hash, check missing */ - } else if (ret != ENOENT) { - goto done; /* Unexpected error */ - } - - ret = sdap_nested_group_check_cache(state, state->sysdb, - state->domain, - state->opts, - state->member_dn, - &msgs, &mtype); - if (ret == EOK) { - /* The entry is cached and valid */ - state->member_index++; - talloc_zfree(state->member_dn); - continue; - } else if (ret == EAGAIN) { - /* The entry is cached but needs refresh */ - switch(mtype) { - case SYSDB_MEMBER_GROUP: - DEBUG(8, ("Cached LDAP group [%s] needs refresh\n", - state->member_dn)); - - missing++; - - dctx->expired_groups[dctx->expired_groups_num] = - talloc_move(dctx, &state->member_dn); - dctx->expired_groups_num++; - - state->member_index++; - continue; - case SYSDB_MEMBER_USER: - DEBUG(8, ("Cached LDAP user [%s] needs refresh\n", - state->member_dn)); - missing++; - - dctx->expired_users[dctx->expired_users_num] = - talloc_move(dctx, &state->member_dn); - dctx->expired_users_num++; - - state->member_index++; - continue; - default: - DEBUG(2, ("Unknown member value\n")); - ret = EINVAL; - goto done; - } - } else if (ret == ENOENT) { - /* The entry is missing. It is unclear whether it - * is a user or a group so we'll need to try looking - * it up */ - missing++; - - dctx->missing_dns[dctx->missing_dns_num] = - talloc_move(dctx, &state->member_dn); - dctx->missing_dns_num++; - - state->member_index++; - continue; - } - - /* Unexpected error, skip this entry */ - state->member_index++; - continue; - } /* while (true) */ - - - dctx->expired_users[dctx->expired_users_num] = NULL; - dctx->expired_groups[dctx->expired_groups_num] = NULL; - dctx->missing_dns[dctx->missing_dns_num] = NULL; - - if (missing == 0) { - ret = EOK; - goto done; - } - - if (missing > dctx->deref_threshold) { - DEBUG(6, ("Missing data past threshold, doing a full deref\n")); - ret = sdap_nested_group_process_deref_call(req); - } else { - DEBUG(6, ("Falling back to individual lookups\n")); - ret = sdap_nested_group_process_noderef(req); - } - - if (ret != EOK && ret != EAGAIN) goto done; - return EAGAIN; - -done: - talloc_zfree(state->member_dn); - return ret; -} - - -static errno_t sdap_nested_group_process_step(struct tevent_req *req) -{ - errno_t ret; - struct sdap_nested_group_ctx *state = - tevent_req_data(req, struct sdap_nested_group_ctx); - struct ldb_message **msgs = NULL; - enum sysdb_member_type mtype; - - while (true) { - /* Continue to loop through until all entries have been - * processed. - */ - ret = sdap_nested_group_check_hash(state); - if (ret == EOK) { - talloc_zfree(state->member_dn); - return EOK; /* All members in hash */ - } else if (ret != ENOENT) { - goto error; /* Unexpected error */ - } - - ret = sdap_nested_group_check_cache(state, state->sysdb, - state->domain, - state->opts, - state->member_dn, - &msgs, &mtype); - if (ret == EOK) { - /* The entry is cached and valid */ - state->member_index++; - talloc_zfree(state->member_dn); - continue; - } else if (ret == EAGAIN) { - /* The entry is cached but needs refresh */ - switch(mtype) { - case SYSDB_MEMBER_GROUP: - DEBUG(6, ("Refreshing cached group from LDAP\n")); - ret = sdap_nested_group_lookup_group(req); - if (ret != EOK) goto error; - break; - case SYSDB_MEMBER_USER: - DEBUG(6, ("Refreshing cached user from LDAP\n")); - ret = sdap_nested_group_lookup_user( - req, sdap_nested_group_process_user); - if (ret != EOK) goto error; - break; - default: - DEBUG(2, ("Unknown member value\n")); - ret = EINVAL; - goto error; - } - - return EAGAIN; - } else if (ret == ENOENT) { - /* It wasn't found in the cache either - * We'll have to do a blind lookup in LDAP - */ - - /* Try users first */ - ret = sdap_nested_group_lookup_user( - req, sdap_nested_group_process_ldap_user); - if (ret != EOK) { - goto error; - } - return EAGAIN; - } - - /* Unexpected error, skip this entry */ - state->member_index++; - talloc_zfree(state->member_dn); - continue; - } /* while (true) */ - -error: - talloc_zfree(state->member_dn); - return ret; -} - -static errno_t -sdap_nested_group_check_hash(struct sdap_nested_group_ctx *state) -{ - hash_key_t key; - bool has_key = false; - uint8_t *data; - - do { - if (state->member_index >= state->members->num_values) { - /* No more entries to check. Return success */ - return EOK; - } - - data = state->members->values[state->member_index].data; - state->member_dn = talloc_strdup(state, (const char *)data); - if (!state->member_dn) { - return ENOMEM; - } - - /* Check the user hash - * If it's there, we can save ourselves a trip to the - * sysdb and possibly LDAP as well - */ - key.type = HASH_KEY_STRING; - key.str = state->member_dn; - has_key = hash_has_key(state->users, &key); - if (has_key) { - talloc_zfree(state->member_dn); - state->member_index++; - continue; - } - } while (has_key); - - return ENOENT; -} - -static errno_t -sdap_nested_group_check_cache(TALLOC_CTX *mem_ctx, - struct sysdb_ctx *sysdb, - struct sss_domain_info *dom, - struct sdap_options *opts, - char *dn, - struct ldb_message ***_msgs, - enum sysdb_member_type *_mtype) -{ - TALLOC_CTX *tmp_ctx; - errno_t ret; - struct ldb_message **msgs = NULL; - char *member_dn; - uint64_t expiration; - uid_t user_uid; - time_t now = time(NULL); - static const char *attrs[] = { SYSDB_CACHE_EXPIRE, SYSDB_UIDNUM, - SYSDB_CREATE_TIME, SYSDB_NAME, - NULL }; - char *filter; - enum sysdb_member_type mtype = -1; - size_t count; - - tmp_ctx = talloc_new(NULL); - if (!tmp_ctx) return ENOMEM; - - ret = sss_filter_sanitize(tmp_ctx, dn, &member_dn); - if (ret != EOK) { - goto fail; - } - - /* Check for the specified origDN in the sysdb */ - filter = talloc_asprintf(tmp_ctx, "(%s=%s)", - SYSDB_ORIG_DN, - member_dn); - if (!filter) { - ret = ENOMEM; - goto fail; - } - - /* Try users first */ - ret = sysdb_search_users(tmp_ctx, sysdb, dom, filter, attrs, &count, &msgs); - if (ret != EOK && ret != ENOENT) { - ret = EIO; - goto fail; - } else if (ret == EOK && count > 0) { - /* We found a user with this origDN in the sysdb. Check if it is valid - */ - mtype = SYSDB_MEMBER_USER; - - /* Check whether the entry is valid */ - if (count != 1) { - DEBUG(1, ("More than one entry with this origDN? Skipping\n")); - ret = EIO; - goto fail; - } - - user_uid = ldb_msg_find_attr_as_uint64(msgs[0], SYSDB_UIDNUM, 0); - if (!user_uid) { - DEBUG(SSSDBG_OP_FAILURE, ("User with no UID? Skipping\n")); - ret = EIO; - goto fail; - } else { - /* Regular user, check if we need a refresh */ - expiration = ldb_msg_find_attr_as_uint64(msgs[0], - SYSDB_CACHE_EXPIRE, - 0); - } - - if (expiration && expiration > now) { - DEBUG(6, ("Cached values are still valid. Skipping\n")); - ret = EOK; - goto done; - } - - /* Refresh the user from LDAP */ - ret = EAGAIN; - goto done; - } - - /* It wasn't a user. Check whether it's a group */ - if (ret == EOK) talloc_zfree(msgs); - - ret = sysdb_search_groups(tmp_ctx, sysdb, dom, - filter, attrs, &count, &msgs); - if (ret != EOK && ret != ENOENT) { - ret = EIO; - goto fail; - } else if (ret == EOK && count > 0) { - /* We found a group with this origDN in the sysdb */ - mtype = SYSDB_MEMBER_GROUP; - - /* Check whether the entry is valid */ - if (count != 1) { - DEBUG(1, ("More than one entry with this origDN? Skipping\n")); - ret = EIO; - goto fail; - } - - expiration = ldb_msg_find_attr_as_uint64(msgs[0], - SYSDB_CACHE_EXPIRE, - 0); - if (expiration && expiration > now) { - DEBUG(6, ("Cached values are still valid.\n")); - ret = EOK; - goto done; - } - - /* Refresh the group from LDAP */ - ret = EAGAIN; - goto done; - } - - /* It wasn't found in the groups either */ - ret = ENOENT; -done: - if (ret == EOK || ret == EAGAIN) { - *_msgs = talloc_steal(mem_ctx, msgs); - *_mtype = mtype; - } - talloc_zfree(tmp_ctx); - return ret; - -fail: - talloc_zfree(tmp_ctx); - return ret; -} - -static void sdap_nested_group_process_deref(struct tevent_req *subreq); - -static errno_t -sdap_nested_group_process_deref_call(struct tevent_req *req) -{ - struct tevent_req *subreq; - struct sdap_attr_map_info *maps; - const char **sdap_attrs; - int ret; - int timeout; - size_t attr_count; - const int num_maps = 2; - struct sdap_nested_group_ctx *state = - tevent_req_data(req, struct sdap_nested_group_ctx); - - maps = talloc_array(state, struct sdap_attr_map_info, num_maps+1); - if (!maps) return ENOMEM; - - maps[0].map = state->opts->user_map; - maps[0].num_attrs = SDAP_OPTS_USER; - maps[1].map = state->opts->group_map; - maps[1].num_attrs = SDAP_OPTS_GROUP; - maps[2].map = NULL; - - /* Pull down the whole group map, but only pull down username - * and originalDN for users. */ - ret = build_attrs_from_map(state, state->opts->group_map, SDAP_OPTS_GROUP, - NULL, &sdap_attrs, &attr_count); - if (ret != EOK) goto fail; - - sdap_attrs = talloc_realloc(NULL, sdap_attrs, const char *, - attr_count + 2); - if (!sdap_attrs) { - ret = ENOMEM; - goto fail; - } - - sdap_attrs[attr_count] = \ - state->opts->user_map[SDAP_AT_USER_NAME].name; - sdap_attrs[attr_count + 1] = NULL; - - timeout = dp_opt_get_int(state->opts->basic, SDAP_SEARCH_TIMEOUT); - - subreq = sdap_deref_search_send(state, state->ev, state->opts, - state->sh, state->derefctx->orig_dn, - state->opts->group_map[SDAP_AT_GROUP_MEMBER].name, - sdap_attrs, num_maps, maps, timeout); - if (!subreq) { - ret = EIO; - goto fail; - } - talloc_steal(subreq, sdap_attrs); - talloc_steal(subreq, maps); - - tevent_req_set_callback(subreq, sdap_nested_group_process_deref, req); - return EOK; - -fail: - talloc_free(sdap_attrs); - talloc_free(maps); - return ret; -} - -static errno_t sdap_nested_group_process_noderef(struct tevent_req *req) -{ - struct sdap_nested_group_ctx *state = - tevent_req_data(req, struct sdap_nested_group_ctx); - struct sdap_deref_ctx *dctx = state->derefctx; - errno_t ret; - - if (dctx->expired_users_index < dctx->expired_users_num) { - state->member_dn = dctx->expired_users[dctx->expired_users_index]; - DEBUG(8, ("Refreshing expired user [%s]\n", state->member_dn)); - - ret = sdap_nested_group_lookup_user( - req, sdap_nested_group_process_user); - if (ret != EOK) goto done; - return EAGAIN; - } - - if (dctx->expired_groups_index < dctx->expired_groups_num) { - state->member_dn = dctx->expired_groups[dctx->expired_groups_index]; - DEBUG(8, ("Refreshing expired group [%s]\n", state->member_dn)); - - ret = sdap_nested_group_lookup_group(req); - if (ret != EOK) goto done; - return EAGAIN; - } - - if (dctx->missing_dns_index < dctx->missing_dns_num) { - state->member_dn = dctx->missing_dns[dctx->missing_dns_index]; - DEBUG(8, ("Looking up missing DN [%s]\n", state->member_dn)); - - /* Try users first for generic missing DNs */ - ret = sdap_nested_group_lookup_user( - req, sdap_nested_group_process_ldap_user); - if (ret != EOK) goto done; - return EAGAIN; - } - - ret = EOK; -done: - return ret; -} - -static errno_t sdap_nested_group_lookup_user(struct tevent_req *req, - tevent_req_fn fn) -{ - char *search_bases_filter = NULL; - struct tevent_req *subreq; - struct sdap_nested_group_ctx *state = - tevent_req_data(req, struct sdap_nested_group_ctx); - errno_t ret; - - /* - * If dn is not in user search base and object may be group - * continue with group lookup. If it can't be group, skip it. - */ - if (!sss_ldap_dn_in_search_bases(state, state->member_dn, - state->opts->user_search_bases, - &search_bases_filter)) { - if (fn == sdap_nested_group_process_ldap_user) { - return sdap_nested_group_lookup_group(req); - } else if (fn == sdap_nested_group_process_user) { - if (state->derefctx) { - state->derefctx->expired_users_index++; - ret = sdap_nested_group_process_noderef(req); - } else { - state->member_index++; - talloc_zfree(state->member_dn); - ret = sdap_nested_group_process_step(req); - } - - if (ret != EOK && ret != EAGAIN) { - DEBUG(SSSDBG_OP_FAILURE, ("Nested group processing failed\n")); - return ret; - } else if (ret == EOK) { - DEBUG(SSSDBG_TRACE_FUNC, ("All done.\n")); - tevent_req_done(req); - - /** - * FIXME: Rewrite nested group processing so we call - * tevent_req_post() only in _send(). - */ - if (state->send_finished == false) { - tevent_req_post(req, state->ev); - } - } - return EOK; - } - /* - * Something else? Continue. - */ - } - - subreq = sdap_nested_get_user_send(state, state->ev, state->domain, - state->sysdb, state->opts, state->sh, - state->member_dn, search_bases_filter); - if (!subreq) { - return EIO; - } - talloc_steal(subreq, search_bases_filter); - tevent_req_set_callback(subreq, fn, req); - return EOK; -} - -static void sdap_nested_group_process_group(struct tevent_req *subreq); -static errno_t sdap_nested_group_lookup_group(struct tevent_req *req) -{ - errno_t ret; - const char **sdap_attrs; - char *filter; - char *search_bases_filter = NULL; - struct tevent_req *subreq; - struct sdap_nested_group_ctx *state = - tevent_req_data(req, struct sdap_nested_group_ctx); - - /* - * If dn is not in group search base, skip it. - */ - if (!sss_ldap_dn_in_search_bases(state, state->member_dn, - state->opts->group_search_bases, - &search_bases_filter)) { - if (state->derefctx) { - if (state->derefctx->expired_groups_index < - state->derefctx->expired_groups_num) { - state->derefctx->expired_groups_index++; - } else { - state->derefctx->missing_dns_index++; - } - ret = sdap_nested_group_process_noderef(req); - } else { - state->member_index++; - talloc_zfree(state->member_dn); - ret = sdap_nested_group_process_step(req); - } - - if (ret != EOK && ret != EAGAIN) { - DEBUG(SSSDBG_OP_FAILURE, ("Nested group processing failed\n")); - return ret; - } else if (ret == EOK) { - DEBUG(SSSDBG_TRACE_FUNC, ("All done.\n")); - tevent_req_done(req); - - /** - * FIXME: Rewrite nested group processing so we call - * tevent_req_post() only in _send(). - */ - if (state->send_finished == false) { - tevent_req_post(req, state->ev); - } - } - return EOK; - } - - ret = build_attrs_from_map(state, state->opts->group_map, SDAP_OPTS_GROUP, - NULL, &sdap_attrs, NULL); - if (ret != EOK) { - return ret; - } - - if (search_bases_filter != NULL) { - filter = talloc_asprintf(sdap_attrs, "(&%s(objectclass=%s)(%s=*))", - search_bases_filter, - state->opts->group_map[SDAP_OC_GROUP].name, - state->opts->group_map[SDAP_AT_GROUP_NAME].name); - } else { - filter = talloc_asprintf(sdap_attrs, "(&(objectclass=%s)(%s=*))", - state->opts->group_map[SDAP_OC_GROUP].name, - state->opts->group_map[SDAP_AT_GROUP_NAME].name); - } - if (!filter) { - talloc_free(sdap_attrs); - return ENOMEM; - } - - subreq = sdap_get_generic_send(state, state->ev, state->opts, - state->sh, state->member_dn, - LDAP_SCOPE_BASE, - filter, sdap_attrs, - state->opts->group_map, - SDAP_OPTS_GROUP, - dp_opt_get_int(state->opts->basic, - SDAP_SEARCH_TIMEOUT), - false); - if (!subreq) { - talloc_free(sdap_attrs); - return EIO; - } - talloc_steal(subreq, sdap_attrs); - - tevent_req_set_callback(subreq, sdap_nested_group_process_group, req); - return EOK; -} - -static void sdap_nested_group_process_user(struct tevent_req *subreq) -{ - errno_t ret; - struct tevent_req *req = - tevent_req_callback_data(subreq, struct tevent_req); - struct sdap_nested_group_ctx *state = - tevent_req_data(req, struct sdap_nested_group_ctx); - TALLOC_CTX *tmp_ctx; - size_t count = 0; - struct sysdb_attrs **replies = NULL; - int hret; - hash_key_t key; - hash_value_t value; - - tmp_ctx = talloc_new(NULL); - if (!tmp_ctx) { - tevent_req_error(req, ENOMEM); - return; - } - - ret = sdap_nested_get_user_recv(subreq, tmp_ctx, &count, &replies); - talloc_zfree(subreq); - if (ret != EOK && ret != ENOENT) { - tevent_req_error(req, ret); - goto done; - } else if (ret == ENOENT || count == 0) { - /* Nothing to do if the user doesn't exist */ - goto skip; - } - - if (count != 1) { - /* There should only ever be one reply for a - * BASE search. If otherwise, it's a serious - * error. - */ - DEBUG(1,("Received multiple replies for a BASE search!\n")); - tevent_req_error(req, EIO); - goto done; - } - - /* Save the user attributes to the user hash so we can store - * them all at once later. - */ - - key.type = HASH_KEY_STRING; - key.str = state->member_dn; - - value.type = HASH_VALUE_PTR; - value.ptr = replies[0]; - - hret = hash_enter(state->users, &key, &value); - if (hret != HASH_SUCCESS) { - tevent_req_error(req, EIO); - goto done; - } - talloc_steal(state->users, replies[0]); - -skip: - if (state->derefctx) { - state->derefctx->expired_users_index++; - ret = sdap_nested_group_process_noderef(req); - } else { - state->member_index++; - talloc_zfree(state->member_dn); - ret = sdap_nested_group_process_step(req); - } - - if (ret == EOK) { - /* EOK means it's complete */ - tevent_req_done(req); - } else if (ret != EAGAIN) { - tevent_req_error(req, ret); - } - - /* EAGAIN means that we should re-enter - * the mainloop - */ - -done: - talloc_free(tmp_ctx); -} - -static void sdap_group_internal_nesting_done(struct tevent_req *subreq); -static void sdap_nested_group_process_group(struct tevent_req *subreq) -{ - errno_t ret; - struct tevent_req *req = - tevent_req_callback_data(subreq, struct tevent_req); - struct sdap_nested_group_ctx *state = - tevent_req_data(req, struct sdap_nested_group_ctx); - TALLOC_CTX *tmp_ctx; - size_t count; - struct sysdb_attrs **replies; - - tmp_ctx = talloc_new(NULL); - if (!tmp_ctx) { - tevent_req_error(req, ENOMEM); - return; - } - - ret = sdap_get_generic_recv(subreq, tmp_ctx, &count, &replies); - talloc_zfree(subreq); - if (ret != EOK && ret != ENOENT) { - tevent_req_error(req, ret); - goto done; - } else if (ret == ENOENT || count == 0) { - /* Nothing to do if the group doesn't exist */ - goto skip; - } - - if (count != 1) { - /* There should only ever be one reply for a - * BASE search. If otherwise, it's a serious - * error. - */ - DEBUG(1,("Received multiple replies for a BASE search!\n")); - tevent_req_error(req, EIO); - goto done; - } - - /* Recurse down into the member group */ - subreq = sdap_nested_group_process_send(state, state->ev, state->domain, - state->sysdb, replies[0], - state->users, state->groups, - state->opts, state->sh, - state->enable_deref, - state->nesting_level + 1); - if (!subreq) { - tevent_req_error(req, EIO); - goto done; - } - tevent_req_set_callback(subreq, sdap_group_internal_nesting_done, req); - - talloc_free(tmp_ctx); - return; - -skip: - if (state->derefctx) { - if (state->derefctx->expired_groups_index < - state->derefctx->expired_groups_num) { - state->derefctx->expired_groups_index++; - } else { - state->derefctx->missing_dns_index++; - } - ret = sdap_nested_group_process_noderef(req); - } else { - state->member_index++; - talloc_zfree(state->member_dn); - ret = sdap_nested_group_process_step(req); - } - - if (ret == EOK) { - /* EOK means it's complete */ - tevent_req_done(req); - } else if (ret != EAGAIN) { - tevent_req_error(req, ret); - } - - /* EAGAIN means that we should re-enter - * the mainloop - */ - -done: - talloc_free(tmp_ctx); -} - -static void sdap_group_internal_nesting_done(struct tevent_req *subreq) -{ - errno_t ret; - struct tevent_req *req = - tevent_req_callback_data(subreq, struct tevent_req); - struct sdap_nested_group_ctx *state = - tevent_req_data(req, struct sdap_nested_group_ctx); - - ret = sdap_nested_group_process_recv(subreq); - talloc_zfree(subreq); - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } - - if (state->derefctx) { - if (state->derefctx->expired_groups_index < - state->derefctx->expired_groups_num) { - state->derefctx->expired_groups_index++; - } else { - state->derefctx->missing_dns_index++; - } - - state->derefctx->expired_users_index++; - ret = sdap_nested_group_process_noderef(req); - } else { - state->member_index++; - talloc_zfree(state->member_dn); - ret = sdap_nested_group_process_step(req); - } - - if (ret == EOK) { - /* EOK means it's complete */ - tevent_req_done(req); - } else if (ret != EAGAIN) { - tevent_req_error(req, ret); - } - - /* EAGAIN means that we should re-enter - * the mainloop - */ -} - -static void sdap_nested_group_process_ldap_user(struct tevent_req *subreq) -{ - errno_t ret; - struct tevent_req *req = - tevent_req_callback_data(subreq, struct tevent_req); - struct sdap_nested_group_ctx *state = - tevent_req_data(req, struct sdap_nested_group_ctx); - TALLOC_CTX *tmp_ctx; - size_t count = 0; - struct sysdb_attrs **replies = NULL; - int hret; - hash_key_t key; - hash_value_t value; - - tmp_ctx = talloc_new(NULL); - if (!tmp_ctx) { - tevent_req_error(req, ENOMEM); - return; - } - - ret = sdap_nested_get_user_recv(subreq, tmp_ctx, &count, &replies); - talloc_zfree(subreq); - if (ret != EOK && ret != ENOENT) { - tevent_req_error(req, ret); - goto done; - } else if (ret == ENOENT || count == 0) { - /* No user found. Assume it's a group */ - ret = sdap_nested_group_lookup_group(req); - if (ret != EOK) { - tevent_req_error(req, ret); - } - goto done; - } - - if (count != 1) { - /* There should only ever be one reply for a - * BASE search. If otherwise, it's a serious - * error. - */ - DEBUG(1,("Received multiple replies for a BASE search!\n")); - tevent_req_error(req, EIO); - goto done; - } - - /* Save the user attributes to the user hash so we can store - * them all at once later. - */ - key.type = HASH_KEY_STRING; - key.str = state->member_dn; - - value.type = HASH_VALUE_PTR; - value.ptr = replies[0]; - - hret = hash_enter(state->users, &key, &value); - if (hret != HASH_SUCCESS) { - tevent_req_error(req, EIO); - goto done; - } - talloc_steal(state->users, replies[0]); - - /* Move on to the next member */ - if (state->derefctx) { - state->derefctx->missing_dns_index++; - ret = sdap_nested_group_process_noderef(req); - } else { - state->member_index++; - talloc_zfree(state->member_dn); - ret = sdap_nested_group_process_step(req); - } - - if (ret == EOK) { - /* EOK means it's complete */ - tevent_req_done(req); - } else if (ret != EAGAIN) { - tevent_req_error(req, ret); - } - - /* EAGAIN means that we should re-enter - * the mainloop - */ - -done: - talloc_free(tmp_ctx); -} - -static errno_t -sdap_nested_group_process_deref_result(struct tevent_req *req); - -static void sdap_nested_group_process_deref(struct tevent_req *subreq) -{ - errno_t ret; - struct tevent_req *req = - tevent_req_callback_data(subreq, struct tevent_req); - struct sdap_nested_group_ctx *state = - tevent_req_data(req, struct sdap_nested_group_ctx); - - ret = sdap_deref_search_recv(subreq, state->derefctx, - &state->derefctx->num_results, - &state->derefctx->deref_result); - talloc_zfree(subreq); - if (ret == ENOTSUP) { - ret = sdap_nested_group_process_noderef(req); - if (ret != EAGAIN) { - if (ret == EOK) { - tevent_req_done(req); - } else { - tevent_req_error(req, ret); - } - } - return; - } else if (ret != EOK && ret != ENOENT) { - tevent_req_error(req, ret); - return; - } else if (ret == ENOENT || state->derefctx->deref_result == NULL) { - /* Nothing could be dereferenced. Done. */ - tevent_req_done(req); - return; - } - - state->derefctx->result_index = 0; - - DEBUG(8, ("Received %d dereference results, about to process them\n", - state->derefctx->num_results)); - ret = sdap_nested_group_process_deref_result(req); - if (ret == EOK) { - tevent_req_done(req); - } else if (ret != EAGAIN) { - tevent_req_error(req, ret); - } - - /* EAGAIN means a recursive search is in progress */ -} - -static void -sdap_nested_group_process_deref_recurse_done(struct tevent_req *subreq); - -static errno_t -sdap_nested_group_process_deref_result(struct tevent_req *req) -{ - struct sdap_nested_group_ctx *state = - tevent_req_data(req, struct sdap_nested_group_ctx); - struct tevent_req *subreq; - hash_key_t key; - hash_value_t value; - int hret; - const char *orig_dn; - errno_t ret; - struct sdap_deref_ctx *dctx = state->derefctx; - const char *tmp_name; - size_t i; - - while (dctx->result_index < dctx->num_results) { - /* Add to appropriate hash table */ - ret = sysdb_attrs_get_string( - dctx->deref_result[dctx->result_index]->attrs, - SYSDB_ORIG_DN, &orig_dn); - if (ret != EOK) { - DEBUG(2, ("The entry has no originalDN\n")); - return ret; - } - - /* Ensure that all members returned from the deref request are included - * in the member processing. Sometimes we will get more results back from - * deref/asq than we got from the initial lookup, as is the case with - * Active Directory and its range retrieval mechanism. - */ - for (i = 0; i < state->members->num_values; i++) { - /* FIXME: This is inefficient for very large sets of groups */ - if (strcasecmp((const char *)state->members->values[i].data, - orig_dn) == 0) break; - } - if (i >= state->members->num_values) { - state->members->values = talloc_realloc(state, - state->members->values, - struct ldb_val, - state->members->num_values + 1); - if (!state->members->values) { - return ENOMEM; - } - state->members->values[state->members->num_values].data = - (uint8_t *)talloc_strdup(state->members->values, orig_dn); - if (!state->members->values[state->members->num_values].data) { - return ENOMEM; - } - state->members->values[state->members->num_values].length = strlen(orig_dn); - state->members->num_values++; - } - - if (dctx->deref_result[dctx->result_index]->map == \ - state->opts->user_map) { - - /* check if the user is in search base */ - if (!sss_ldap_dn_in_search_bases(state, orig_dn, - state->opts->user_search_bases, - NULL)) { - dctx->result_index++; - continue; - } - - DEBUG(9, ("Found member user [%s]\n", orig_dn)); - - key.type = HASH_KEY_STRING; - key.str = talloc_strdup(state, orig_dn); - - value.type = HASH_VALUE_PTR; - value.ptr = dctx->deref_result[dctx->result_index]->attrs; - - hret = hash_enter(state->users, &key, &value); - if (hret != HASH_SUCCESS) return EIO; - - talloc_steal(state->users, - dctx->deref_result[dctx->result_index]->attrs); - dctx->result_index++; - } else if (dctx->deref_result[dctx->result_index]->map == \ - state->opts->group_map) { - ret = sysdb_attrs_get_string(dctx->deref_result[dctx->result_index]->attrs, - state->opts->group_map[SDAP_AT_GROUP_NAME].sys_name, - &tmp_name); - if (ret == ENOENT) { - DEBUG(7, ("Dereferenced a group without name, skipping ...\n")); - } else if (ret) { - return EIO; - } - - /* check if the group is in search base */ - if (!sss_ldap_dn_in_search_bases(state, orig_dn, - state->opts->group_search_bases, - NULL)) { - dctx->result_index++; - continue; - } - - DEBUG(6, ("Recursing down a nested group\n")); - subreq = sdap_nested_group_process_send(state, state->ev, - state->domain, state->sysdb, - dctx->deref_result[dctx->result_index]->attrs, - state->users, state->groups, - state->opts, state->sh, - state->enable_deref, - state->nesting_level + 1); - if (!subreq) return EIO; - - tevent_req_set_callback(subreq, - sdap_nested_group_process_deref_recurse_done, - req); - return EAGAIN; - } else { - /* This should never happen, but if it does, - * do not loop forever */ - DEBUG(2, ("Entry does not match any known map, skipping\n")); - dctx->result_index++; - continue; - } - } - - /* All deref results processed */ - DEBUG(8, ("All dereference results processed\n")); - return EOK; -} - -static void -sdap_nested_group_process_deref_recurse_done(struct tevent_req *subreq) -{ - errno_t ret; - struct tevent_req *req = - tevent_req_callback_data(subreq, struct tevent_req); - struct sdap_nested_group_ctx *state = - tevent_req_data(req, struct sdap_nested_group_ctx); - - ret = sdap_nested_group_process_recv(subreq); - talloc_zfree(subreq); - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } - - state->derefctx->result_index++; - - ret = sdap_nested_group_process_deref_result(req); - if (ret == EOK) { - tevent_req_done(req); - } else if (ret != EAGAIN) { - tevent_req_error(req, ret); - } - - /* EAGAIN means a recursive search is in progress */ -} - -static errno_t sdap_nested_group_process_recv(struct tevent_req *req) -{ - TEVENT_REQ_RETURN_ON_ERROR(req); - - return EOK; -} diff --git a/src/providers/ldap/sdap_async_private.h b/src/providers/ldap/sdap_async_private.h index 71cb2e5..488387e 100644 --- a/src/providers/ldap/sdap_async_private.h +++ b/src/providers/ldap/sdap_async_private.h @@ -112,4 +112,20 @@ errno_t get_sysdb_grouplist(TALLOC_CTX *mem_ctx, const char *name, char ***grouplist); +/* from sdap_async_nested_groups.c */ + +struct tevent_req *sdap_nested_group_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sss_domain_info *domain, + struct sdap_options *opts, + struct sdap_handle *sh, + struct sysdb_attrs *group); + +errno_t sdap_nested_group_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + unsigned long *_num_users, + struct sysdb_attrs ***_users, + unsigned long *_num_groups, + struct sysdb_attrs ***_groups); + #endif /* _SDAP_ASYNC_PRIVATE_H_ */