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"
41 enum {ASQ_INIT
, ASQ_SEARCH_BASE
, ASQ_SEARCH_MULTI
} step
;
43 struct ldb_module
*module
;
44 struct ldb_request
*orig_req
;
46 struct ldb_asq_control
*asq_ctrl
;
48 const char * const *req_attrs
;
52 ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX
= 21,
53 ASQ_CTRL_UNWILLING_TO_PERFORM
= 53,
54 ASQ_CTRL_AFFECTS_MULTIPLE_DSA
= 71
57 struct ldb_request
*base_req
;
58 struct ldb_reply
*base_res
;
60 struct ldb_request
**reqs
;
64 struct ldb_control
**controls
;
67 static struct ldb_handle
*init_handle(struct ldb_request
*req
, struct ldb_module
*module
)
69 struct asq_context
*ac
;
72 h
= talloc_zero(req
, struct ldb_handle
);
74 ldb_set_errstring(module
->ldb
, "Out of Memory");
80 ac
= talloc_zero(h
, struct asq_context
);
82 ldb_set_errstring(module
->ldb
, "Out of Memory");
87 h
->private_data
= (void *)ac
;
89 h
->state
= LDB_ASYNC_INIT
;
90 h
->status
= LDB_SUCCESS
;
99 static int asq_terminate(struct ldb_handle
*handle
)
101 struct asq_context
*ac
;
102 struct ldb_reply
*ares
;
103 struct ldb_asq_control
*asq
;
106 ac
= talloc_get_type(handle
->private_data
, struct asq_context
);
108 return LDB_ERR_OPERATIONS_ERROR
;
111 handle
->status
= LDB_SUCCESS
;
112 handle
->state
= LDB_ASYNC_DONE
;
114 ares
= talloc_zero(ac
, struct ldb_reply
);
116 return LDB_ERR_OPERATIONS_ERROR
;
118 ares
->type
= LDB_REPLY_DONE
;
121 for (i
= 0; ac
->controls
[i
]; i
++);
122 ares
->controls
= talloc_move(ares
, &ac
->controls
);
127 ares
->controls
= talloc_realloc(ares
, ares
->controls
, struct ldb_control
*, i
+ 2);
129 if (ares
->controls
== NULL
)
130 return LDB_ERR_OPERATIONS_ERROR
;
132 ares
->controls
[i
] = talloc(ares
->controls
, struct ldb_control
);
133 if (ares
->controls
[i
] == NULL
)
134 return LDB_ERR_OPERATIONS_ERROR
;
136 ares
->controls
[i
]->oid
= LDB_CONTROL_ASQ_OID
;
137 ares
->controls
[i
]->critical
= 0;
139 asq
= talloc_zero(ares
->controls
[i
], struct ldb_asq_control
);
141 return LDB_ERR_OPERATIONS_ERROR
;
143 asq
->result
= ac
->asq_ret
;
145 ares
->controls
[i
]->data
= asq
;
147 ares
->controls
[i
+ 1] = NULL
;
149 ac
->orig_req
->callback(ac
->module
->ldb
, ac
->orig_req
->context
, ares
);
154 static int asq_base_callback(struct ldb_context
*ldb
, void *context
, struct ldb_reply
*ares
)
156 struct asq_context
*ac
;
158 if (!context
|| !ares
) {
159 ldb_set_errstring(ldb
, "NULL Context or Result in callback");
163 ac
= talloc_get_type(context
, struct asq_context
);
168 /* we are interested only in the single reply (base search) we receive here */
169 if (ares
->type
== LDB_REPLY_ENTRY
) {
170 ac
->base_res
= talloc_move(ac
, &ares
);
178 return LDB_ERR_OPERATIONS_ERROR
;
181 static int asq_reqs_callback(struct ldb_context
*ldb
, void *context
, struct ldb_reply
*ares
)
183 struct asq_context
*ac
;
185 if (!context
|| !ares
) {
186 ldb_set_errstring(ldb
, "NULL Context or Result in callback");
190 ac
= talloc_get_type(context
, struct asq_context
);
195 /* we are interested only in the single reply (base search) we receive here */
196 if (ares
->type
== LDB_REPLY_ENTRY
) {
198 /* pass the message up to the original callback as we
199 * do not have to elaborate on it any further */
200 return ac
->orig_req
->callback(ac
->module
->ldb
, ac
->orig_req
->context
, ares
);
202 } else { /* ignore any REFERRAL or DONE reply */
209 return LDB_ERR_OPERATIONS_ERROR
;
212 static int asq_build_first_request(struct asq_context
*ac
)
216 ac
->base_req
= talloc_zero(ac
, struct ldb_request
);
217 if (ac
->base_req
== NULL
) return LDB_ERR_OPERATIONS_ERROR
;
219 ac
->base_req
->operation
= ac
->orig_req
->operation
;
220 ac
->base_req
->op
.search
.base
= ac
->orig_req
->op
.search
.base
;
221 ac
->base_req
->op
.search
.scope
= LDB_SCOPE_BASE
;
222 ac
->base_req
->op
.search
.tree
= ac
->orig_req
->op
.search
.tree
;
223 base_attrs
= talloc_array(ac
->base_req
, char *, 2);
224 if (base_attrs
== NULL
) return LDB_ERR_OPERATIONS_ERROR
;
226 base_attrs
[0] = talloc_strdup(base_attrs
, ac
->asq_ctrl
->source_attribute
);
227 if (base_attrs
[0] == NULL
) return LDB_ERR_OPERATIONS_ERROR
;
229 base_attrs
[1] = NULL
;
230 ac
->base_req
->op
.search
.attrs
= (const char * const *)base_attrs
;
232 ac
->base_req
->context
= ac
;
233 ac
->base_req
->callback
= asq_base_callback
;
234 ldb_set_timeout_from_prev_req(ac
->module
->ldb
, ac
->orig_req
, ac
->base_req
);
239 static int asq_build_multiple_requests(struct asq_context
*ac
, struct ldb_handle
*handle
)
241 struct ldb_message_element
*el
;
244 /* look up the DNs */
245 if (ac
->base_res
== NULL
) {
246 return LDB_ERR_NO_SUCH_OBJECT
;
248 el
= ldb_msg_find_element(ac
->base_res
->message
, ac
->req_attribute
);
249 /* no values found */
251 ac
->asq_ret
= ASQ_CTRL_SUCCESS
;
252 return asq_terminate(handle
);
255 ac
->num_reqs
= el
->num_values
;
257 ac
->reqs
= talloc_array(ac
, struct ldb_request
*, ac
->num_reqs
);
258 if (ac
->reqs
== NULL
) {
259 return LDB_ERR_OPERATIONS_ERROR
;
262 for (i
= 0; i
< el
->num_values
; i
++) {
264 ac
->reqs
[i
] = talloc_zero(ac
->reqs
, struct ldb_request
);
265 if (ac
->reqs
[i
] == NULL
)
266 return LDB_ERR_OPERATIONS_ERROR
;
267 ac
->reqs
[i
]->operation
= LDB_SEARCH
;
268 ac
->reqs
[i
]->op
.search
.base
= ldb_dn_new(ac
->reqs
[i
], ac
->module
->ldb
, (const char *)el
->values
[i
].data
);
269 if ( ! ldb_dn_validate(ac
->reqs
[i
]->op
.search
.base
)) {
270 ac
->asq_ret
= ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX
;
271 return asq_terminate(handle
);
273 ac
->reqs
[i
]->op
.search
.scope
= LDB_SCOPE_BASE
;
274 ac
->reqs
[i
]->op
.search
.tree
= ac
->base_req
->op
.search
.tree
;
275 ac
->reqs
[i
]->op
.search
.attrs
= ac
->req_attrs
;
277 ac
->reqs
[i
]->context
= ac
;
278 ac
->reqs
[i
]->callback
= asq_reqs_callback
;
279 ldb_set_timeout_from_prev_req(ac
->module
->ldb
, ac
->base_req
, ac
->reqs
[i
]);
285 static int asq_search_continue(struct ldb_handle
*handle
)
287 struct asq_context
*ac
;
290 if (!handle
|| !handle
->private_data
) {
291 return LDB_ERR_OPERATIONS_ERROR
;
294 if (handle
->state
== LDB_ASYNC_DONE
) {
295 return handle
->status
;
298 ac
= talloc_get_type(handle
->private_data
, struct asq_context
);
300 return LDB_ERR_OPERATIONS_ERROR
;
305 /* check the search is well formed */
306 if (ac
->orig_req
->op
.search
.scope
!= LDB_SCOPE_BASE
) {
307 ac
->asq_ret
= ASQ_CTRL_UNWILLING_TO_PERFORM
;
308 return asq_terminate(handle
);
311 ac
->req_attrs
= ac
->orig_req
->op
.search
.attrs
;
312 ac
->req_attribute
= talloc_strdup(ac
, ac
->asq_ctrl
->source_attribute
);
313 if (ac
->req_attribute
== NULL
)
314 return LDB_ERR_OPERATIONS_ERROR
;
316 /* get the object to retrieve the DNs to search */
317 ret
= asq_build_first_request(ac
);
318 if (ret
!= LDB_SUCCESS
) {
322 ac
->step
= ASQ_SEARCH_BASE
;
324 handle
->state
= LDB_ASYNC_PENDING
;
325 handle
->status
= LDB_SUCCESS
;
327 return ldb_request(ac
->module
->ldb
, ac
->base_req
);
329 case ASQ_SEARCH_BASE
:
331 ret
= ldb_wait(ac
->base_req
->handle
, LDB_WAIT_NONE
);
333 if (ret
!= LDB_SUCCESS
) {
334 handle
->status
= ret
;
338 if (ac
->base_req
->handle
->status
!= LDB_SUCCESS
) {
339 handle
->status
= ac
->base_req
->handle
->status
;
343 if (ac
->base_req
->handle
->state
== LDB_ASYNC_DONE
) {
345 /* build up the requests call chain */
346 ret
= asq_build_multiple_requests(ac
, handle
);
347 if (ret
!= LDB_SUCCESS
) {
350 if (handle
->state
== LDB_ASYNC_DONE
) {
354 ac
->step
= ASQ_SEARCH_MULTI
;
356 return ldb_request(ac
->module
->ldb
, ac
->reqs
[ac
->cur_req
]);
359 /* request still pending, return to cycle again */
362 case ASQ_SEARCH_MULTI
:
364 ret
= ldb_wait(ac
->reqs
[ac
->cur_req
]->handle
, LDB_WAIT_NONE
);
366 if (ret
!= LDB_SUCCESS
) {
367 handle
->status
= ret
;
370 if (ac
->reqs
[ac
->cur_req
]->handle
->status
!= LDB_SUCCESS
) {
371 handle
->status
= ac
->reqs
[ac
->cur_req
]->handle
->status
;
374 if (ac
->reqs
[ac
->cur_req
]->handle
->state
== LDB_ASYNC_DONE
) {
377 if (ac
->cur_req
< ac
->num_reqs
) {
378 return ldb_request(ac
->module
->ldb
, ac
->reqs
[ac
->cur_req
]);
381 return asq_terminate(handle
);
384 /* request still pending, return to cycle again */
388 ret
= LDB_ERR_OPERATIONS_ERROR
;
393 handle
->state
= LDB_ASYNC_DONE
;
397 static int asq_search(struct ldb_module
*module
, struct ldb_request
*req
)
399 struct ldb_control
*control
;
400 struct asq_context
*ac
;
401 struct ldb_handle
*h
;
403 /* check if there's a paged request control */
404 control
= ldb_request_get_control(req
, LDB_CONTROL_ASQ_OID
);
405 if (control
== NULL
) {
406 /* not found go on */
407 return ldb_next_request(module
, req
);
412 if (!req
->callback
|| !req
->context
) {
413 ldb_set_errstring(module
->ldb
,
414 "Async interface called with NULL callback function or NULL context");
415 return LDB_ERR_OPERATIONS_ERROR
;
418 h
= init_handle(req
, module
);
420 return LDB_ERR_OPERATIONS_ERROR
;
422 ac
= talloc_get_type(h
->private_data
, struct asq_context
);
424 ac
->asq_ctrl
= talloc_get_type(control
->data
, struct ldb_asq_control
);
426 return LDB_ERR_PROTOCOL_ERROR
;
431 return asq_search_continue(h
);
434 static int asq_wait_all(struct ldb_handle
*handle
)
438 while (handle
->state
!= LDB_ASYNC_DONE
) {
439 ret
= asq_search_continue(handle
);
440 if (ret
!= LDB_SUCCESS
) {
445 return handle
->status
;
448 static int asq_wait(struct ldb_handle
*handle
, enum ldb_wait_type type
)
450 if (type
== LDB_WAIT_ALL
) {
451 return asq_wait_all(handle
);
453 return asq_search_continue(handle
);
457 static int asq_init(struct ldb_module
*module
)
459 struct ldb_request
*req
;
462 req
= talloc_zero(module
, struct ldb_request
);
464 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "asq: Out of memory!\n");
465 return LDB_ERR_OPERATIONS_ERROR
;
468 req
->operation
= LDB_REQ_REGISTER_CONTROL
;
469 req
->op
.reg_control
.oid
= LDB_CONTROL_ASQ_OID
;
471 ret
= ldb_request(module
->ldb
, req
);
472 if (ret
!= LDB_SUCCESS
) {
473 ldb_debug(module
->ldb
, LDB_DEBUG_WARNING
, "asq: Unable to register control with rootdse!\n");
476 return ldb_next_init(module
);
480 static const struct ldb_module_ops asq_ops
= {
482 .search
= asq_search
,
484 .init_context
= asq_init
487 int ldb_asq_init(void)
489 return ldb_register_module(&asq_ops
);