sdap_async_groups.c revision 2f3ee3f49019f5b60adbe073070f31e6e2d7c7ab
/*
SSSD
Async LDAP Helper routines - retrieving groups
Copyright (C) Simo Sorce <ssorce@redhat.com> - 2009
Copyright (C) 2010, Ralf Haferkamp <rhafer@suse.de>, Novell Inc.
Copyright (C) Jan Zeleny <jzeleny@redhat.com> - 2011
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "providers/ldap/sdap_async_private.h"
#include "providers/ldap/ldap_common.h"
/* ==Group-Parsing Routines=============================================== */
struct sss_domain_info *domain,
const char *orig_dn,
char **localdn)
{
char *filter;
struct ldb_message **msgs;
int ret;
char *sanitized_dn;
if (!tmpctx) {
return ENOMEM;
}
goto done;
}
if (!filter) {
goto done;
}
if (!base_dn) {
goto done;
}
if (ret) {
goto done;
}
if (num_msgs != 1) {
goto done;
}
if (!*localdn) {
goto done;
}
done:
return ret;
}
struct sdap_options *opts,
struct sss_domain_info *domain,
int num_values)
{
struct ldb_message_element *el;
int i, j;
int ret;
switch (opts->schema_type) {
case SDAP_SCHEMA_RFC2307:
values, num_values);
if (ret) {
goto done;
}
break;
case SDAP_SCHEMA_RFC2307BIS:
case SDAP_SCHEMA_IPA_V1:
case SDAP_SCHEMA_AD:
if (ret) {
goto done;
}
/* Just allocate both big enough to contain all members for now */
goto done;
}
/* sync search entry with this as origDN */
goto done;
}
} else {
j++;
}
}
el->num_values = j;
break;
default:
DEBUG(0, ("FATAL ERROR: Unhandled schema type! (%d)\n",
opts->schema_type));
goto done;
}
done:
return ret;
}
/* ==Save-Group-Entry===================================================== */
/* FIXME: support non legacy */
/* FIXME: support storing additional attributes */
static errno_t
const char *name,
struct sysdb_attrs *group_attrs,
bool posix_group,
{
/* make sure that non-posix (empty or explicit gid=0) groups have the
* gidNumber set to zero even if updating existing group */
if (!posix_group) {
if (ret) {
return ret;
}
}
if (ret) {
return ret;
}
return ret;
}
struct sdap_options *opts,
struct sss_domain_info *dom,
struct sysdb_attrs *attrs,
bool store_members,
bool populate_members,
char **_usn_value,
{
struct ldb_message_element *el;
struct sysdb_attrs *group_attrs;
int ret;
bool posix_group;
if (!tmpctx) {
goto fail;
}
if (group_attrs == NULL) {
goto fail;
}
&name);
goto fail;
}
posix_group = true;
goto fail;
}
goto fail;
}
&gid);
goto fail;
}
/* check that the gid is valid for this domain */
if (posix_group) {
name));
goto fail;
}
/* Group ID OK */
}
name, group_attrs);
goto fail;
}
"original mod-Timestamp",
name, group_attrs);
goto fail;
}
if (ret) {
goto fail;
}
if (el->num_values == 0) {
name));
} else {
if (ret) {
goto fail;
}
if (!usn_value) {
goto fail;
}
}
if (populate_members) {
struct ldb_message_element *el1;
goto fail;
}
goto fail;
}
} else if (store_members) {
goto fail;
}
if (el->num_values == 0) {
} else {
if (ret) {
goto fail;
}
}
}
goto fail;
}
posix_group, now);
if (_usn_value) {
}
return EOK;
fail:
return ret;
}
/* ==Save-Group-Memebrs=================================================== */
/* FIXME: support non legacy */
/* FIXME: support storing additional attributes */
struct sdap_options *opts,
struct sss_domain_info *dom,
struct sysdb_attrs *attrs,
{
struct ldb_message_element *el;
const char *name;
int ret;
&name);
goto fail;
}
goto fail;
}
if (el->num_values == 0) {
} else {
if (!group_attrs) {
goto fail;
}
if (ret) {
goto fail;
}
}
return EOK;
fail:
return ret;
}
/* ==Generic-Function-to-save-multiple-groups============================= */
struct sss_domain_info *dom,
struct sdap_options *opts,
struct sysdb_attrs **groups,
int num_groups,
bool populate_members,
char **_usn_value)
{
char *higher_usn = NULL;
char *usn_value;
bool twopass;
int ret;
int i;
int nsaved_groups = 0;
switch (opts->schema_type) {
case SDAP_SCHEMA_RFC2307:
twopass = false;
break;
case SDAP_SCHEMA_RFC2307BIS:
case SDAP_SCHEMA_IPA_V1:
case SDAP_SCHEMA_AD:
twopass = true;
break;
default:
return EINVAL;
}
if (!tmpctx) {
return ENOMEM;
}
if (ret) {
goto done;
}
if (twopass && !populate_members) {
if (!saved_groups) {
goto done;
}
}
for (i = 0; i < num_groups; i++) {
/* if 2 pass savemembers = false */
/* Do not fail completely on errors.
* Just report the failure to save and go on */
if (ret) {
} else {
if (twopass && !populate_members) {
}
}
if (usn_value) {
if (higher_usn) {
} else {
}
} else {
}
}
}
if (twopass && !populate_members) {
for (i = 0; i < nsaved_groups; i++) {
/* Do not fail completely on errors.
* Just report the failure to save and go on */
if (ret) {
} else {
}
}
}
if (ret) {
goto done;
}
if (_usn_value) {
}
done:
return ret;
}
/* ==Process-Groups======================================================= */
struct sdap_process_group_state {
struct tevent_context *ev;
struct sdap_options *opts;
struct sdap_handle *sh;
struct sss_domain_info *dom;
struct sysdb_attrs *group;
struct sysdb_attrs **new_members;
struct ldb_message_element* sysdb_dns;
char **queued_members;
int queue_len;
const char **attrs;
const char *filter;
bool enumeration;
};
#define GROUPMEMBER_REQ_PARALLEL 50
struct sdap_process_group_state *state,
struct ldb_message_element *memberel);
struct ldb_message_element *memberel);
struct tevent_context *ev,
struct sss_domain_info *dom,
struct sdap_options *opts,
struct sdap_handle *sh,
struct sysdb_attrs *group,
bool enumeration)
{
struct ldb_message_element *el;
struct sdap_process_group_state *grp_state;
const char **attrs;
char* filter;
int ret;
struct sdap_process_group_state);
if (ret) {
goto done;
}
/* FIXME: we ignore nested rfc2307bis groups for now */
if (!filter) {
return NULL;
}
grp_state->check_count = 0;
grp_state->member_idx = 0;
&el);
if (ret) {
goto done;
}
/* Group without members */
if (el->num_values == 0) {
goto done;
}
return NULL;
}
el->num_values);
return NULL;
}
switch (opts->schema_type) {
case SDAP_SCHEMA_RFC2307:
break;
case SDAP_SCHEMA_IPA_V1:
case SDAP_SCHEMA_AD:
case SDAP_SCHEMA_RFC2307BIS:
break;
default:
break;
}
done:
/* We managed to process all the entries */
/* EBUSY means we need to wait for entries in LDAP */
}
}
return req;
}
static int
char *user_dn,
int num_users)
{
struct sdap_process_group_state *grp_state =
struct tevent_req *subreq;
/*
* Issue at most GROUPMEMBER_REQ_PARALLEL LDAP searches at once.
* The rest is sent while the results are being processed.
* We limit the number as of request here, as the Server might
* enforce limits on the number of pending operations per
* connection.
*/
if (!grp_state->queued_members) {
if (!grp_state->queued_members) {
return ENOMEM;
}
}
} else {
false);
if (!subreq) {
return ENOMEM;
}
}
grp_state->check_count++;
return EOK;
}
static int
struct sdap_process_group_state *state,
struct ldb_message_element *memberel)
{
char *member_dn;
char *strdn;
int ret;
int i;
for (i=0; i < memberel->num_values; i++) {
&strdn);
/*
* User already cached in sysdb. Remember the sysdb DN for later
* use by sdap_save_groups()
*/
if (!state->enumeration) {
/* The user is not in sysdb, need to add it
* We don't need to do this if we're in an enumeration,
* because all real members should all be populated
* already by the first pass of the enumeration.
* Also, we don't want to be holding the sysdb
* transaction while we're performing LDAP lookups.
*/
i, member_dn));
return ret;
}
}
} else {
return ret;
}
}
}
if (state->check_count == 0) {
/*
* All group members are already cached in sysdb, we are done
* with this group. To avoid redundant sysdb lookups, populate the
* "member" attribute of the group entry with the sysdb DNs of
* the members.
*/
} else {
struct sysdb_attrs *,
if (!state->new_members) {
return ENOMEM;
}
}
return ret;
}
static int
const char *username)
{
char *strdn;
if (!strdn) {
return ENOMEM;
}
return EOK;
}
static int
char *member_name, bool *in_transaction,
{
const char *filter;
const char *username;
if (!in_transaction) return EINVAL;
/* Check for the alias in the sysdb */
if (!filter) {
goto fail;
}
/* Entry exists but the group references it with an alias. */
if (count != 1) {
goto fail;
}
/* fill username with primary name */
goto done;
goto fail;
}
/* The entry really does not exist, add a fake entry */
if (!*in_transaction) {
return ret;
}
*in_transaction = true;
}
goto fail;
}
/*
* Convert the just received DN into the corresponding sysdb DN
* for saving into member attribute of the group
*/
done:
goto fail;
}
return EOK;
fail:
if (*in_transaction) {
*in_transaction = false;
} else {
DEBUG(0, ("Unable to cancel transaction! [%d][%s]\n",
}
}
return ret;
}
static int
struct ldb_message_element *memberel)
{
struct ldb_message *msg;
bool in_transaction = false;
char *member_name;
int ret;
int i;
for (i=0; i < memberel->num_values; i++) {
/* We need to skip over zero-length usernames */
if (member_name[0] == '\0') continue;
/*
* User already cached in sysdb. Remember the sysdb DN for later
* use by sdap_save_groups()
*/
goto done;
}
/* The user is not in sysdb, need to add it */
i, member_name));
&in_transaction, now);
i, member_name));
goto done;
}
} else {
goto done;
}
}
/* sdap_process_missing_member_2307 starts transaction */
if (in_transaction) {
if (ret) {
goto done;
}
in_transaction = false;
}
done:
if (in_transaction) {
/* If the transaction is still active here, we need to cancel it */
DEBUG(0, ("Unable to cancel transaction! [%d][%s]\n",
}
}
return ret;
}
{
struct sysdb_attrs **usr_attrs;
int ret;
struct tevent_req *req =
struct sdap_process_group_state *state =
struct ldb_message_element *el;
char* dn_string;
state->check_count--;
if (ret) {
goto next;
}
if (count != 1) {
goto next;
}
if (el->num_values == 0) {
}
if (ret) {
goto next;
}
/*
* Convert the just received DN into the corresponding sysdb DN
* for later usage by sdap_save_groups()
*/
if (!dn) {
return;
}
if (!dn_string) {
return;
}
state->member_idx++;
next:
if (ret) {
}
/* Are there more searches for uncached users to submit ? */
false);
if (!subreq) {
return;
}
}
if (state->check_count == 0) {
if (ret) {
return;
}
/*
* To avoid redundant sysdb lookups, populate the "member" attribute
* of the group entry with the sysdb DNs of the members.
*/
}
}
{
return EOK;
}
/* ==Search-Groups-with-filter============================================ */
struct sdap_get_groups_state {
struct tevent_context *ev;
struct sdap_options *opts;
struct sdap_handle *sh;
struct sss_domain_info *dom;
const char **attrs;
const char *base_filter;
char *filter;
int timeout;
bool enumeration;
char *higher_usn;
struct sysdb_attrs **groups;
struct sdap_search_base **search_bases;
};
struct tevent_context *ev,
struct sss_domain_info *dom,
struct sdap_options *opts,
struct sdap_search_base **search_bases,
struct sdap_handle *sh,
const char **attrs,
const char *filter,
int timeout,
bool enumeration)
{
struct tevent_req *req;
struct sdap_get_groups_state *state;
if (!search_bases) {
("Group lookup request without a search base\n"));
goto done;
}
done:
}
return req;
}
{
struct tevent_req *subreq;
struct sdap_get_groups_state *state;
return ENOMEM;
}
("Searching for groups with base [%s]\n",
if (!subreq) {
return ENOMEM;
}
return EOK;
}
static struct tevent_req *sdap_nested_group_process_send(
struct sss_domain_info *domain,
{
struct tevent_req *req =
struct sdap_get_groups_state *state =
int ret;
int i;
bool next_base = false;
struct sysdb_attrs **groups;
bool enable_deref = true;
if (ret) {
return;
}
("Individual group search returned multiple results\n"));
return;
}
next_base = true;
}
/* Add this batch of groups to the list */
if (count > 0) {
struct sysdb_attrs *,
return;
}
/* Copy the new groups into the list
*/
for (i = 0; i < count; i++) {
}
}
("Individual group search returned multiple results\n"));
return;
}
next_base = true;
}
if (next_base) {
/* There are more search bases to try */
}
return;
}
}
/* No more search bases
* Return ENOENT if no groups were found
*/
return;
}
/* Check whether we need to do nested searches
* for RFC2307bis/FreeIPA/ActiveDirectory
* We don't need to do this for enumeration,
* because all groups will be picked up anyway.
*/
if (!state->enumeration) {
/* Prepare hashes for nested user processing */
return;
}
return;
}
/*
* If any search base contains filter, disable dereference.
*/
enable_deref = true;
("User search base contains filter, "
"dereference will be disabled\n"));
enable_deref = false;
break;
}
}
if (enable_deref) {
("Group search base contains filter, "
"dereference will be disabled\n"));
enable_deref = false;
break;
}
}
}
0);
if (!subreq) {
return;
}
return;
}
}
/* We have all of the groups. Save them to the sysdb */
DEBUG(0, ("Failed to start transaction\n"));
return;
}
if (state->enumeration
"to allow unrolling of nested groups.\n"));
if (ret) {
return;
}
}
state->enumeration);
if (!subreq) {
return;
}
}
}
{
struct tevent_req *req =
struct sdap_get_groups_state *state =
int ret;
if (ret) {
DEBUG(0, ("Could not cancel sysdb transaction\n"));
}
return;
}
state->check_count--;
if (state->check_count == 0) {
&state->higher_usn);
if (ret) {
return;
}
DEBUG(0, ("Couldn't commit transaction\n"));
} else {
}
}
}
{
struct sdap_get_groups_state);
if (usn_value) {
}
return EOK;
}
struct sdap_options *opts,
struct sysdb_attrs **users,
int num_users);
{
int hret;
unsigned long i;
unsigned long user_count;
unsigned long group_count;
bool in_transaction = false;
struct tevent_req);
struct sdap_get_groups_state);
goto fail;
}
if (hret != HASH_SUCCESS) {
goto fail;
}
if (user_count) {
if (!users) {
goto fail;
}
for (i = 0; i < user_count; i++) {
}
}
/* Users are all saved. Now save groups */
if (hret != HASH_SUCCESS) {
goto fail;
}
if (!groups) {
goto fail;
}
for (i = 0; i < group_count; i++) {
}
/* Save all of the users first so that they are in
* place for the groups to add them.
*/
goto fail;
}
in_transaction = true;
users, user_count);
goto fail;
}
goto fail;
}
goto fail;
}
in_transaction = false;
/* Processing complete */
return;
fail:
if (in_transaction) {
}
}
}
struct sdap_options *opts,
struct sysdb_attrs **users,
int num_users)
{
int i;
struct ldb_message_element *el;
const char *username;
char *clean_orig_dn;
const char *original_dn;
struct ldb_message **msgs;
char *filter;
const char *sysdb_name;
struct sysdb_attrs *attrs;
if (num_users == 0) {
/* Nothing to do if there are no users */
return EOK;
}
if (ret) {
goto done;
}
for (i = 0; i < num_users; i++) {
&username);
continue;
}
if (el->num_values == 0) {
}
goto done;
}
goto done;
}
/* Check for the specified origDN in the sysdb */
if (!filter) {
goto done;
}
goto done;
}
/* The entry is cached but expired. Update the username
* if needed. */
if (count != 1) {
continue;
}
/* Username is correct, continue */
continue;
}
if (!attrs) {
goto done;
}
}
/* If the entry does not exist add a fake user record */
continue;
} else {
}
}
if (ret) {
goto done;
}
done:
}
}
return ret;
}
struct sdap_deref_ctx {
const char *orig_dn;
char **expired_users;
char **expired_groups;
char **missing_dns;
struct sdap_deref_attrs **deref_result;
int deref_threshold;
};
struct sdap_nested_group_ctx {
struct tevent_context *ev;
struct sss_domain_info *domain;
struct sdap_options *opts;
struct sdap_handle *sh;
struct ldb_message_element *members;
char *member_dn;
bool enable_deref;
struct sdap_deref_ctx *derefctx;
};
static struct tevent_req *sdap_nested_group_process_send(
struct sss_domain_info *domain,
{
int hret;
struct tevent_req *req;
struct sdap_nested_group_ctx *state;
const char *groupname;
if (!req) {
return NULL;
}
/* If this is too many levels deep, just return success */
goto immediate;
}
/* Add the current group to the groups hash so we don't
* look it up more than once
*/
&groupname);
goto immediate;
}
goto immediate;
}
/* This group has already been processed
* (or is in progress)
* Skip it and just return success
*/
goto immediate;
}
&gid);
0);
goto immediate;
}
}
goto immediate;
}
} else if (ret) {
goto immediate;
}
if (hret != HASH_SUCCESS) {
goto immediate;
}
/* Process group memberships */
/* TODO: future enhancement, check for memberuid as well
*/
/* No members to process */
}
goto immediate;
}
state->member_index = 0;
goto immediate;
}
} else {
}
return req;
} else {
}
return req;
}
struct sss_domain_info *dom,
struct sdap_options *opts,
char *member_dn,
struct ldb_message ***_msgs,
enum sysdb_member_type *_mtype);
{
struct sdap_nested_group_ctx *state =
enum sysdb_member_type mtype;
if (!dctx->expired_users ||
!dctx->expired_groups ||
while (true) {
/* No more entries to check. Return success */
break;
}
/* Continue to loop through until all entries have been
* processed.
*/
break; /* All remaining members in hash, check missing */
goto done; /* Unexpected error */
}
/* The entry is cached and valid */
state->member_index++;
continue;
/* The entry is cached but needs refresh */
switch(mtype) {
case SYSDB_MEMBER_GROUP:
missing++;
state->member_index++;
continue;
case SYSDB_MEMBER_USER:
missing++;
state->member_index++;
continue;
default:
goto done;
}
/* 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_num++;
state->member_index++;
continue;
}
/* Unexpected error, skip this entry */
state->member_index++;
continue;
} /* while (true) */
if (missing == 0) {
goto done;
}
} else {
}
return EAGAIN;
done:
return ret;
}
{
struct sdap_nested_group_ctx *state =
enum sysdb_member_type mtype;
while (true) {
/* Continue to loop through until all entries have been
* processed.
*/
return EOK; /* All members in hash */
goto error; /* Unexpected error */
}
/* The entry is cached and valid */
state->member_index++;
continue;
/* The entry is cached but needs refresh */
switch(mtype) {
case SYSDB_MEMBER_GROUP:
break;
case SYSDB_MEMBER_USER:
break;
default:
goto error;
}
return EAGAIN;
/* It wasn't found in the cache either
* We'll have to do a blind lookup in LDAP
*/
/* Try users first */
goto error;
}
return EAGAIN;
}
/* Unexpected error, skip this entry */
state->member_index++;
continue;
} /* while (true) */
return ret;
}
static errno_t
{
bool has_key = false;
do {
/* No more entries to check. Return success */
return EOK;
}
return ENOMEM;
}
/* Check the user hash
* If it's there, we can save ourselves a trip to the
* sysdb and possibly LDAP as well
*/
if (has_key) {
state->member_index++;
continue;
}
} while (has_key);
return ENOENT;
}
static errno_t
struct sss_domain_info *dom,
struct sdap_options *opts,
char *dn,
struct ldb_message ***_msgs,
enum sysdb_member_type *_mtype)
{
char *member_dn;
NULL };
char *filter;
enum sysdb_member_type mtype;
goto fail;
}
/* Check for the specified origDN in the sysdb */
if (!filter) {
goto fail;
}
/* Try users first */
goto fail;
/* We found a user with this origDN in the sysdb. Check if it is valid
*/
/* Check whether the entry is valid */
if (count != 1) {
goto fail;
}
if (!user_uid) {
/* Refresh the fake user if he was created before cache_timeout */
0);
} else {
/* Regular user, check if we need a refresh */
0);
}
goto done;
}
/* Refresh the user from LDAP */
goto done;
}
/* It wasn't a user. Check whether it's a group */
goto fail;
/* We found a group with this origDN in the sysdb */
/* Check whether the entry is valid */
if (count != 1) {
goto fail;
}
0);
goto done;
}
/* Refresh the group from LDAP */
goto done;
}
/* It wasn't found in the groups either */
done:
}
return ret;
fail:
return ret;
}
static errno_t
{
struct tevent_req *subreq;
struct sdap_attr_map_info *maps;
const char **sdap_attrs;
int ret;
int timeout;
const int num_maps = 2;
struct sdap_nested_group_ctx *state =
/* Pull down the whole group map, but only pull down username
* and originalDN for users. */
SDAP_OPTS_GROUP + 2);
if (!sdap_attrs) {
goto fail;
}
if (!subreq) {
goto fail;
}
return EOK;
fail:
return ret;
}
{
struct sdap_nested_group_ctx *state =
return EAGAIN;
}
return EAGAIN;
}
/* Try users first for generic missing DNs */
return EAGAIN;
}
done:
return ret;
}
{
const char **sdap_attrs;
char *filter;
char *search_bases_filter = NULL;
struct tevent_req *subreq;
struct sdap_nested_group_ctx *state =
/*
* 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.
*/
&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) {
} else {
state->member_index++;
}
/* EOK means it's complete */
return ret;
}
return EOK;
}
/*
* Something else? Continue.
*/
}
/* Only pull down username and originalDN */
if (!sdap_attrs) return ENOMEM;
sdap_attrs[0] = "objectClass";
if (search_bases_filter != NULL) {
} else {
}
if (!filter) {
return ENOMEM;
}
false);
if (!subreq) {
return EIO;
}
return EOK;
}
{
const char **sdap_attrs;
char *filter;
char *search_bases_filter = NULL;
struct tevent_req *subreq;
struct sdap_nested_group_ctx *state =
/*
* If dn is not in group search base, skip it.
*/
&search_bases_filter)) {
} else {
}
} else {
state->member_index++;
}
/* EOK means it's complete */
return ret;
}
return EOK;
}
return ret;
}
if (search_bases_filter != NULL) {
} else {
}
if (!filter) {
return ENOMEM;
}
false);
if (!subreq) {
return EIO;
}
return EOK;
}
{
struct tevent_req *req =
struct sdap_nested_group_ctx *state =
struct sysdb_attrs **replies;
int hret;
if (!tmp_ctx) {
return;
}
goto done;
/* 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.
*/
goto done;
}
/* Save the user attributes to the user hash so we can store
* them all at once later.
*/
if (hret != HASH_SUCCESS) {
goto done;
}
skip:
} else {
state->member_index++;
}
/* EOK means it's complete */
}
/* EAGAIN means that we should re-enter
* the mainloop
*/
done:
}
{
struct tevent_req *req =
struct sdap_nested_group_ctx *state =
struct sysdb_attrs **replies;
if (!tmp_ctx) {
return;
}
goto done;
/* 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.
*/
goto done;
}
/* Recurse down into the member group */
if (!subreq) {
goto done;
}
return;
skip:
} else {
}
} else {
state->member_index++;
}
/* EOK means it's complete */
}
/* EAGAIN means that we should re-enter
* the mainloop
*/
done:
}
{
struct tevent_req *req =
struct sdap_nested_group_ctx *state =
return;
}
} else {
}
} else {
state->member_index++;
}
/* EOK means it's complete */
}
/* EAGAIN means that we should re-enter
* the mainloop
*/
}
{
struct tevent_req *req =
struct sdap_nested_group_ctx *state =
struct sysdb_attrs **replies;
int hret;
if (!tmp_ctx) {
return;
}
goto done;
/* No user found. Assume it's a group */
}
goto done;
}
if (count != 1) {
/* There should only ever be one reply for a
* BASE search. If otherwise, it's a serious
* error.
*/
goto done;
}
/* Save the user attributes to the user hash so we can store
* them all at once later.
*/
if (hret != HASH_SUCCESS) {
goto done;
}
/* Move on to the next member */
} else {
state->member_index++;
}
/* EOK means it's complete */
}
/* EAGAIN means that we should re-enter
* the mainloop
*/
done:
}
static errno_t
{
struct tevent_req *req =
struct sdap_nested_group_ctx *state =
return;
/* Nothing could be dereferenced. Done. */
return;
}
}
/* EAGAIN means a recursive search is in progress */
}
static void
static errno_t
{
struct sdap_nested_group_ctx *state =
struct tevent_req *subreq;
int hret;
const char *orig_dn;
const char *tmp_name;
/* Add to appropriate hash table */
SYSDB_ORIG_DN, &orig_dn);
return ret;
}
/* check if the user is in search base */
NULL)) {
dctx->result_index++;
continue;
}
dctx->result_index++;
&tmp_name);
} else if (ret) {
return EIO;
}
SYSDB_ORIG_DN, &orig_dn);
return ret;
}
/* check if the group is in search base */
NULL)) {
dctx->result_index++;
continue;
}
req);
return EAGAIN;
} else {
/* This should never happen, but if it does,
* do not loop forever */
dctx->result_index++;
continue;
}
}
/* All deref results processed */
return EOK;
}
static void
{
struct tevent_req *req =
struct sdap_nested_group_ctx *state =
return;
}
}
/* EAGAIN means a recursive search is in progress */
}
{
return EOK;
}