From 3063486d01c0be2ef64b884a20bfbc7f8cfd7105 Mon Sep 17 00:00:00 2001 From: Pavel Březina Date: Jan 19 2016 16:30:02 +0000 Subject: SDAP: Add request that iterates over all search bases We often need to iterate over many search bases but we always use mostly copy&paste iterator. This will reduce code duplication and simplify code flow. Reviewed-by: Sumit Bose (cherry picked from commit d0599eaa9369fd867953e3c58b8d7bb445525ff5) --- diff --git a/Makefile.am b/Makefile.am index 1937dcb..095b1cf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -628,6 +628,7 @@ dist_noinst_HEADERS = \ src/providers/ldap/sdap_users.h \ src/providers/ldap/sdap_dyndns.h \ src/providers/ldap/sdap_async_enum.h \ + src/providers/ldap/sdap_ops.h \ src/providers/ipa/ipa_common.h \ src/providers/ipa/ipa_config.h \ src/providers/ipa/ipa_access.h \ @@ -2836,6 +2837,7 @@ libsss_ldap_common_la_SOURCES = \ src/providers/ldap/sdap_refresh.c \ src/providers/ldap/sdap_utils.c \ src/providers/ldap/sdap_domain.c \ + src/providers/ldap/sdap_ops.c \ src/providers/ldap/sdap.c \ src/util/user_info_msg.c \ src/util/sss_ldap.c \ diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h index ae45fb7..66434dd 100644 --- a/src/providers/ldap/ldap_common.h +++ b/src/providers/ldap/ldap_common.h @@ -264,9 +264,12 @@ errno_t list_missing_attrs(TALLOC_CTX *mem_ctx, bool sdap_is_secure_uri(const char *uri); -char *sdap_get_id_specific_filter(TALLOC_CTX *mem_ctx, - const char *base_filter, - const char *extra_filter); +char *sdap_combine_filters(TALLOC_CTX *mem_ctx, + const char *base_filter, + const char *extra_filter); + +#define sdap_get_id_specific_filter(mem_ctx, base_filter, extra_filter) \ + sdap_combine_filters((mem_ctx), (base_filter), (extra_filter)) char *sdap_get_access_filter(TALLOC_CTX *mem_ctx, const char *base_filter); diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c index fcdc402..f9b9ff7 100644 --- a/src/providers/ldap/sdap.c +++ b/src/providers/ldap/sdap.c @@ -312,7 +312,7 @@ int sdap_get_map(TALLOC_CTX *memctx, char *name; int i, ret; - map = talloc_array(memctx, struct sdap_attr_map, num_entries); + map = talloc_zero_array(memctx, struct sdap_attr_map, num_entries + 1); if (!map) { return ENOMEM; } diff --git a/src/providers/ldap/sdap_ops.c b/src/providers/ldap/sdap_ops.c new file mode 100644 index 0000000..b2f2c35 --- /dev/null +++ b/src/providers/ldap/sdap_ops.c @@ -0,0 +1,232 @@ +/* + Authors: + Pavel Březina + + Copyright (C) 2015 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 . +*/ + +#include +#include + +#include "util/util.h" +#include "providers/ldap/sdap.h" +#include "providers/ldap/sdap_async.h" +#include "providers/ldap/ldap_common.h" + +struct sdap_search_bases_state { + struct tevent_context *ev; + struct sdap_options *opts; + struct sdap_handle *sh; + const char *filter; + const char **attrs; + struct sdap_attr_map *map; + int map_num_attrs; + int timeout; + bool allow_paging; + + size_t base_iter; + struct sdap_search_base *cur_base; + struct sdap_search_base **bases; + + size_t reply_count; + struct sysdb_attrs **reply; +}; + +static errno_t sdap_search_bases_next_base(struct tevent_req *req); +static void sdap_search_bases_done(struct tevent_req *subreq); + +struct tevent_req *sdap_search_bases_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sdap_options *opts, + struct sdap_handle *sh, + struct sdap_search_base **bases, + struct sdap_attr_map *map, + bool allow_paging, + int timeout, + const char *filter, + const char **attrs) +{ + struct tevent_req *req; + struct sdap_search_bases_state *state; + errno_t ret; + + req = tevent_req_create(mem_ctx, &state, struct sdap_search_bases_state); + if (req == NULL) { + return NULL; + } + + if (bases == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "No search base specified!\n"); + ret = ERR_INTERNAL; + goto immediately; + } + + if (map == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "No attribute map specified!\n"); + ret = ERR_INTERNAL; + goto immediately; + } + + state->ev = ev; + state->opts = opts; + state->sh = sh; + state->bases = bases; + state->map = map; + state->filter = filter; + state->attrs = attrs; + state->allow_paging = allow_paging; + + state->timeout = timeout == 0 + ? dp_opt_get_int(opts->basic, SDAP_SEARCH_TIMEOUT) + : timeout; + + for (state->map_num_attrs = 0; + state->map[state->map_num_attrs].opt_name != NULL; + state->map_num_attrs++) { + /* no op */; + } + + if (state->attrs == NULL) { + ret = build_attrs_from_map(state, state->map, state->map_num_attrs, + NULL, &state->attrs, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Unable to build attrs from map " + "[%d]: %s\n", ret, sss_strerror(ret)); + goto immediately; + } + } + + state->base_iter = 0; + ret = sdap_search_bases_next_base(req); + if (ret == EAGAIN) { + /* asynchronous processing */ + 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_search_bases_next_base(struct tevent_req *req) +{ + struct sdap_search_bases_state *state; + struct tevent_req *subreq; + char *filter; + + state = tevent_req_data(req, struct sdap_search_bases_state); + state->cur_base = state->bases[state->base_iter]; + if (state->cur_base == NULL) { + return EOK; + } + + /* Combine lookup and search base filters. */ + filter = sdap_combine_filters(state, state->filter, + state->cur_base->filter); + if (filter == NULL) { + return ENOMEM; + } + + DEBUG(SSSDBG_TRACE_FUNC, "Issuing LDAP lookup with base [%s]\n", + state->cur_base->basedn); + + subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh, + state->cur_base->basedn, + state->cur_base->scope, filter, + state->attrs, state->map, + state->map_num_attrs, state->timeout, + state->allow_paging); + if (subreq == NULL) { + return ENOMEM; + } + + tevent_req_set_callback(subreq, sdap_search_bases_done, req); + + state->base_iter++; + return EAGAIN; +} + +static void sdap_search_bases_done(struct tevent_req *subreq) +{ + struct tevent_req *req; + struct sdap_search_bases_state *state; + struct sysdb_attrs **attrs; + size_t count; + size_t i; + int ret; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_search_bases_state); + + DEBUG(SSSDBG_TRACE_FUNC, "Receiving data from base [%s]\n", + state->cur_base->basedn); + + ret = sdap_get_generic_recv(subreq, state, &count, &attrs); + talloc_zfree(subreq); + if (ret != EOK) { + tevent_req_error(req, ret); + return; + } + + /* Add rules to result. */ + if (count > 0) { + state->reply = talloc_realloc(state, state->reply, struct sysdb_attrs *, + state->reply_count + count); + if (state->reply == NULL) { + tevent_req_error(req, ENOMEM); + return; + } + + for (i = 0; i < count; i++) { + state->reply[state->reply_count + i] = talloc_steal(state->reply, + attrs[i]); + } + + state->reply_count += count; + } + + /* Try next search base. */ + ret = sdap_search_bases_next_base(req); + if (ret == EOK) { + tevent_req_done(req); + } else if (ret != EAGAIN) { + tevent_req_error(req, ret); + } + + return; +} + +int sdap_search_bases_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + size_t *reply_count, + struct sysdb_attrs ***reply) +{ + struct sdap_search_bases_state *state = + tevent_req_data(req, struct sdap_search_bases_state); + + TEVENT_REQ_RETURN_ON_ERROR(req); + + *reply_count = state->reply_count; + *reply = talloc_steal(mem_ctx, state->reply); + + return EOK; +} diff --git a/src/providers/ldap/sdap_ops.h b/src/providers/ldap/sdap_ops.h new file mode 100644 index 0000000..bc53ff8 --- /dev/null +++ b/src/providers/ldap/sdap_ops.h @@ -0,0 +1,44 @@ +/* + Authors: + Pavel Březina + + Copyright (C) 2015 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 . +*/ + +#ifndef _SDAP_OPS_H_ +#define _SDAP_OPS_H_ + +#include +#include +#include "providers/ldap/ldap_common.h" + +struct tevent_req *sdap_search_bases_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sdap_options *opts, + struct sdap_handle *sh, + struct sdap_search_base **bases, + struct sdap_attr_map *map, + bool allow_paging, + int timeout, + const char *filter, + const char **attrs); + +int sdap_search_bases_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + size_t *reply_count, + struct sysdb_attrs ***reply); + +#endif /* _SDAP_OPS_H_ */ diff --git a/src/providers/ldap/sdap_utils.c b/src/providers/ldap/sdap_utils.c index 9da46ea..7a96f81 100644 --- a/src/providers/ldap/sdap_utils.c +++ b/src/providers/ldap/sdap_utils.c @@ -149,9 +149,9 @@ errno_t deref_string_to_val(const char *str, int *val) return EOK; } -char *sdap_get_id_specific_filter(TALLOC_CTX *mem_ctx, - const char *base_filter, - const char *extra_filter) +char *sdap_combine_filters(TALLOC_CTX *mem_ctx, + const char *base_filter, + const char *extra_filter) { char *filter = NULL;