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_SEARCH_BASE
, ASQ_SEARCH_MULTI
} step
;
43 struct ldb_module
*module
;
45 int (*up_callback
)(struct ldb_context
*, void *, struct ldb_reply
*);
47 const char * const *req_attrs
;
51 ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX
= 21,
52 ASQ_CTRL_UNWILLING_TO_PERFORM
= 53,
53 ASQ_CTRL_AFFECTS_MULTIPLE_DSA
= 71
56 struct ldb_request
*base_req
;
57 struct ldb_reply
*base_res
;
59 struct ldb_request
**reqs
;
63 struct ldb_control
**controls
;
66 static struct ldb_handle
*init_handle(void *mem_ctx
, struct ldb_module
*module
,
68 int (*callback
)(struct ldb_context
*, void *, struct ldb_reply
*))
70 struct asq_context
*ac
;
73 h
= talloc_zero(mem_ctx
, struct ldb_handle
);
75 ldb_set_errstring(module
->ldb
, "Out of Memory");
81 ac
= talloc_zero(h
, struct asq_context
);
83 ldb_set_errstring(module
->ldb
, "Out of Memory");
88 h
->private_data
= (void *)ac
;
90 h
->state
= LDB_ASYNC_INIT
;
91 h
->status
= LDB_SUCCESS
;
94 ac
->up_context
= context
;
95 ac
->up_callback
= callback
;
100 static int asq_terminate(struct ldb_handle
*handle
)
102 struct asq_context
*ac
;
103 struct ldb_reply
*ares
;
104 struct ldb_asq_control
*asq
;
107 ac
= talloc_get_type(handle
->private_data
, struct asq_context
);
109 return LDB_ERR_OPERATIONS_ERROR
;
112 handle
->status
= LDB_SUCCESS
;
113 handle
->state
= LDB_ASYNC_DONE
;
115 ares
= talloc_zero(ac
, struct ldb_reply
);
117 return LDB_ERR_OPERATIONS_ERROR
;
119 ares
->type
= LDB_REPLY_DONE
;
122 for (i
= 0; ac
->controls
[i
]; i
++);
123 ares
->controls
= talloc_move(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_reply
*ares
)
157 struct asq_context
*ac
;
159 if (!context
|| !ares
) {
160 ldb_set_errstring(ldb
, "NULL Context or Result in callback");
164 if (!(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 if (!(ac
= talloc_get_type(context
, struct asq_context
))) {
194 /* we are interested only in the single reply (base search) we receive here */
195 if (ares
->type
== LDB_REPLY_ENTRY
) {
197 /* pass the message up to the original callback as we
198 * do not have to elaborate on it any further */
199 return ac
->up_callback(ac
->module
->ldb
, ac
->up_context
, ares
);
201 } else { /* ignore any REFERRAL or DONE reply */
208 return LDB_ERR_OPERATIONS_ERROR
;
211 static int asq_search(struct ldb_module
*module
, struct ldb_request
*req
)
213 struct ldb_control
*control
;
214 struct ldb_asq_control
*asq_ctrl
;
215 struct asq_context
*ac
;
216 struct ldb_handle
*h
;
220 /* check if there's a paged request control */
221 control
= get_control_from_list(req
->controls
, LDB_CONTROL_ASQ_OID
);
222 if (control
== NULL
) {
223 /* not found go on */
224 return ldb_next_request(module
, req
);
229 if (!req
->callback
|| !req
->context
) {
230 ldb_set_errstring(module
->ldb
,
231 "Async interface called with NULL callback function or NULL context");
232 return LDB_ERR_OPERATIONS_ERROR
;
235 asq_ctrl
= talloc_get_type(control
->data
, struct ldb_asq_control
);
237 return LDB_ERR_PROTOCOL_ERROR
;
240 h
= init_handle(req
, module
, req
->context
, req
->callback
);
242 return LDB_ERR_OPERATIONS_ERROR
;
244 if (!(ac
= talloc_get_type(h
->private_data
, struct asq_context
))) {
246 return LDB_ERR_OPERATIONS_ERROR
;
251 /* check the search is well formed */
252 if (req
->op
.search
.scope
!= LDB_SCOPE_BASE
) {
253 ac
->asq_ret
= ASQ_CTRL_UNWILLING_TO_PERFORM
;
254 return asq_terminate(h
);
257 ac
->req_attrs
= req
->op
.search
.attrs
;
258 ac
->req_attribute
= talloc_strdup(ac
, asq_ctrl
->source_attribute
);
259 if (ac
->req_attribute
== NULL
)
260 return LDB_ERR_OPERATIONS_ERROR
;
262 /* get the object to retrieve the DNs to search */
263 ac
->base_req
= talloc_zero(req
, struct ldb_request
);
264 if (ac
->base_req
== NULL
)
265 return LDB_ERR_OPERATIONS_ERROR
;
266 ac
->base_req
->operation
= req
->operation
;
267 ac
->base_req
->op
.search
.base
= req
->op
.search
.base
;
268 ac
->base_req
->op
.search
.scope
= LDB_SCOPE_BASE
;
269 ac
->base_req
->op
.search
.tree
= req
->op
.search
.tree
;
270 base_attrs
= talloc_array(ac
->base_req
, char *, 2);
271 if (base_attrs
== NULL
)
272 return LDB_ERR_OPERATIONS_ERROR
;
273 base_attrs
[0] = talloc_strdup(base_attrs
, asq_ctrl
->source_attribute
);
274 if (base_attrs
[0] == NULL
)
275 return LDB_ERR_OPERATIONS_ERROR
;
276 base_attrs
[1] = NULL
;
277 ac
->base_req
->op
.search
.attrs
= (const char * const *)base_attrs
;
279 ac
->base_req
->context
= ac
;
280 ac
->base_req
->callback
= asq_base_callback
;
281 ldb_set_timeout_from_prev_req(module
->ldb
, req
, ac
->base_req
);
283 ac
->step
= ASQ_SEARCH_BASE
;
285 ret
= ldb_request(module
->ldb
, ac
->base_req
);
287 if (ret
!= LDB_SUCCESS
) {
294 static int asq_requests(struct ldb_handle
*handle
) {
295 struct asq_context
*ac
;
296 struct ldb_message_element
*el
;
299 if (!(ac
= talloc_get_type(handle
->private_data
,
300 struct asq_context
))) {
301 return LDB_ERR_OPERATIONS_ERROR
;
304 /* look up the DNs */
305 if (ac
->base_res
== NULL
) {
306 return LDB_ERR_NO_SUCH_OBJECT
;
308 el
= ldb_msg_find_element(ac
->base_res
->message
, ac
->req_attribute
);
309 /* no values found */
311 ac
->asq_ret
= ASQ_CTRL_SUCCESS
;
312 return asq_terminate(handle
);
315 /* build up the requests call chain */
316 ac
->num_reqs
= el
->num_values
;
318 ac
->reqs
= talloc_array(ac
, struct ldb_request
*, ac
->num_reqs
);
319 if (ac
->reqs
== NULL
) {
320 return LDB_ERR_OPERATIONS_ERROR
;
323 for (i
= 0; i
< el
->num_values
; i
++) {
325 ac
->reqs
[i
] = talloc_zero(ac
->reqs
, struct ldb_request
);
326 if (ac
->reqs
[i
] == NULL
)
327 return LDB_ERR_OPERATIONS_ERROR
;
328 ac
->reqs
[i
]->operation
= LDB_SEARCH
;
329 ac
->reqs
[i
]->op
.search
.base
= ldb_dn_explode(ac
->reqs
[i
], (const char *)el
->values
[i
].data
);
330 if (ac
->reqs
[i
]->op
.search
.base
== NULL
) {
331 ac
->asq_ret
= ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX
;
332 return asq_terminate(handle
);
334 ac
->reqs
[i
]->op
.search
.scope
= LDB_SCOPE_BASE
;
335 ac
->reqs
[i
]->op
.search
.tree
= ac
->base_req
->op
.search
.tree
;
336 ac
->reqs
[i
]->op
.search
.attrs
= ac
->req_attrs
;
338 ac
->reqs
[i
]->context
= ac
;
339 ac
->reqs
[i
]->callback
= asq_reqs_callback
;
340 ldb_set_timeout_from_prev_req(ac
->module
->ldb
, ac
->base_req
, ac
->reqs
[i
]);
343 ac
->step
= ASQ_SEARCH_MULTI
;
348 static int asq_wait_none(struct ldb_handle
*handle
)
350 struct asq_context
*ac
;
353 if (!handle
|| !handle
->private_data
) {
354 return LDB_ERR_OPERATIONS_ERROR
;
357 if (handle
->state
== LDB_ASYNC_DONE
) {
358 return handle
->status
;
361 handle
->state
= LDB_ASYNC_PENDING
;
362 handle
->status
= LDB_SUCCESS
;
364 if (!(ac
= talloc_get_type(handle
->private_data
,
365 struct asq_context
))) {
366 return LDB_ERR_OPERATIONS_ERROR
;
370 case ASQ_SEARCH_BASE
:
371 ret
= ldb_wait(ac
->base_req
->handle
, LDB_WAIT_NONE
);
373 if (ret
!= LDB_SUCCESS
) {
374 handle
->status
= ret
;
378 if (ac
->base_req
->handle
->status
!= LDB_SUCCESS
) {
379 handle
->status
= ac
->base_req
->handle
->status
;
382 if (ac
->base_req
->handle
->state
!= LDB_ASYNC_DONE
) {
386 ret
= asq_requests(handle
);
388 /* no break nor return,
389 * the set of requests is performed in ASQ_SEARCH_MULTI
392 case ASQ_SEARCH_MULTI
:
394 if (ac
->reqs
[ac
->cur_req
]->handle
== NULL
) {
395 ret
= ldb_request(ac
->module
->ldb
, ac
->reqs
[ac
->cur_req
]);
396 if (ret
!= LDB_SUCCESS
) {
401 ret
= ldb_wait(ac
->reqs
[ac
->cur_req
]->handle
, LDB_WAIT_NONE
);
403 if (ret
!= LDB_SUCCESS
) {
404 handle
->status
= ret
;
407 if (ac
->reqs
[ac
->cur_req
]->handle
->status
!= LDB_SUCCESS
) {
408 handle
->status
= ac
->reqs
[ac
->cur_req
]->handle
->status
;
411 if (ac
->reqs
[ac
->cur_req
]->handle
->state
== LDB_ASYNC_DONE
) {
415 if (ac
->cur_req
< ac
->num_reqs
) {
419 return asq_terminate(handle
);
422 ret
= LDB_ERR_OPERATIONS_ERROR
;
429 handle
->state
= LDB_ASYNC_DONE
;
433 static int asq_wait_all(struct ldb_handle
*handle
)
437 while (handle
->state
!= LDB_ASYNC_DONE
) {
438 ret
= asq_wait_none(handle
);
439 if (ret
!= LDB_SUCCESS
) {
444 return handle
->status
;
447 static int asq_wait(struct ldb_handle
*handle
, enum ldb_wait_type type
)
449 if (type
== LDB_WAIT_ALL
) {
450 return asq_wait_all(handle
);
452 return asq_wait_none(handle
);
456 static int asq_init(struct ldb_module
*module
)
458 struct ldb_request
*req
;
461 req
= talloc_zero(module
, struct ldb_request
);
463 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "asq: Out of memory!\n");
464 return LDB_ERR_OPERATIONS_ERROR
;
467 req
->operation
= LDB_REQ_REGISTER_CONTROL
;
468 req
->op
.reg_control
.oid
= LDB_CONTROL_ASQ_OID
;
470 ret
= ldb_request(module
->ldb
, req
);
471 if (ret
!= LDB_SUCCESS
) {
472 ldb_debug(module
->ldb
, LDB_DEBUG_WARNING
, "asq: Unable to register control with rootdse!\n");
475 return ldb_next_init(module
);
479 static const struct ldb_module_ops asq_ops
= {
481 .search
= asq_search
,
483 .init_context
= asq_init
486 int ldb_asq_init(void)
488 return ldb_register_module(&asq_ops
);