4 Copyright (C) Simo Sorce 2005
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 2 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, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 * Component: ldb attribute scoped query control module
30 * Description: this module searches all the the objects pointed
31 * by the DNs contained in the references attribute
37 #include "ldb/include/includes.h"
39 #define ASQ_CTRL_SUCCESS 0
40 #define ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX 21
41 #define ASQ_CTRL_UNWILLING_TO_PERFORM 53
42 #define ASQ_CTRL_AFFECTS_MULTIPLE_DSA 71
44 struct asq_async_context {
46 enum {ASQ_SEARCH_BASE, ASQ_SEARCH_MULTI} step;
48 struct ldb_module *module;
50 int (*up_callback)(struct ldb_context *, void *, struct ldb_async_result *);
53 const char * const *req_attrs;
57 struct ldb_request *base_req;
58 struct ldb_async_result *base_res;
60 struct ldb_request **reqs;
64 struct ldb_control **controls;
67 static struct ldb_async_handle *init_handle(void *mem_ctx, struct ldb_module *module,
69 int (*callback)(struct ldb_context *, void *, struct ldb_async_result *),
72 struct asq_async_context *ac;
73 struct ldb_async_handle *h;
75 h = talloc_zero(mem_ctx, struct ldb_async_handle);
77 ldb_set_errstring(module->ldb, talloc_asprintf(module, "Out of Memory"));
83 ac = talloc_zero(h, struct asq_async_context);
85 ldb_set_errstring(module->ldb, talloc_asprintf(module, "Out of Memory"));
90 h->private_data = (void *)ac;
92 h->state = LDB_ASYNC_INIT;
93 h->status = LDB_SUCCESS;
96 ac->up_context = context;
97 ac->up_callback = callback;
98 ac->timeout = timeout;
103 static int asq_terminate(struct ldb_async_handle *handle)
105 struct asq_async_context *ac;
106 struct ldb_async_result *ares;
107 struct ldb_asq_control *asq;
110 ac = talloc_get_type(handle->private_data, struct asq_async_context);
112 handle->status = LDB_SUCCESS;
113 handle->state = LDB_ASYNC_DONE;
115 ares = talloc_zero(ac, struct ldb_async_result);
117 return LDB_ERR_OPERATIONS_ERROR;
119 ares->type = LDB_REPLY_DONE;
122 for (i = 0; ac->controls[i]; i++);
123 ares->controls = talloc_steal(ares, ac->controls);
128 ares->controls = talloc_realloc(ares, ares->controls, struct ldb_control *, i + 2);
130 if (ares->controls == NULL)
131 return LDB_ERR_OPERATIONS_ERROR;
133 ares->controls[i] = talloc(ares->controls, struct ldb_control);
134 if (ares->controls[i] == NULL)
135 return LDB_ERR_OPERATIONS_ERROR;
137 ares->controls[i]->oid = LDB_CONTROL_ASQ_OID;
138 ares->controls[i]->critical = 0;
140 asq = talloc_zero(ares->controls[i], struct ldb_asq_control);
142 return LDB_ERR_OPERATIONS_ERROR;
144 asq->result = ac->asq_ret;
146 ares->controls[i]->data = asq;
148 ares->controls[i + 1] = NULL;
150 ac->up_callback(ac->module->ldb, ac->up_context, ares);
155 static int asq_base_callback(struct ldb_context *ldb, void *context, struct ldb_async_result *ares)
157 struct asq_async_context *ac;
159 if (!context || !ares) {
160 ldb_set_errstring(ldb, talloc_asprintf(ldb, "NULL Context or Result in callback"));
164 ac = talloc_get_type(context, struct asq_async_context);
166 /* we are interested only in the single reply (base search) we receive here */
167 if (ares->type == LDB_REPLY_ENTRY) {
168 ac->base_res = talloc_steal(ac, ares);
176 return LDB_ERR_OPERATIONS_ERROR;
179 static int asq_reqs_callback(struct ldb_context *ldb, void *context, struct ldb_async_result *ares)
181 struct asq_async_context *ac;
183 if (!context || !ares) {
184 ldb_set_errstring(ldb, talloc_asprintf(ldb, "NULL Context or Result in callback"));
188 ac = talloc_get_type(context, struct asq_async_context);
190 /* we are interested only in the single reply (base search) we receive here */
191 if (ares->type == LDB_REPLY_ENTRY) {
193 /* pass the message up to the original callback as we
194 * do not have to elaborate on it any further */
195 return ac->up_callback(ac->module->ldb, ac->up_context, ares);
197 } else { /* ignore any REFERRAL or DONE reply */
204 return LDB_ERR_OPERATIONS_ERROR;
207 static int asq_search(struct ldb_module *module, struct ldb_request *req)
209 struct ldb_control *control;
210 struct ldb_asq_control *asq_ctrl;
211 struct asq_async_context *ac;
212 struct ldb_async_handle *h;
216 /* check if there's a paged request control */
217 control = get_control_from_list(req->controls, LDB_CONTROL_ASQ_OID);
218 if (control == NULL) {
219 /* not found go on */
220 return ldb_next_request(module, req);
223 req->async.handle = NULL;
225 if (!req->async.callback || !req->async.context) {
226 ldb_set_errstring(module->ldb, talloc_asprintf(module,
227 "Async interface called with NULL callback function or NULL context"));
228 return LDB_ERR_OPERATIONS_ERROR;
231 asq_ctrl = talloc_get_type(control->data, struct ldb_asq_control);
233 return LDB_ERR_PROTOCOL_ERROR;
236 h = init_handle(req, module, req->async.context, req->async.callback, req->async.timeout);
238 return LDB_ERR_OPERATIONS_ERROR;
240 ac = talloc_get_type(h->private_data, struct asq_async_context);
242 req->async.handle = h;
244 /* check the search is well formed */
245 if (req->op.search.scope != LDB_SCOPE_BASE) {
246 ac->asq_ret = ASQ_CTRL_UNWILLING_TO_PERFORM;
247 return asq_terminate(h);
250 ac->req_attrs = req->op.search.attrs;
251 ac->req_attribute = talloc_strdup(ac, asq_ctrl->source_attribute);
252 if (ac->req_attribute == NULL)
253 return LDB_ERR_OPERATIONS_ERROR;
255 /* get the object to retrieve the DNs to search */
256 ac->base_req = talloc_zero(req, struct ldb_request);
257 if (ac->base_req == NULL)
258 return LDB_ERR_OPERATIONS_ERROR;
259 ac->base_req->operation = req->operation;
260 ac->base_req->op.search.base = req->op.search.base;
261 ac->base_req->op.search.scope = LDB_SCOPE_BASE;
262 ac->base_req->op.search.tree = req->op.search.tree;
263 base_attrs = talloc_array(ac->base_req, char *, 2);
264 if (base_attrs == NULL)
265 return LDB_ERR_OPERATIONS_ERROR;
266 base_attrs[0] = talloc_strdup(base_attrs, asq_ctrl->source_attribute);
267 if (base_attrs[0] == NULL)
268 return LDB_ERR_OPERATIONS_ERROR;
269 base_attrs[1] = NULL;
270 ac->base_req->op.search.attrs = (const char * const *)base_attrs;
272 ac->base_req->async.context = ac;
273 ac->base_req->async.callback = asq_base_callback;
274 ac->base_req->async.timeout = req->async.timeout;
276 ac->step = ASQ_SEARCH_BASE;
278 ret = ldb_request(module->ldb, ac->base_req);
280 if (ret != LDB_SUCCESS) {
287 static int asq_async_requests(struct ldb_async_handle *handle) {
288 struct asq_async_context *ac;
289 struct ldb_message_element *el;
292 ac = talloc_get_type(handle->private_data, struct asq_async_context);
294 /* look up the DNs */
295 el = ldb_msg_find_element(ac->base_res->message, ac->req_attribute);
296 /* no values found */
298 ac->asq_ret = ASQ_CTRL_SUCCESS;
299 return asq_terminate(handle);
302 /* build up the requests call chain */
303 ac->num_reqs = el->num_values;
305 ac->reqs = talloc_array(ac, struct ldb_request *, ac->num_reqs);
306 if (ac->reqs == NULL) {
307 return LDB_ERR_OPERATIONS_ERROR;
310 for (i = 0; i < el->num_values; i++) {
312 ac->reqs[i] = talloc_zero(ac->reqs, struct ldb_request);
313 if (ac->reqs[i] == NULL)
314 return LDB_ERR_OPERATIONS_ERROR;
315 ac->reqs[i]->operation = LDB_SEARCH;
316 ac->reqs[i]->op.search.base = ldb_dn_explode(ac->reqs[i], (const char *)el->values[i].data);
317 if (ac->reqs[i]->op.search.base == NULL) {
318 ac->asq_ret = ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX;
319 return asq_terminate(handle);
321 ac->reqs[i]->op.search.scope = LDB_SCOPE_BASE;
322 ac->reqs[i]->op.search.tree = ac->base_req->op.search.tree;
323 ac->reqs[i]->op.search.attrs = ac->req_attrs;
325 ac->reqs[i]->async.context = ac;
326 ac->reqs[i]->async.callback = asq_reqs_callback;
327 ac->reqs[i]->async.timeout = ac->base_req->async.timeout;
330 ac->step = ASQ_SEARCH_MULTI;
335 static int asq_async_wait_none(struct ldb_async_handle *handle)
337 struct asq_async_context *ac;
340 if (!handle || !handle->private_data) {
341 return LDB_ERR_OPERATIONS_ERROR;
344 if (handle->state == LDB_ASYNC_DONE) {
345 return handle->status;
348 handle->state = LDB_ASYNC_PENDING;
349 handle->status = LDB_SUCCESS;
351 ac = talloc_get_type(handle->private_data, struct asq_async_context);
355 case ASQ_SEARCH_BASE:
356 ret = ldb_async_wait(ac->base_req->async.handle, LDB_WAIT_NONE);
358 if (ret != LDB_SUCCESS) {
359 handle->status = ret;
363 if (ac->base_req->async.handle->status != LDB_SUCCESS) {
364 handle->status = ac->base_req->async.handle->status;
367 if (ac->base_req->async.handle->state != LDB_ASYNC_DONE) {
371 ret = asq_async_requests(handle);
373 case ASQ_SEARCH_MULTI:
375 if (ac->reqs[ac->cur_req]->async.handle == NULL) {
376 ret = ldb_request(ac->module->ldb, ac->reqs[ac->cur_req]);
377 if (ret != LDB_SUCCESS) {
382 ret = ldb_async_wait(ac->reqs[ac->cur_req]->async.handle, LDB_WAIT_NONE);
384 if (ret != LDB_SUCCESS) {
385 handle->status = ret;
388 if (ac->reqs[ac->cur_req]->async.handle->status != LDB_SUCCESS) {
389 handle->status = ac->reqs[ac->cur_req]->async.handle->status;
392 if (ac->reqs[ac->cur_req]->async.handle->state == LDB_ASYNC_DONE) {
396 if (ac->cur_req < ac->num_reqs) {
400 return asq_terminate(handle);
403 ret = LDB_ERR_OPERATIONS_ERROR;
410 handle->state = LDB_ASYNC_DONE;
414 static int asq_async_wait_all(struct ldb_async_handle *handle)
418 while (handle->state != LDB_ASYNC_DONE) {
419 ret = asq_async_wait_none(handle);
420 if (ret != LDB_SUCCESS) {
425 return handle->status;
428 static int asq_async_wait(struct ldb_async_handle *handle, enum ldb_async_wait_type type)
430 if (type == LDB_WAIT_ALL) {
431 return asq_async_wait_all(handle);
433 return asq_async_wait_none(handle);
437 static int asq_init(struct ldb_module *module)
439 struct ldb_request request;
442 request.operation = LDB_REQ_REGISTER;
443 request.op.reg.oid = LDB_CONTROL_ASQ_OID;
444 request.controls = NULL;
446 ret = ldb_request(module->ldb, &request);
447 if (ret != LDB_SUCCESS) {
448 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "asq: Unable to register control with rootdse!\n");
449 return LDB_ERR_OTHER;
452 return ldb_next_init(module);
456 static const struct ldb_module_ops asq_ops = {
458 .search = asq_search,
459 .async_wait = asq_async_wait,
460 .init_context = asq_init
463 int ldb_asq_init(void)
465 return ldb_register_module(&asq_ops);