diff options
author | Stephen Gallagher <sgallagh@redhat.com> | 2012-06-10 13:07:15 -0400 |
---|---|---|
committer | Stephen Gallagher <sgallagh@redhat.com> | 2012-06-13 10:01:12 -0400 |
commit | 97ae45d61d921f07e812620e0156aee02b7b83a7 (patch) | |
tree | 94d6b10313f7626f426388acc2dffacdae3fe01a /src/providers/ldap/sdap_async_groups_ad.c | |
parent | 3963d3fa9e3099bc02d612b5051d8b769d6e3a75 (diff) | |
download | sssd-97ae45d61d921f07e812620e0156aee02b7b83a7.tar.gz sssd-97ae45d61d921f07e812620e0156aee02b7b83a7.tar.bz2 sssd-97ae45d61d921f07e812620e0156aee02b7b83a7.zip |
LDAP: Add support for AD chain matching extension in group lookups
Diffstat (limited to 'src/providers/ldap/sdap_async_groups_ad.c')
-rw-r--r-- | src/providers/ldap/sdap_async_groups_ad.c | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/src/providers/ldap/sdap_async_groups_ad.c b/src/providers/ldap/sdap_async_groups_ad.c new file mode 100644 index 00000000..1082957f --- /dev/null +++ b/src/providers/ldap/sdap_async_groups_ad.c @@ -0,0 +1,250 @@ +/* + 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" + +struct sdap_ad_match_rule_state { + struct tevent_context *ev; + struct sdap_handle *sh; + const char **attrs; + + struct sdap_options *opts; + const char *base_filter; + char *filter; + int timeout; + + size_t base_iter; + struct sdap_search_base **search_bases; + + size_t count; + struct sysdb_attrs **users; +}; + +static errno_t +sdap_get_ad_match_rule_members_next_base(struct tevent_req *req); +static void +sdap_get_ad_match_rule_members_step(struct tevent_req *subreq); + +struct tevent_req * +sdap_get_ad_match_rule_members_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sdap_options *opts, + struct sdap_handle *sh, + struct sysdb_attrs *group, + int timeout) +{ + errno_t ret; + struct tevent_req *req; + struct sdap_ad_match_rule_state *state; + const char *group_dn; + char *sanitized_group_dn; + + req = tevent_req_create(mem_ctx, &state, struct sdap_ad_match_rule_state); + if (!req) return NULL; + + state->ev = ev; + state->opts = opts; + state->sh = sh; + state->timeout = timeout; + state->count = 0; + state->base_iter = 0; + state->search_bases = opts->user_search_bases; + + /* Request all of the user attributes that we know about. */ + ret = build_attrs_from_map(state, opts->user_map, SDAP_OPTS_USER, + NULL, &state->attrs, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, + ("Could not build attribute map: [%s]\n", + strerror(ret))); + goto immediate; + } + + /* Get the DN of the group */ + ret = sysdb_attrs_get_string(group, SYSDB_ORIG_DN, &group_dn); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, + ("Could not retrieve originalDN for group: %s\n", + strerror(ret))); + goto immediate; + } + + /* Sanitize it in case we have special characters in DN */ + ret = sss_filter_sanitize(state, group_dn, &sanitized_group_dn); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, + ("Could not sanitize group 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->user_map[SDAP_AT_USER_MEMBEROF].name, + SDAP_MATCHING_RULE_IN_CHAIN, + sanitized_group_dn, + state->opts->user_map[SDAP_OC_USER].name); + talloc_zfree(sanitized_group_dn); + if (!state->base_filter) { + ret = ENOMEM; + goto immediate; + } + + /* Start the loop through the search bases to get all of the users */ + ret = sdap_get_ad_match_rule_members_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_members_next_base(struct tevent_req *req) +{ + struct tevent_req *subreq; + struct sdap_ad_match_rule_state *state; + + state = tevent_req_data(req, struct sdap_ad_match_rule_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 users 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->user_map, SDAP_OPTS_USER, + state->timeout, true); + if (!subreq) { + return ENOMEM; + } + + tevent_req_set_callback(subreq, sdap_get_ad_match_rule_members_step, req); + + return EOK; +} + +static void +sdap_get_ad_match_rule_members_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_state *state = + tevent_req_data(req, struct sdap_ad_match_rule_state); + size_t count, i; + struct sysdb_attrs **users; + + ret = sdap_get_generic_recv(subreq, state, &count, &users); + talloc_zfree(subreq); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, + ("LDAP search failed: [%s]\n", strerror(ret))); + tevent_req_error(req, ret); + return; + } + + DEBUG(SSSDBG_TRACE_LIBS, + ("Search for users returned %d results\n", count)); + + /* Add this batch of users to the list */ + if (count > 0) { + state->users = talloc_realloc(state, state->users, + struct sysdb_attrs *, + state->count + count + 1); + if (!state->users) { + tevent_req_error(req, ENOMEM); + return; + } + + /* Copy the new users into the list */ + for (i = 0; i < count; i++) { + state->users[state->count + i] = + talloc_steal(state->users, users[i]); + } + + state->count += count; + state->users[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_members_next_base(req); + if (ret != EOK) { + tevent_req_error(req, ret); + } + return; + } + + /* No more search bases. We're done here. */ + if (state->count == 0) { + DEBUG(SSSDBG_TRACE_LIBS, + ("No users matched in any search base\n")); + tevent_req_error(req, ENOENT); + return; + } + + tevent_req_done(req); +} + +errno_t +sdap_get_ad_match_rule_members_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + size_t *num_users, + struct sysdb_attrs ***users) +{ + struct sdap_ad_match_rule_state *state = + tevent_req_data(req, struct sdap_ad_match_rule_state); + + TEVENT_REQ_RETURN_ON_ERROR(req); + + *num_users = state->count; + *users = talloc_steal(mem_ctx, state->users); + return EOK; +} |