4 Copyright (C) Simo Sorce 2005-2008
6 ** NOTE! The following LGPL license applies to the ldb
7 ** library. This does NOT imply that all of Samba is released
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 3 of the License, or (at your option) any later version.
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, see <http://www.gnu.org/licenses/>.
27 * Component: ldb attribute scoped query control module
29 * Description: this module searches all the the objects pointed
30 * by the DNs contained in the references attribute
35 #include "ldb_includes.h"
39 enum {ASQ_SEARCH_BASE, ASQ_SEARCH_MULTI} step;
41 struct ldb_module *module;
42 struct ldb_request *req;
44 struct ldb_asq_control *asq_ctrl;
46 const char * const *req_attrs;
50 ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX = 21,
51 ASQ_CTRL_UNWILLING_TO_PERFORM = 53,
52 ASQ_CTRL_AFFECTS_MULTIPLE_DSA = 71
55 struct ldb_reply *base_res;
57 struct ldb_request **reqs;
61 struct ldb_control **controls;
64 static struct asq_context *asq_context_init(struct ldb_module *module, struct ldb_request *req)
66 struct asq_context *ac;
68 ac = talloc_zero(req, struct asq_context);
80 static int asq_search_continue(struct asq_context *ac);
82 static int asq_search_terminate(struct asq_context *ac)
84 struct ldb_asq_control *asq;
88 for (i = 0; ac->controls[i]; i++) /* count em */ ;
93 ac->controls = talloc_realloc(ac, ac->controls, struct ldb_control *, i + 2);
95 if (ac->controls == NULL) {
96 return LDB_ERR_OPERATIONS_ERROR;
99 ac->controls[i] = talloc(ac->controls, struct ldb_control);
100 if (ac->controls[i] == NULL) {
101 return LDB_ERR_OPERATIONS_ERROR;
104 ac->controls[i]->oid = LDB_CONTROL_ASQ_OID;
105 ac->controls[i]->critical = 0;
107 asq = talloc_zero(ac->controls[i], struct ldb_asq_control);
109 return LDB_ERR_OPERATIONS_ERROR;
111 asq->result = ac->asq_ret;
113 ac->controls[i]->data = asq;
115 ac->controls[i + 1] = NULL;
117 return ldb_module_done(ac->req, ac->controls, NULL, LDB_SUCCESS);
120 static int asq_base_callback(struct ldb_request *req, struct ldb_reply *ares)
122 struct asq_context *ac;
125 ac = talloc_get_type(req->context, struct asq_context);
128 return ldb_module_done(ac->req, NULL, NULL,
129 LDB_ERR_OPERATIONS_ERROR);
131 if (ares->error != LDB_SUCCESS) {
132 return ldb_module_done(ac->req, ares->controls,
133 ares->response, ares->error);
136 switch (ares->type) {
137 case LDB_REPLY_ENTRY:
138 ac->base_res = talloc_move(ac, &ares);
141 case LDB_REPLY_REFERRAL:
142 /* ignore referrals */
151 ret = asq_search_continue(ac);
152 if (ret != LDB_SUCCESS) {
153 return ldb_module_done(ac->req, NULL, NULL, ret);
161 static int asq_reqs_callback(struct ldb_request *req, struct ldb_reply *ares)
163 struct asq_context *ac;
166 ac = talloc_get_type(req->context, struct asq_context);
169 return ldb_module_done(ac->req, NULL, NULL,
170 LDB_ERR_OPERATIONS_ERROR);
172 if (ares->error != LDB_SUCCESS) {
173 return ldb_module_done(ac->req, ares->controls,
174 ares->response, ares->error);
177 switch (ares->type) {
178 case LDB_REPLY_ENTRY:
179 /* pass the message up to the original callback as we
180 * do not have to elaborate on it any further */
181 ret = ldb_module_send_entry(ac->req, ares->message, ares->controls);
182 if (ret != LDB_SUCCESS) {
183 return ldb_module_done(ac->req, NULL, NULL, ret);
188 case LDB_REPLY_REFERRAL:
189 /* ignore referrals */
197 ret = asq_search_continue(ac);
198 if (ret != LDB_SUCCESS) {
199 return ldb_module_done(ac->req, NULL, NULL, ret);
207 static int asq_build_first_request(struct asq_context *ac, struct ldb_request **base_req)
209 const char **base_attrs;
212 ac->req_attrs = ac->req->op.search.attrs;
213 ac->req_attribute = talloc_strdup(ac, ac->asq_ctrl->source_attribute);
214 if (ac->req_attribute == NULL)
215 return LDB_ERR_OPERATIONS_ERROR;
217 base_attrs = talloc_array(ac, const char *, 2);
218 if (base_attrs == NULL) return LDB_ERR_OPERATIONS_ERROR;
220 base_attrs[0] = talloc_strdup(base_attrs, ac->asq_ctrl->source_attribute);
221 if (base_attrs[0] == NULL) return LDB_ERR_OPERATIONS_ERROR;
223 base_attrs[1] = NULL;
225 ret = ldb_build_search_req(base_req, ac->module->ldb, ac,
226 ac->req->op.search.base,
229 (const char * const *)base_attrs,
231 ac, asq_base_callback,
233 if (ret != LDB_SUCCESS) {
234 return LDB_ERR_OPERATIONS_ERROR;
240 static int asq_build_multiple_requests(struct asq_context *ac, bool *terminated)
242 struct ldb_control **saved_controls;
243 struct ldb_control *control;
245 struct ldb_message_element *el;
248 if (ac->base_res == NULL) {
249 return LDB_ERR_NO_SUCH_OBJECT;
252 el = ldb_msg_find_element(ac->base_res->message, ac->req_attribute);
253 /* no values found */
255 ac->asq_ret = ASQ_CTRL_SUCCESS;
257 return asq_search_terminate(ac);
260 ac->num_reqs = el->num_values;
262 ac->reqs = talloc_array(ac, struct ldb_request *, ac->num_reqs);
263 if (ac->reqs == NULL) {
264 return LDB_ERR_OPERATIONS_ERROR;
267 for (i = 0; i < el->num_values; i++) {
269 dn = ldb_dn_new(ac, ac->module->ldb,
270 (const char *)el->values[i].data);
271 if ( ! ldb_dn_validate(dn)) {
272 ac->asq_ret = ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX;
274 return asq_search_terminate(ac);
277 ret = ldb_build_search_req_ex(&ac->reqs[i],
280 ac->req->op.search.tree,
283 ac, asq_reqs_callback,
285 if (ret != LDB_SUCCESS) {
286 return LDB_ERR_OPERATIONS_ERROR;
289 /* remove the ASQ control itself */
290 control = ldb_request_get_control(ac->req, LDB_CONTROL_ASQ_OID);
291 if (!save_controls(control, ac->reqs[i], &saved_controls)) {
292 return LDB_ERR_OPERATIONS_ERROR;
299 static int asq_search_continue(struct asq_context *ac)
301 bool terminated = false;
305 case ASQ_SEARCH_BASE:
307 /* build up the requests call chain */
308 ret = asq_build_multiple_requests(ac, &terminated);
309 if (ret != LDB_SUCCESS || terminated) {
313 ac->step = ASQ_SEARCH_MULTI;
315 return ldb_request(ac->module->ldb, ac->reqs[ac->cur_req]);
317 case ASQ_SEARCH_MULTI:
321 if (ac->cur_req == ac->num_reqs) {
323 return asq_search_terminate(ac);
326 return ldb_request(ac->module->ldb, ac->reqs[ac->cur_req]);
329 return LDB_ERR_OPERATIONS_ERROR;
332 static int asq_search(struct ldb_module *module, struct ldb_request *req)
334 struct ldb_request *base_req;
335 struct ldb_control *control;
336 struct asq_context *ac;
339 /* check if there's a paged request control */
340 control = ldb_request_get_control(req, LDB_CONTROL_ASQ_OID);
341 if (control == NULL) {
342 /* not found go on */
343 return ldb_next_request(module, req);
346 ac = asq_context_init(module, req);
348 return LDB_ERR_OPERATIONS_ERROR;
351 /* check the search is well formed */
352 if (req->op.search.scope != LDB_SCOPE_BASE) {
353 ac->asq_ret = ASQ_CTRL_UNWILLING_TO_PERFORM;
354 return asq_search_terminate(ac);
357 ac->asq_ctrl = talloc_get_type(control->data, struct ldb_asq_control);
359 return LDB_ERR_PROTOCOL_ERROR;
362 ret = asq_build_first_request(ac, &base_req);
363 if (ret != LDB_SUCCESS) {
367 ac->step = ASQ_SEARCH_BASE;
369 return ldb_request(module->ldb, base_req);
372 static int asq_init(struct ldb_module *module)
376 ret = ldb_mod_register_control(module, LDB_CONTROL_ASQ_OID);
377 if (ret != LDB_SUCCESS) {
378 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "asq: Unable to register control with rootdse!\n");
381 return ldb_next_init(module);
384 const struct ldb_module_ops ldb_asq_module_ops = {
386 .search = asq_search,
387 .init_context = asq_init