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 objects pointed by
30 * the DNs contained in the references attribute
36 #include "system/filesys.h"
37 #include "system/time.h"
38 #include "ldb_module.h"
42 enum {ASQ_SEARCH_BASE, ASQ_SEARCH_MULTI} step;
44 struct ldb_module *module;
45 struct ldb_request *req;
47 struct ldb_asq_control *asq_ctrl;
49 const char * const *req_attrs;
53 ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX = 21,
54 ASQ_CTRL_UNWILLING_TO_PERFORM = 53,
55 ASQ_CTRL_AFFECTS_MULTIPLE_DSA = 71
58 struct ldb_reply *base_res;
60 struct ldb_request **reqs;
61 unsigned int num_reqs;
64 struct ldb_control **controls;
67 static struct asq_context *asq_context_init(struct ldb_module *module, struct ldb_request *req)
69 struct ldb_context *ldb;
70 struct asq_context *ac;
72 ldb = ldb_module_get_ctx(module);
74 ac = talloc_zero(req, struct asq_context);
86 static int asq_search_continue(struct asq_context *ac);
88 static int asq_search_terminate(struct asq_context *ac)
90 struct ldb_asq_control *asq;
94 for (i = 0; ac->controls[i]; i++) /* count em */ ;
99 ac->controls = talloc_realloc(ac, ac->controls, struct ldb_control *, i + 2);
101 if (ac->controls == NULL) {
102 return LDB_ERR_OPERATIONS_ERROR;
105 ac->controls[i] = talloc(ac->controls, struct ldb_control);
106 if (ac->controls[i] == NULL) {
107 return LDB_ERR_OPERATIONS_ERROR;
110 ac->controls[i]->oid = LDB_CONTROL_ASQ_OID;
111 ac->controls[i]->critical = 0;
113 asq = talloc_zero(ac->controls[i], struct ldb_asq_control);
115 return LDB_ERR_OPERATIONS_ERROR;
117 asq->result = ac->asq_ret;
119 ac->controls[i]->data = asq;
121 ac->controls[i + 1] = NULL;
123 return ldb_module_done(ac->req, ac->controls, NULL, LDB_SUCCESS);
126 static int asq_base_callback(struct ldb_request *req, struct ldb_reply *ares)
128 struct asq_context *ac;
131 ac = talloc_get_type(req->context, struct asq_context);
134 return ldb_module_done(ac->req, NULL, NULL,
135 LDB_ERR_OPERATIONS_ERROR);
137 if (ares->error != LDB_SUCCESS) {
138 return ldb_module_done(ac->req, ares->controls,
139 ares->response, ares->error);
142 switch (ares->type) {
143 case LDB_REPLY_ENTRY:
144 ac->base_res = talloc_move(ac, &ares);
147 case LDB_REPLY_REFERRAL:
148 /* ignore referrals */
157 ret = asq_search_continue(ac);
158 if (ret != LDB_SUCCESS) {
159 return ldb_module_done(ac->req, NULL, NULL, ret);
167 static int asq_reqs_callback(struct ldb_request *req, struct ldb_reply *ares)
169 struct asq_context *ac;
172 ac = talloc_get_type(req->context, struct asq_context);
175 return ldb_module_done(ac->req, NULL, NULL,
176 LDB_ERR_OPERATIONS_ERROR);
178 if (ares->error != LDB_SUCCESS) {
179 return ldb_module_done(ac->req, ares->controls,
180 ares->response, ares->error);
183 switch (ares->type) {
184 case LDB_REPLY_ENTRY:
185 /* pass the message up to the original callback as we
186 * do not have to elaborate on it any further */
187 ret = ldb_module_send_entry(ac->req, ares->message, ares->controls);
188 if (ret != LDB_SUCCESS) {
189 return ldb_module_done(ac->req, NULL, NULL, ret);
194 case LDB_REPLY_REFERRAL:
195 /* ignore referrals */
203 ret = asq_search_continue(ac);
204 if (ret != LDB_SUCCESS) {
205 return ldb_module_done(ac->req, NULL, NULL, ret);
213 static int asq_build_first_request(struct asq_context *ac, struct ldb_request **base_req)
215 struct ldb_context *ldb;
216 const char **base_attrs;
219 ldb = ldb_module_get_ctx(ac->module);
221 ac->req_attrs = ac->req->op.search.attrs;
222 ac->req_attribute = talloc_strdup(ac, ac->asq_ctrl->source_attribute);
223 if (ac->req_attribute == NULL)
224 return LDB_ERR_OPERATIONS_ERROR;
226 base_attrs = talloc_array(ac, const char *, 2);
227 if (base_attrs == NULL) return LDB_ERR_OPERATIONS_ERROR;
229 base_attrs[0] = talloc_strdup(base_attrs, ac->asq_ctrl->source_attribute);
230 if (base_attrs[0] == NULL) return LDB_ERR_OPERATIONS_ERROR;
232 base_attrs[1] = NULL;
234 ret = ldb_build_search_req(base_req, ldb, ac,
235 ac->req->op.search.base,
238 (const char * const *)base_attrs,
240 ac, asq_base_callback,
242 ldb_req_mark_trusted(*base_req);
243 if (ret != LDB_SUCCESS) {
250 static int asq_build_multiple_requests(struct asq_context *ac, bool *terminated)
252 struct ldb_context *ldb;
253 struct ldb_control **saved_controls;
254 struct ldb_control *control;
256 struct ldb_message_element *el;
260 if (ac->base_res == NULL) {
261 return LDB_ERR_NO_SUCH_OBJECT;
264 ldb = ldb_module_get_ctx(ac->module);
266 el = ldb_msg_find_element(ac->base_res->message, ac->req_attribute);
267 /* no values found */
269 ac->asq_ret = ASQ_CTRL_SUCCESS;
271 return asq_search_terminate(ac);
274 ac->num_reqs = el->num_values;
276 ac->reqs = talloc_array(ac, struct ldb_request *, ac->num_reqs);
277 if (ac->reqs == NULL) {
278 return LDB_ERR_OPERATIONS_ERROR;
281 for (i = 0; i < el->num_values; i++) {
283 dn = ldb_dn_new(ac, ldb,
284 (const char *)el->values[i].data);
285 if ( ! ldb_dn_validate(dn)) {
286 ac->asq_ret = ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX;
288 return asq_search_terminate(ac);
291 ret = ldb_build_search_req_ex(&ac->reqs[i],
294 ac->req->op.search.tree,
297 ac, asq_reqs_callback,
299 if (ret != LDB_SUCCESS) {
303 /* remove the ASQ control itself */
304 control = ldb_request_get_control(ac->req, LDB_CONTROL_ASQ_OID);
305 if (!ldb_save_controls(control, ac->reqs[i], &saved_controls)) {
306 return LDB_ERR_OPERATIONS_ERROR;
313 static int asq_search_continue(struct asq_context *ac)
315 struct ldb_context *ldb;
316 bool terminated = false;
319 ldb = ldb_module_get_ctx(ac->module);
322 case ASQ_SEARCH_BASE:
324 /* build up the requests call chain */
325 ret = asq_build_multiple_requests(ac, &terminated);
326 if (ret != LDB_SUCCESS || terminated) {
330 ac->step = ASQ_SEARCH_MULTI;
332 return ldb_request(ldb, ac->reqs[ac->cur_req]);
334 case ASQ_SEARCH_MULTI:
338 if (ac->cur_req == ac->num_reqs) {
340 return asq_search_terminate(ac);
343 return ldb_request(ldb, ac->reqs[ac->cur_req]);
346 return LDB_ERR_OPERATIONS_ERROR;
349 static int asq_search(struct ldb_module *module, struct ldb_request *req)
351 struct ldb_context *ldb;
352 struct ldb_request *base_req;
353 struct ldb_control *control;
354 struct asq_context *ac;
357 ldb = ldb_module_get_ctx(module);
359 /* check if there's an ASQ control */
360 control = ldb_request_get_control(req, LDB_CONTROL_ASQ_OID);
361 if (control == NULL) {
362 /* not found go on */
363 return ldb_next_request(module, req);
366 ac = asq_context_init(module, req);
368 return LDB_ERR_OPERATIONS_ERROR;
371 /* check the search is well formed */
372 if (req->op.search.scope != LDB_SCOPE_BASE) {
373 ac->asq_ret = ASQ_CTRL_UNWILLING_TO_PERFORM;
374 return asq_search_terminate(ac);
377 ac->asq_ctrl = talloc_get_type(control->data, struct ldb_asq_control);
379 return LDB_ERR_PROTOCOL_ERROR;
382 ret = asq_build_first_request(ac, &base_req);
383 if (ret != LDB_SUCCESS) {
387 ac->step = ASQ_SEARCH_BASE;
389 return ldb_request(ldb, base_req);
392 static int asq_init(struct ldb_module *module)
394 struct ldb_context *ldb;
397 ldb = ldb_module_get_ctx(module);
399 ret = ldb_mod_register_control(module, LDB_CONTROL_ASQ_OID);
400 if (ret != LDB_SUCCESS) {
401 ldb_debug(ldb, LDB_DEBUG_WARNING, "asq: Unable to register control with rootdse!");
404 return ldb_next_init(module);
407 static const struct ldb_module_ops ldb_asq_module_ops = {
409 .search = asq_search,
410 .init_context = asq_init
413 int ldb_asq_init(const char *version)
415 LDB_MODULE_CHECK_VERSION(version);
416 return ldb_register_module(&ldb_asq_module_ops);