From 6385798f807d370fe6685653e337f65bf59f21bc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Tue, 12 Nov 2013 13:51:34 +0100
Subject: [PATCH 25/31] ad: use tokengroups even when id mapping is disabled
https://fedorahosted.org/sssd/ticket/1568
---
src/providers/ldap/sdap_async.h | 4 +-
src/providers/ldap/sdap_async_initgroups.c | 10 +-
src/providers/ldap/sdap_async_initgroups_ad.c | 537 +++++++++++++++++++++++++-
3 files changed, 525 insertions(+), 26 deletions(-)
diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
index 67623454e675f648259c089acca59258f386ecdb..f47437553a2d35dac90d86209848e840a237c3fb 100644
--- a/src/providers/ldap/sdap_async.h
+++ b/src/providers/ldap/sdap_async.h
@@ -296,13 +296,15 @@ sdap_get_ad_match_rule_initgroups_recv(struct tevent_req *req);
struct tevent_req *
sdap_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
+ struct sdap_id_ctx *id_ctx,
struct sdap_options *opts,
struct sysdb_ctx *sysdb,
struct sss_domain_info *domain,
struct sdap_handle *sh,
const char *name,
const char *orig_dn,
- int timeout);
+ int timeout,
+ bool use_id_mapping);
errno_t
sdap_ad_tokengroups_initgroups_recv(struct tevent_req *req);
diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c
index 7d5cd2e7cbd86e2eb9774dfee1b8e31edec57b88..1b865af0a113222b3c9c11e9401718abad577fd7 100644
--- a/src/providers/ldap/sdap_async_initgroups.c
+++ b/src/providers/ldap/sdap_async_initgroups.c
@@ -2852,18 +2852,19 @@ static void sdap_get_initgr_user(struct tevent_req *subreq)
return;
}
- if (state->use_id_mapping
- && state->opts->dc_functional_level >= DS_BEHAVIOR_WIN2008) {
+ if (state->opts->dc_functional_level >= DS_BEHAVIOR_WIN2008) {
/* Take advantage of AD's tokenGroups mechanism to look up all
* parent groups in a single request.
*/
subreq = sdap_ad_tokengroups_initgroups_send(state, state->ev,
+ state->id_ctx,
state->opts,
state->sysdb,
state->dom,
state->sh,
cname, orig_dn,
- state->timeout);
+ state->timeout,
+ state->use_id_mapping);
} else if (state->opts->support_matching_rule
&& dp_opt_get_bool(state->opts->basic,
SDAP_AD_MATCHING_RULE_INITGROUPS)) {
@@ -2950,8 +2951,7 @@ static void sdap_get_initgr_done(struct tevent_req *subreq)
case SDAP_SCHEMA_RFC2307BIS:
case SDAP_SCHEMA_AD:
- if (state->use_id_mapping
- && state->opts->dc_functional_level >= DS_BEHAVIOR_WIN2008) {
+ if (state->opts->dc_functional_level >= DS_BEHAVIOR_WIN2008) {
ret = sdap_ad_tokengroups_initgroups_recv(subreq);
}
else if (state->opts->support_matching_rule
diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c
index 7ba155338a358681c1bd201bee1c75f67afb4650..8e0506831cb189415b62efaa378d3dc7ec350cde 100644
--- a/src/providers/ldap/sdap_async_initgroups_ad.c
+++ b/src/providers/ldap/sdap_async_initgroups_ad.c
@@ -525,33 +525,180 @@ done:
return ret;
}
-struct sdap_ad_tokengroups_initgroups_state {
+struct sdap_ad_resolve_sids_state {
+ struct tevent_context *ev;
+ struct sdap_id_ctx *id_ctx;
+ struct sdap_options *opts;
+ struct sss_domain_info *domain;
+ char **sids;
+
+ const char *current_sid;
+ int index;
+};
+
+static errno_t sdap_ad_resolve_sids_step(struct tevent_req *req);
+static void sdap_ad_resolve_sids_done(struct tevent_req *subreq);
+
+static struct tevent_req *
+sdap_ad_resolve_sids_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct sdap_id_ctx *id_ctx,
+ struct sdap_options *opts,
+ struct sss_domain_info *domain,
+ char **sids)
+{
+ struct sdap_ad_resolve_sids_state *state = NULL;
+ struct tevent_req *req = NULL;
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct sdap_ad_resolve_sids_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("tevent_req_create() failed\n"));
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->id_ctx = id_ctx;
+ state->opts = opts;
+ state->domain = get_domains_head(domain);
+ state->sids = sids;
+ state->index = 0;
+
+ if (state->sids == NULL) {
+ ret = EOK;
+ goto immediately;
+ }
+
+ ret = sdap_ad_resolve_sids_step(req);
+ if (ret != EAGAIN) {
+ goto immediately;
+ }
+
+ return req;
+
+immediately:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+ tevent_req_post(req, ev);
+
+ return req;
+}
+
+static errno_t sdap_ad_resolve_sids_step(struct tevent_req *req)
+{
+ struct sdap_ad_resolve_sids_state *state = NULL;
+ struct tevent_req *subreq = NULL;
+ struct sdap_domain *sdap_domain = NULL;
+ struct sss_domain_info *domain = NULL;
+
+ state = tevent_req_data(req, struct sdap_ad_resolve_sids_state);
+
+ do {
+ state->current_sid = state->sids[state->index];
+ if (state->current_sid == NULL) {
+ return EOK;
+ }
+ state->index++;
+
+ domain = find_subdomain_by_sid(state->domain, state->current_sid);
+ if (domain == NULL) {
+ DEBUG(SSSDBG_MINOR_FAILURE, ("SID %s does not belong to any known "
+ "domain\n", state->current_sid));
+ }
+ } while (domain == NULL);
+
+ sdap_domain = sdap_domain_get(state->opts, domain);
+ if (sdap_domain == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("SDAP domain does not exist?\n"));
+ return ERR_INTERNAL;
+ }
+
+ subreq = groups_get_send(state, state->ev, state->id_ctx, sdap_domain,
+ state->id_ctx->conn, state->current_sid,
+ BE_FILTER_SECID, BE_ATTR_CORE, false);
+ if (subreq == NULL) {
+ return ENOMEM;
+ }
+
+ tevent_req_set_callback(subreq, sdap_ad_resolve_sids_done, req);
+
+ return EAGAIN;
+}
+
+static void sdap_ad_resolve_sids_done(struct tevent_req *subreq)
+{
+ struct sdap_ad_resolve_sids_state *state = NULL;
+ struct tevent_req *req = NULL;
+ int dp_error;
+ int sdap_error;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct sdap_ad_resolve_sids_state);
+
+ ret = groups_get_recv(subreq, &dp_error, &sdap_error);
+ talloc_zfree(subreq);
+ if (ret != EOK || sdap_error != EOK || dp_error != DP_ERR_OK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to resolve SID %s [dp_error: %d, "
+ "sdap_error: %d, ret: %d]: %s\n", state->current_sid, dp_error,
+ sdap_error, ret, strerror(ret)));
+ goto done;
+ }
+
+ ret = sdap_ad_resolve_sids_step(req);
+ if (ret == EAGAIN) {
+ /* continue with next SID */
+ return;
+ }
+
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static errno_t sdap_ad_resolve_sids_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ return EOK;
+}
+
+
+struct sdap_ad_tokengroups_initgr_mapping_state {
struct sdap_idmap_ctx *idmap_ctx;
struct sysdb_ctx *sysdb;
struct sss_domain_info *domain;
const char *username;
};
-static void sdap_ad_tokengroups_initgroups_done(struct tevent_req *subreq);
+static void sdap_ad_tokengroups_initgr_mapping_done(struct tevent_req *subreq);
-struct tevent_req *
-sdap_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct sdap_options *opts,
- struct sysdb_ctx *sysdb,
- struct sss_domain_info *domain,
- struct sdap_handle *sh,
- const char *name,
- const char *orig_dn,
- int timeout)
+static struct tevent_req *
+sdap_ad_tokengroups_initgr_mapping_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct sdap_options *opts,
+ struct sysdb_ctx *sysdb,
+ struct sss_domain_info *domain,
+ struct sdap_handle *sh,
+ const char *name,
+ const char *orig_dn,
+ int timeout)
{
- struct sdap_ad_tokengroups_initgroups_state *state = NULL;
+ struct sdap_ad_tokengroups_initgr_mapping_state *state = NULL;
struct tevent_req *req = NULL;
struct tevent_req *subreq = NULL;
errno_t ret;
req = tevent_req_create(mem_ctx, &state,
- struct sdap_ad_tokengroups_initgroups_state);
+ struct sdap_ad_tokengroups_initgr_mapping_state);
if (req == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, ("tevent_req_create() failed\n"));
return NULL;
@@ -573,7 +720,8 @@ sdap_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx,
goto immediately;
}
- tevent_req_set_callback(subreq, sdap_ad_tokengroups_initgroups_done, req);
+ tevent_req_set_callback(subreq, sdap_ad_tokengroups_initgr_mapping_done,
+ req);
return req;
@@ -588,10 +736,10 @@ immediately:
return req;
}
-static void sdap_ad_tokengroups_initgroups_done(struct tevent_req *subreq)
+static void sdap_ad_tokengroups_initgr_mapping_done(struct tevent_req *subreq)
{
TALLOC_CTX *tmp_ctx = NULL;
- struct sdap_ad_tokengroups_initgroups_state *state = NULL;
+ struct sdap_ad_tokengroups_initgr_mapping_state *state = NULL;
struct tevent_req *req = NULL;
struct sss_domain_info *domain = NULL;
struct ldb_message *msg = NULL;
@@ -599,14 +747,14 @@ static void sdap_ad_tokengroups_initgroups_done(struct tevent_req *subreq)
const char *name = NULL;
const char *sid = NULL;
char **sids = NULL;
- size_t num_sids;
+ size_t num_sids = 0;
size_t i;
time_t now;
gid_t gid;
char **groups = NULL;
size_t num_groups;
errno_t ret, sret;
- bool in_transaction;
+ bool in_transaction = false;
tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) {
@@ -616,7 +764,7 @@ static void sdap_ad_tokengroups_initgroups_done(struct tevent_req *subreq)
}
req = tevent_req_callback_data(subreq, struct tevent_req);
- state = tevent_req_data(req, struct sdap_ad_tokengroups_initgroups_state);
+ state = tevent_req_data(req, struct sdap_ad_tokengroups_initgr_mapping_state);
ret = sdap_get_ad_tokengroups_recv(state, subreq, &num_sids, &sids);
talloc_zfree(subreq);
@@ -738,6 +886,355 @@ done:
tevent_req_done(req);
}
+static int sdap_ad_tokengroups_initgr_mapping_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ return EOK;
+}
+
+struct sdap_ad_tokengroups_initgr_posix_state {
+ struct tevent_context *ev;
+ struct sdap_id_ctx *id_ctx;
+ struct sdap_options *opts;
+ struct sysdb_ctx *sysdb;
+ struct sss_domain_info *domain;
+ const char *username;
+};
+
+static void
+sdap_ad_tokengroups_initgr_posix_tg_done(struct tevent_req *subreq);
+
+static void
+sdap_ad_tokengroups_initgr_posix_sids_done(struct tevent_req *subreq);
+
+static struct tevent_req *
+sdap_ad_tokengroups_initgr_posix_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct sdap_id_ctx *id_ctx,
+ struct sdap_options *opts,
+ struct sysdb_ctx *sysdb,
+ struct sss_domain_info *domain,
+ struct sdap_handle *sh,
+ const char *name,
+ const char *orig_dn,
+ int timeout)
+{
+ struct sdap_ad_tokengroups_initgr_posix_state *state = NULL;
+ struct tevent_req *req = NULL;
+ struct tevent_req *subreq = NULL;
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct sdap_ad_tokengroups_initgr_posix_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("tevent_req_create() failed\n"));
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->id_ctx = id_ctx;
+ state->opts = opts;
+ state->sysdb = sysdb;
+ state->domain = domain;
+ state->username = talloc_strdup(state, name);
+ if (state->username == NULL) {
+ ret = ENOMEM;
+ goto immediately;
+ }
+
+ subreq = sdap_get_ad_tokengroups_send(state, ev, opts, sh, name, orig_dn,
+ timeout);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto immediately;
+ }
+
+ tevent_req_set_callback(subreq, sdap_ad_tokengroups_initgr_posix_tg_done,
+ req);
+
+ return req;
+
+immediately:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+ tevent_req_post(req, ev);
+
+ return req;
+}
+
+static void
+sdap_ad_tokengroups_initgr_posix_tg_done(struct tevent_req *subreq)
+{
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct sdap_ad_tokengroups_initgr_posix_state *state = NULL;
+ struct tevent_req *req = NULL;
+ struct sss_domain_info *domain = NULL;
+ struct ldb_message *msg = NULL;
+ const char *attrs[] = {SYSDB_NAME, SYSDB_POSIX, NULL};
+ const char *is_posix = NULL;
+ const char *name = NULL;
+ char *sid = NULL;
+ char **sids = NULL;
+ size_t num_sids = 0;
+ char **valid_groups = NULL;
+ size_t num_valid_groups;
+ char **missing_sids = NULL;
+ size_t num_missing_sids;
+ size_t i;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n"));
+ ret = ENOMEM;
+ goto done;
+ }
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req,
+ struct sdap_ad_tokengroups_initgr_posix_state);
+
+ ret = sdap_get_ad_tokengroups_recv(state, subreq, &num_sids, &sids);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to acquire tokengroups [%d]: %s\n",
+ ret, strerror(ret)));
+ goto done;
+ }
+
+ num_valid_groups = 0;
+ valid_groups = talloc_zero_array(tmp_ctx, char*, num_sids + 1);
+ if (valid_groups == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ num_missing_sids = 0;
+ missing_sids = talloc_zero_array(tmp_ctx, char*, num_sids + 1);
+ if (missing_sids == NULL) {
+ ret = ENOMEM;
+ 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++) {
+ sid = sids[i];
+ DEBUG(SSSDBG_TRACE_LIBS, ("Processing membership SID [%s]\n", sid));
+
+ domain = find_subdomain_by_sid(get_domains_head(state->domain), sid);
+ if (domain == NULL) {
+ DEBUG(SSSDBG_MINOR_FAILURE, ("Domain not found for SID %s\n", sid));
+ continue;
+ }
+
+ ret = sysdb_search_group_by_sid_str(tmp_ctx, domain->sysdb, domain,
+ sid, attrs, &msg);
+ if (ret == EOK) {
+ is_posix = ldb_msg_find_attr_as_string(msg, SYSDB_POSIX, NULL);
+ if (is_posix != NULL && strcmp(is_posix, "FALSE") == 0) {
+ /* skip non-posix group */
+ continue;
+ }
+
+ /* we will update membership of this group */
+ name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
+ if (name == NULL) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ ("Could not retrieve group name from sysdb\n"));
+ ret = EINVAL;
+ goto done;
+ }
+
+ valid_groups[num_valid_groups] = sysdb_group_strdn(tmp_ctx,
+ domain->name,
+ name);
+ if (valid_groups[num_valid_groups] == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ num_valid_groups++;
+ } else if (ret == ENOENT) {
+ /* we need to download this group */
+ missing_sids[num_missing_sids] = talloc_steal(missing_sids, sid);
+ num_missing_sids++;
+
+ DEBUG(SSSDBG_TRACE_FUNC, ("Missing SID %s will be downloaded\n",
+ sid));
+ } else {
+ DEBUG(SSSDBG_MINOR_FAILURE, ("Could not look up group in sysdb: "
+ "[%s]\n", strerror(ret)));
+ goto done;
+ }
+ }
+
+ valid_groups[num_valid_groups] = NULL;
+ missing_sids[num_missing_sids] = NULL;
+
+ /* update membership of existing groups */
+ ret = sdap_ad_tokengroups_update_members(state, state->username,
+ state->sysdb, state->domain,
+ valid_groups);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE, ("Membership update failed [%d]: %s\n",
+ ret, strerror(ret)));
+ goto done;
+ }
+
+ /* download missing SIDs */
+ missing_sids = talloc_steal(state, missing_sids);
+ subreq = sdap_ad_resolve_sids_send(state, state->ev, state->id_ctx,
+ state->opts, state->domain,
+ missing_sids);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ tevent_req_set_callback(subreq, sdap_ad_tokengroups_initgr_posix_sids_done,
+ req);
+
+ return;
+
+done:
+ talloc_free(tmp_ctx);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static void
+sdap_ad_tokengroups_initgr_posix_sids_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = NULL;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+
+ ret = sdap_ad_resolve_sids_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to resolve missing SIDs "
+ "[%d]: %s\n", ret, strerror(ret)));
+ goto done;
+ }
+
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static errno_t sdap_ad_tokengroups_initgr_posix_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ return EOK;
+}
+
+struct sdap_ad_tokengroups_initgroups_state {
+ bool use_id_mapping;
+};
+
+static void sdap_ad_tokengroups_initgroups_done(struct tevent_req *subreq);
+
+struct tevent_req *
+sdap_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct sdap_id_ctx *id_ctx,
+ struct sdap_options *opts,
+ struct sysdb_ctx *sysdb,
+ 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 *state = NULL;
+ struct tevent_req *req = NULL;
+ struct tevent_req *subreq = NULL;
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct sdap_ad_tokengroups_initgroups_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("tevent_req_create() failed\n"));
+ return NULL;
+ }
+
+ state->use_id_mapping = use_id_mapping;
+
+ if (state->use_id_mapping) {
+ subreq = sdap_ad_tokengroups_initgr_mapping_send(state, ev, opts,
+ sysdb, domain, sh,
+ name, orig_dn,
+ timeout);
+ } else {
+ subreq = sdap_ad_tokengroups_initgr_posix_send(state, ev, id_ctx, opts,
+ sysdb, domain, sh,
+ name, orig_dn,
+ timeout);
+ }
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto immediately;
+ }
+
+ tevent_req_set_callback(subreq, sdap_ad_tokengroups_initgroups_done, req);
+
+ return req;
+
+immediately:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+ tevent_req_post(req, ev);
+
+ return req;
+}
+
+static void sdap_ad_tokengroups_initgroups_done(struct tevent_req *subreq)
+{
+ struct sdap_ad_tokengroups_initgroups_state *state = NULL;
+ struct tevent_req *req = NULL;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct sdap_ad_tokengroups_initgroups_state);
+
+ if (state->use_id_mapping) {
+ ret = sdap_ad_tokengroups_initgr_mapping_recv(subreq);
+ } else {
+ ret = sdap_ad_tokengroups_initgr_posix_recv(subreq);
+ }
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ goto done;
+ }
+
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
errno_t sdap_ad_tokengroups_initgroups_recv(struct tevent_req *req)
{
TEVENT_REQ_RETURN_ON_ERROR(req);
--
1.8.4.2