/*
SSSD
Authors:
Stephen Gallagher <sgallagh@redhat.com>
Copyright (C) 2012 Red Hat
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.h"
#include "providers/ldap/sdap_async_ad.h"
#include "providers/ldap/ldap_common.h"
#include "providers/ldap/sdap_async_private.h"
#include "providers/ldap/sdap_idmap.h"
#include "providers/ad/ad_common.h"
#include "lib/idmap/sss_idmap.h"
struct sdap_ad_match_rule_initgr_state {
const char *name;
const char *orig_dn;
const char **attrs;
int timeout;
const char *base_filter;
char *filter;
};
static errno_t
static void
struct tevent_req *
struct tevent_context *ev,
struct sdap_options *opts,
struct sss_domain_info *domain,
struct sdap_handle *sh,
const char *name,
const char *orig_dn,
int timeout)
{
const char **filter_members;
char *sanitized_user_dn;
char *oc_list;
struct sdap_ad_match_rule_initgr_state);
/* Request all of the group attributes that we know
* about, except for 'member' because that wastes a
* lot of bandwidth here and we only really
* care about a single member (the one we already
* have).
*/
if (!filter_members) {
goto immediate;
}
"Could not build attribute map: [%s]\n",
goto immediate;
}
/* Sanitize the user DN in case we have special characters in DN */
"Could not sanitize user DN: %s\n",
goto immediate;
}
/* Craft a special filter according to
*/
goto immediate;
}
state->base_filter =
"(&(%s:%s:=%s)(%s))",
if (!state->base_filter) {
goto immediate;
}
/* Start the loop through the search bases to get all of the
* groups to which this user belongs.
*/
"sdap_get_ad_match_rule_members_next_base failed: [%s]\n",
goto immediate;
}
return req;
return req;
}
static errno_t
{
return ENOMEM;
}
"Searching for groups with base [%s]\n",
if (!subreq) {
return ENOMEM;
}
req);
return EOK;
}
static void
{
char **sysdb_grouplist;
goto error;
}
"Search for users returned %zu results\n", count);
/* 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++) {
}
}
/* Continue checking other search bases */
/* There are more search bases to try */
goto error;
}
return;
}
/* No more search bases. Save the groups. */
"User is not a member of any group in the search bases\n");
}
/* Get the current sysdb group list for this user
* so we can update it.
*/
"Could not get the list of groups for [%s] in the sysdb: "
"[%s]\n",
goto error;
}
/* The extensibleMatch search rule eliminates the need for
* nested group searches, so we can just update the
* memberships now.
*/
"Could not store groups for user [%s]: [%s]\n",
goto error;
}
return;
}
{
return EOK;
}
struct sdap_get_ad_tokengroups_state {
const char *username;
char **sids;
};
static struct tevent_req *
struct tevent_context *ev,
struct sdap_options *opts,
struct sdap_handle *sh,
const char *name,
const char *orig_dn,
int timeout)
{
struct sdap_get_ad_tokengroups_state);
return NULL;
}
goto immediately;
}
goto immediately;
}
return req;
} else {
}
return req;
}
{
size_t i;
goto done;
}
if (num_users != 1) {
"More than one result on a base search!\n");
goto done;
}
/* get the list of sids from tokengroups */
goto done;
goto done;
}
goto done;
}
/* convert binary sid to string */
for (i = 0; i < el->num_values; i++) {
if (err != IDMAP_SUCCESS) {
"Could not convert binary SID to string: [%s]. Skipping\n",
continue;
}
}
/* shrink array to final number of elements */
goto done;
}
done:
return;
}
}
struct tevent_req *req,
char ***_sids)
{
}
}
return EOK;
}
struct sss_domain_info *domain,
char **ldap_groups)
{
return ENOMEM;
}
/* Get the current sysdb group list for this user so we can update it. */
username, &sysdb_groups);
goto done;
}
/* Find the differences between the sysdb and LDAP lists.
* Groups in the sysdb only must be removed. */
goto done;
}
(const char *const *) add_groups,
(const char *const *) del_groups);
goto done;
}
done:
return ret;
}
struct sdap_ad_resolve_sids_state {
char **sids;
const char *current_sid;
int index;
};
struct tevent_req *
struct tevent_context *ev,
struct sdap_id_ctx *id_ctx,
struct sdap_id_conn_ctx *conn,
struct sdap_options *opts,
struct sss_domain_info *domain,
char **sids)
{
struct sdap_ad_resolve_sids_state);
return NULL;
}
goto immediately;
}
goto immediately;
}
return req;
} else {
}
return req;
}
{
do {
return EOK;
}
state->current_sid);
}
if (sdap_domain == NULL) {
return ERR_INTERNAL;
}
BE_FILTER_SECID, false, true);
return ENOMEM;
}
return EAGAIN;
}
{
int dp_error;
int sdap_error;
/* Group was not found, we will ignore the error and continue with
* next group. This may happen for example if the group is built-in,
* but a custom search base is provided. */
"Unable to resolve SID %s - will try next sid.\n",
state->current_sid);
goto done;
}
/* continue with next SID */
return;
}
done:
return;
}
}
{
return EOK;
}
const char *orig_dn;
int timeout;
const char *username;
};
static void
struct tevent_context *ev,
struct sdap_options *opts,
const char *orig_dn,
int timeout,
const char *username,
struct sdap_handle *sh,
struct tevent_req *req,
static struct tevent_req *
struct tevent_context *ev,
struct sdap_options *opts,
struct sss_domain_info *domain,
struct sdap_handle *sh,
const char *name,
const char *orig_dn,
int timeout)
{
return NULL;
}
goto immediately;
}
return req;
} else {
goto immediately;
}
}
goto immediately;
}
goto immediately;
}
req);
return req;
} else {
}
return req;
}
static void
{
int ret;
return;
}
return;
}
req);
return;
}
struct sdap_options *opts,
struct sss_domain_info *user_dom,
struct sdap_idmap_ctx *idmap_ctx,
char **sids)
{
size_t i;
bool in_transaction = false;
return ENOMEM;
}
num_groups = 0;
goto done;
}
goto done;
}
in_transaction = true;
for (i = 0; i < num_sids; i++) {
continue;
continue;
}
continue;
}
/* Check whether this GID already exists in the sysdb */
"Could not retrieve group name from sysdb\n");
goto done;
}
/* This is a new group. For now, we will store it under the name
* of its SID. When a direct lookup of the group or its GID occurs,
* it will replace this temporary entry. */
goto done;
}
if (ret == ERR_GID_DUPLICATED) {
/* In case o group id-collision, do:
* - Delete the group from sysdb
* - Add the new incomplete group
* - Notify the NSS responder that the entry has also to be
* removed from the memory cache
*/
false, now);
}
goto done;
}
} else {
/* Unexpected error */
goto done;
}
goto done;
}
num_groups++;
}
groups);
goto done;
}
goto done;
}
in_transaction = false;
done:
if (in_transaction) {
}
return ret;
}
{
goto done;
}
sids);
"sdap_ad_save_group_membership_with_idmapping failed.\n");
goto done;
}
done:
return;
}
}
{
return EOK;
}
const char *orig_dn;
int timeout;
const char *username;
char **missing_sids;
char **cached_groups;
};
static void
static void
static void
static struct tevent_req *
struct tevent_context *ev,
struct sdap_id_ctx *id_ctx,
struct sdap_id_conn_ctx *conn,
struct sdap_options *opts,
struct sss_domain_info *domain,
struct sdap_handle *sh,
const char *name,
const char *orig_dn,
int timeout)
{
return NULL;
}
goto immediately;
}
return req;
} else {
goto immediately;
}
}
goto immediately;
}
goto immediately;
}
req);
return req;
} else {
}
return req;
}
static void
{
int ret;
return;
}
return;
}
req);
return;
}
struct sss_domain_info *user_domain,
char **sids,
char ***_missing,
char ***_valid_groups)
{
size_t i;
goto done;
}
num_valid_groups = 0;
if (valid_groups == NULL) {
goto done;
}
num_missing_sids = 0;
if (missing_sids == NULL) {
goto done;
}
/* For each SID check if it is already present in the cache. If yes, we
* will get name of the group and update the membership. Otherwise we need
* to remember the SID and download missing groups one by one. */
for (i = 0; i < num_sids; i++) {
continue;
}
/* we will update membership of this group */
"Could not retrieve group name from sysdb\n");
goto done;
}
name);
goto done;
}
/* we need to download this group */
sid);
sid);
}
/* else: We have downloaded missing groups but some of them may
* remained missing because they are outside of search base. We
* will just ignore them and continue with the next group. */
} else {
goto done;
}
}
/* return list of missing groups */
}
/* return list of missing groups */
if (_valid_groups != NULL) {
}
done:
return ret;
}
static void
{
goto done;
}
&state->cached_groups);
goto done;
}
/* download missing SIDs */
goto done;
}
req);
return;
done:
return;
}
}
static void
{
char **cached_groups;
goto done;
}
"sdap_ad_tokengroups_get_posix_members failed [%d]: %s\n",
goto done;
}
goto done;
}
/* update membership of existing groups */
goto done;
}
done:
return;
}
}
{
return EOK;
}
int dp_error;
};
static void
struct tevent_req *
struct tevent_context *ev,
struct sdap_domain *local_sdom,
struct sdap_options *opts,
struct sss_domain_info *dom,
struct sysdb_attrs **groups,
{
return NULL;
}
goto fail;
}
goto fail;
}
goto fail;
}
return req;
fail:
return req;
}
static void
{
struct tevent_req);
int ret;
return;
}
state->group_hash, 0);
return;
}
return;
}
struct sdap_nested_group {
};
static errno_t
struct sdap_nested_group *gr,
struct sss_domain_info *dom,
struct sdap_options *opts,
const char **_sysdb_name,
enum sysdb_member_type *_type,
char ***_add_list,
char ***_del_list)
{
int ret;
size_t c;
const char *sysdb_name;
const char *group_name;
const char *class;
char *local_groups_base_dn;
return ENOMEM;
}
if (local_groups_base_dn == NULL) {
goto done;
}
if (gr->parents_count != 0) {
/* Store the parents if needed */
goto done;
}
goto done;
}
}
"sysdb_attrs_get_string failed to get SYSDB_NAME, "
"skipping.\n");
goto done;
}
/* If objectcategory is missing, gr->group is a nested parent found during
* the nested group lookup. It might not already be stored in the cache.
*/
"sysdb_attrs_get_string failed to get %s for [%s], assuming "
/* make sure group exists in cache */
goto done;
}
/* Since the object is coming from LDAP it cannot have the internal
* fully-qualified name, so we can expand it unconditionally. */
group_name = NULL;
&group_name);
}
if (group_name != NULL) {
}
} else {
} else {
}
}
/* We need to get the cached list of groups form the local domain the
* object is a member of to compare them with the current list just
* retrieved (groupnamelist). Even if this list is empty we have to
* proceed because the membership might have been removed recently on the
* server. */
"trying with local domain [%s].\n",
}
goto done;
}
}
if (DEBUG_IS_SET(SSSDBG_TRACE_ALL)) {
if (cached_local_parents != NULL) {
for (c = 0; cached_local_parents[c] != NULL; c++) {
}
}
if (groupnamelist != NULL) {
for (c = 0; groupnamelist[c] != NULL; c++) {
sysdb_name, groupnamelist[c]);
}
}
}
goto done;
}
if (DEBUG_IS_SET(SSSDBG_TRACE_ALL)) {
sysdb_name, add_list[c]);
}
}
sysdb_name, del_list[c]);
}
}
}
done:
return ret;
}
{
struct tevent_req);
int ret;
int hret;
unsigned long count;
size_t c;
/* In case of ENOENT we can just proceed without making
* sdap_get_initgr_user() fail because there's no nested
goto done;
return;
}
if (hret != HASH_SUCCESS) {
goto done;
}
for (c = 0; c < count; c++) {
struct sdap_nested_group);
/* The values from the hash are either user or group objects returned
* by sysdb_initgroups() which where used to start the request or
* nested parents found during the request. The nested parents contain
* the processed LDAP data and can be identified by a missing
* objectclass attribute. */
&type,
&add_list,
&del_list);
"sdap_ad_get_domain_local_groups_parse_parents failed.\n");
continue;
}
continue;
}
(const char *const *) add_list,
(const char *const *) del_list);
goto done;
}
}
done:
} else {
}
return;
}
{
return EOK;
}
struct sdap_ad_tokengroups_initgroups_state {
bool use_id_mapping;
};
struct tevent_req *
struct tevent_context *ev,
struct sdap_id_ctx *id_ctx,
struct sdap_id_conn_ctx *conn,
struct sdap_options *opts,
struct sss_domain_info *domain,
struct sdap_handle *sh,
const char *name,
const char *orig_dn,
int timeout,
bool use_id_mapping)
{
struct sdap_ad_tokengroups_initgroups_state);
return NULL;
}
/* We can compute the gidNumber attribute from SIDs obtained from
* the tokenGroups lookup in case ID mapping is used for a user from the
* parent domain. For trusted domains, we need to know the group type
* to be able to filter out domain-local groups. Additionally, as a
* temporary workaround until https://fedorahosted.org/sssd/ticket/2656
* is fixed, we also fetch the group object if group members are ignored
* to avoid having to transfer and retain members when the fake
* tokengroups object without name is replaced by the full group object
*/
if (state->use_id_mapping
timeout);
} else {
timeout);
}
goto immediately;
}
return req;
} else {
}
return req;
}
{
if (state->use_id_mapping
} else {
}
goto done;
}
done:
return;
}
}
{
return EOK;
}
struct tevent_context *ev,
struct sdap_options *opts,
const char *orig_dn,
int timeout,
const char *username,
struct sdap_handle *sh,
struct tevent_req *req,
{
/* plain LDAP provider already has a sdap_handle */
goto done;
}
goto done;
} else {
goto done;
}
done:
return ret;
}