summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Gallagher <sgallagh@redhat.com>2012-06-10 14:50:43 -0400
committerStephen Gallagher <sgallagh@redhat.com>2012-06-13 10:01:12 -0400
commitd42d371c00c83ae44b9d1c3e88ecbe0e01b112e6 (patch)
tree6907c5ab6191128a1a8a1adf430425fb933b5dea
parent97ae45d61d921f07e812620e0156aee02b7b83a7 (diff)
downloadsssd-d42d371c00c83ae44b9d1c3e88ecbe0e01b112e6.tar.gz
sssd-d42d371c00c83ae44b9d1c3e88ecbe0e01b112e6.tar.xz
sssd-d42d371c00c83ae44b9d1c3e88ecbe0e01b112e6.zip
LDAP: Add support for AD chain matching extension in initgroups
-rw-r--r--Makefile.am1
-rw-r--r--src/providers/ldap/sdap_async.h13
-rw-r--r--src/providers/ldap/sdap_async_initgroups.c29
-rw-r--r--src/providers/ldap/sdap_async_initgroups_ad.c292
4 files changed, 326 insertions, 9 deletions
diff --git a/Makefile.am b/Makefile.am
index 0e84da00a..8af213e59 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1093,6 +1093,7 @@ libsss_ldap_common_la_SOURCES = \
src/providers/ldap/sdap_async_groups.c \
src/providers/ldap/sdap_async_groups_ad.c \
src/providers/ldap/sdap_async_initgroups.c \
+ src/providers/ldap/sdap_async_initgroups_ad.c \
src/providers/ldap/sdap_async_connection.c \
src/providers/ldap/sdap_async_netgroups.c \
src/providers/ldap/sdap_async_services.c \
diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
index 9a65b25e0..d024e30a9 100644
--- a/src/providers/ldap/sdap_async.h
+++ b/src/providers/ldap/sdap_async.h
@@ -262,4 +262,17 @@ sdap_get_ad_match_rule_members_recv(struct tevent_req *req,
size_t *num_users,
struct sysdb_attrs ***users);
+struct tevent_req *
+sdap_get_ad_match_rule_initgroups_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct sdap_options *opts,
+ struct sysdb_ctx *sysdb,
+ struct sdap_handle *sh,
+ const char *name,
+ const char *orig_dn,
+ int timeout);
+
+errno_t
+sdap_get_ad_match_rule_initgroups_recv(struct tevent_req *req);
+
#endif /* _SDAP_ASYNC_H_ */
diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c
index 8524b1374..2f146b016 100644
--- a/src/providers/ldap/sdap_async_initgroups.c
+++ b/src/providers/ldap/sdap_async_initgroups.c
@@ -2657,10 +2657,6 @@ static void sdap_get_initgr_user(struct tevent_req *subreq)
case SDAP_SCHEMA_RFC2307BIS:
case SDAP_SCHEMA_AD:
- /* TODO: AD uses a different member/memberof schema
- * We need an AD specific call that is able to unroll
- * nested groups by doing extensive recursive searches */
-
ret = sysdb_attrs_get_string(state->orig_user,
SYSDB_ORIG_DN,
&orig_dn);
@@ -2669,17 +2665,28 @@ static void sdap_get_initgr_user(struct tevent_req *subreq)
return;
}
- subreq = sdap_initgr_rfc2307bis_send(
- state, state->ev, state->opts, state->sysdb,
- state->dom, state->sh,
- cname, orig_dn);
+ if (dp_opt_get_bool(state->opts->basic, SDAP_AD_MATCHING_RULE_INITGROUPS)) {
+ /* Take advantage of AD's extensibleMatch filter to look up
+ * all parent groups in a single request.
+ */
+ subreq = sdap_get_ad_match_rule_initgroups_send(
+ state, state->ev, state->opts, state->sysdb,
+ state->sh, cname, orig_dn, state->timeout);
+ } else {
+ subreq = sdap_initgr_rfc2307bis_send(
+ state, state->ev, state->opts, state->sysdb,
+ state->dom, state->sh,
+ cname, orig_dn);
+ }
if (!subreq) {
tevent_req_error(req, ENOMEM);
return;
}
+
talloc_steal(subreq, orig_dn);
tevent_req_set_callback(subreq, sdap_get_initgr_done, req);
break;
+
case SDAP_SCHEMA_IPA_V1:
subreq = sdap_initgr_nested_send(state, state->ev, state->opts,
state->sysdb, state->dom, state->sh,
@@ -2730,7 +2737,11 @@ static void sdap_get_initgr_done(struct tevent_req *subreq)
case SDAP_SCHEMA_RFC2307BIS:
case SDAP_SCHEMA_AD:
- ret = sdap_initgr_rfc2307bis_recv(subreq);
+ if (dp_opt_get_bool(state->opts->basic, SDAP_AD_MATCHING_RULE_INITGROUPS)) {
+ ret = sdap_get_ad_match_rule_initgroups_recv(subreq);
+ } else {
+ ret = sdap_initgr_rfc2307bis_recv(subreq);
+ }
break;
case SDAP_SCHEMA_IPA_V1:
diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c
new file mode 100644
index 000000000..f74729f47
--- /dev/null
+++ b/src/providers/ldap/sdap_async_initgroups_ad.c
@@ -0,0 +1,292 @@
+/*
+ SSSD
+
+ Authors:
+ Stephen Gallagher <sgallagh@redhat.com>
+
+ Copyright (C) 2012 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ 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 "util/util.h"
+#include "providers/ldap/sdap_async.h"
+#include "providers/ldap/ldap_common.h"
+#include "providers/ldap/sdap_async_private.h"
+
+struct sdap_ad_match_rule_initgr_state {
+ struct tevent_context *ev;
+ struct sdap_options *opts;
+ struct sysdb_ctx *sysdb;
+ struct sdap_handle *sh;
+ const char *name;
+ const char *orig_dn;
+ const char **attrs;
+ int timeout;
+ const char *base_filter;
+ char *filter;
+
+ size_t count;
+ struct sysdb_attrs **groups;
+
+ size_t base_iter;
+ struct sdap_search_base **search_bases;
+};
+
+static errno_t
+sdap_get_ad_match_rule_initgroups_next_base(struct tevent_req *req);
+
+static void
+sdap_get_ad_match_rule_initgroups_step(struct tevent_req *subreq);
+
+struct tevent_req *
+sdap_get_ad_match_rule_initgroups_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct sdap_options *opts,
+ struct sysdb_ctx *sysdb,
+ struct sdap_handle *sh,
+ const char *name,
+ const char *orig_dn,
+ int timeout)
+{
+ errno_t ret;
+ struct tevent_req *req;
+ struct sdap_ad_match_rule_initgr_state *state;
+ const char **filter_members;
+ char *sanitized_user_dn;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct sdap_ad_match_rule_initgr_state);
+ if (!req) return NULL;
+
+ state->ev = ev;
+ state->opts = opts;
+ state->sysdb = sysdb;
+ state->sh = sh;
+ state->name = name;
+ state->orig_dn = orig_dn;
+ state->base_iter = 0;
+ state->search_bases = opts->group_search_bases;
+
+ /* 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).
+ */
+ filter_members = talloc_array(state, const char *, 2);
+ if (!filter_members) {
+ ret = ENOMEM;
+ goto immediate;
+ }
+ filter_members[0] = opts->group_map[SDAP_AT_GROUP_MEMBER].name;
+ filter_members[1] = NULL;
+
+ ret = build_attrs_from_map(state, opts->group_map,
+ SDAP_OPTS_GROUP,
+ filter_members,
+ &state->attrs, NULL);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ ("Could not build attribute map: [%s]\n",
+ strerror(ret)));
+ goto immediate;
+ }
+
+ /* Sanitize the user DN in case we have special characters in DN */
+ ret = sss_filter_sanitize(state, state->orig_dn, &sanitized_user_dn);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ ("Could not sanitize user DN: %s\n",
+ strerror(ret)));
+ goto immediate;
+ }
+
+ /* Craft a special filter according to
+ * http://msdn.microsoft.com/en-us/library/windows/desktop/aa746475%28v=vs.85%29.aspx
+ */
+ state->base_filter =
+ talloc_asprintf(state,
+ "(&(%s:%s:=%s)(objectClass=%s))",
+ state->opts->group_map[SDAP_AT_GROUP_MEMBER].name,
+ SDAP_MATCHING_RULE_IN_CHAIN,
+ sanitized_user_dn,
+ state->opts->group_map[SDAP_OC_GROUP].name);
+ talloc_zfree(sanitized_user_dn);
+ if (!state->base_filter) {
+ ret = ENOMEM;
+ goto immediate;
+ }
+
+ /* Start the loop through the search bases to get all of the
+ * groups to which this user belongs.
+ */
+ ret = sdap_get_ad_match_rule_initgroups_next_base(req);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ ("sdap_get_ad_match_rule_members_next_base failed: [%s]\n",
+ strerror(ret)));
+ goto immediate;
+ }
+
+ return req;
+
+immediate:
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static errno_t
+sdap_get_ad_match_rule_initgroups_next_base(struct tevent_req *req)
+{
+ struct tevent_req *subreq;
+ struct sdap_ad_match_rule_initgr_state *state;
+
+ state = tevent_req_data(req, struct sdap_ad_match_rule_initgr_state);
+
+ talloc_zfree(state->filter);
+ state->filter = sdap_get_id_specific_filter(state,
+ state->base_filter,
+ state->search_bases[state->base_iter]->filter);
+ if (!state->filter) {
+ return ENOMEM;
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC,
+ ("Searching for groups with base [%s]\n",
+ state->search_bases[state->base_iter]->basedn));
+
+ subreq = sdap_get_generic_send(
+ state, state->ev, state->opts, state->sh,
+ state->search_bases[state->base_iter]->basedn,
+ state->search_bases[state->base_iter]->scope,
+ state->filter, state->attrs,
+ state->opts->group_map, SDAP_OPTS_GROUP,
+ state->timeout, true);
+ if (!subreq) {
+ return ENOMEM;
+ }
+
+ tevent_req_set_callback(subreq,
+ sdap_get_ad_match_rule_initgroups_step,
+ req);
+
+ return EOK;
+}
+
+static void
+sdap_get_ad_match_rule_initgroups_step(struct tevent_req *subreq)
+{
+ errno_t ret;
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq, struct tevent_req);
+ struct sdap_ad_match_rule_initgr_state *state =
+ tevent_req_data(req, struct sdap_ad_match_rule_initgr_state);
+ size_t count, i;
+ struct sysdb_attrs **groups;
+ char **sysdb_grouplist;
+
+ ret = sdap_get_generic_recv(subreq, state, &count, &groups);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ ("LDAP search failed: [%s]\n", strerror(ret)));
+ goto error;
+ }
+
+ DEBUG(SSSDBG_TRACE_LIBS,
+ ("Search for users returned %d results\n", count));
+
+ /* Add this batch of groups to the list */
+ if (count > 0) {
+ state->groups = talloc_realloc(state, state->groups,
+ struct sysdb_attrs *,
+ state->count + count + 1);
+ if (!state->groups) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+
+ /* Copy the new groups into the list */
+ for (i = 0; i < count; i++) {
+ state->groups[state->count + i] =
+ talloc_steal(state->groups, groups[i]);
+ }
+
+ state->count += count;
+ state->groups[state->count] = NULL;
+ }
+
+ /* Continue checking other search bases */
+ state->base_iter++;
+ if (state->search_bases[state->base_iter]) {
+ /* There are more search bases to try */
+ ret = sdap_get_ad_match_rule_initgroups_next_base(req);
+ if (ret != EOK) {
+ goto error;
+ }
+ return;
+ }
+
+ /* No more search bases. Save the groups. */
+
+ if (state->count == 0) {
+ DEBUG(SSSDBG_TRACE_LIBS,
+ ("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.
+ */
+ ret = get_sysdb_grouplist(state, state->sysdb, state->name,
+ &sysdb_grouplist);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ ("Could not get the list of groups for [%s] in the sysdb: "
+ "[%s]\n",
+ state->name, strerror(ret)));
+ goto error;
+ }
+
+ /* The extensibleMatch search rule eliminates the need for
+ * nested group searches, so we can just update the
+ * memberships now.
+ */
+ ret = sdap_initgr_common_store(state->sysdb, state->opts,
+ state->name,
+ SYSDB_MEMBER_USER,
+ sysdb_grouplist,
+ state->groups,
+ state->count);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ ("Could not store groups for user [%s]: [%s]\n",
+ state->name, strerror(ret)));
+ goto error;
+ }
+
+ tevent_req_done(req);
+ return;
+
+error:
+ tevent_req_error(req, ret);
+}
+
+errno_t
+sdap_get_ad_match_rule_initgroups_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+ return EOK;
+}