summaryrefslogtreecommitdiffstats
path: root/src/providers/ldap/sdap_async_groups.c
diff options
context:
space:
mode:
authorPavel Březina <pbrezina@redhat.com>2013-02-18 10:28:07 +0100
committerJakub Hrozek <jhrozek@redhat.com>2013-04-02 15:33:03 +0200
commit755aee449c6311518200c2f11c1aae329a19b038 (patch)
tree035da595452433b260eed5b2e8a27eb7ccd71b8a /src/providers/ldap/sdap_async_groups.c
parent02b2c042d0c2ace289583c8e5e4ead1eff481376 (diff)
downloadsssd-755aee449c6311518200c2f11c1aae329a19b038.tar.gz
sssd-755aee449c6311518200c2f11c1aae329a19b038.tar.xz
sssd-755aee449c6311518200c2f11c1aae329a19b038.zip
refactor nested group processing: replace old code
https://fedorahosted.org/sssd/ticket/1784
Diffstat (limited to 'src/providers/ldap/sdap_async_groups.c')
-rw-r--r--src/providers/ldap/sdap_async_groups.c1726
1 files changed, 5 insertions, 1721 deletions
diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c
index 4d1ece840..9d4a84871 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;
-}