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 ac
= talloc_get_type(h
->private_data
, struct asq_context
);
248 /* check the search is well formed */
249 if (req
->op
.search
.scope
!= LDB_SCOPE_BASE
) {
250 ac
->asq_ret
= ASQ_CTRL_UNWILLING_TO_PERFORM
;
251 return asq_terminate(h
);
254 ac
->req_attrs
= req
->op
.search
.attrs
;
255 ac
->req_attribute
= talloc_strdup(ac
, asq_ctrl
->source_attribute
);
256 if (ac
->req_attribute
== NULL
)
257 return LDB_ERR_OPERATIONS_ERROR
;
259 /* get the object to retrieve the DNs to search */
260 ac
->base_req
= talloc_zero(req
, struct ldb_request
);
261 if (ac
->base_req
== NULL
)
262 return LDB_ERR_OPERATIONS_ERROR
;
263 ac
->base_req
->operation
= req
->operation
;
264 ac
->base_req
->op
.search
.base
= req
->op
.search
.base
;
265 ac
->base_req
->op
.search
.scope
= LDB_SCOPE_BASE
;
266 ac
->base_req
->op
.search
.tree
= req
->op
.search
.tree
;
267 base_attrs
= talloc_array(ac
->base_req
, char *, 2);
268 if (base_attrs
== NULL
)
269 return LDB_ERR_OPERATIONS_ERROR
;
270 base_attrs
[0] = talloc_strdup(base_attrs
, asq_ctrl
->source_attribute
);
271 if (base_attrs
[0] == NULL
)
272 return LDB_ERR_OPERATIONS_ERROR
;
273 base_attrs
[1] = NULL
;
274 ac
->base_req
->op
.search
.attrs
= (const char * const *)base_attrs
;
276 ac
->base_req
->context
= ac
;
277 ac
->base_req
->callback
= asq_base_callback
;
278 ldb_set_timeout_from_prev_req(module
->ldb
, req
, ac
->base_req
);
280 ac
->step
= ASQ_SEARCH_BASE
;
282 ret
= ldb_request(module
->ldb
, ac
->base_req
);
284 if (ret
!= LDB_SUCCESS
) {
291 static int asq_requests(struct ldb_handle
*handle
) {
292 struct asq_context
*ac
;
293 struct ldb_message_element
*el
;
296 ac
= talloc_get_type(handle
->private_data
, struct asq_context
);
298 /* look up the DNs */
299 if (ac
->base_res
== NULL
) {
300 return LDB_ERR_NO_SUCH_OBJECT
;
302 el
= ldb_msg_find_element(ac
->base_res
->message
, ac
->req_attribute
);
303 /* no values found */
305 ac
->asq_ret
= ASQ_CTRL_SUCCESS
;
306 return asq_terminate(handle
);
309 /* build up the requests call chain */
310 ac
->num_reqs
= el
->num_values
;
312 ac
->reqs
= talloc_array(ac
, struct ldb_request
*, ac
->num_reqs
);
313 if (ac
->reqs
== NULL
) {
314 return LDB_ERR_OPERATIONS_ERROR
;
317 for (i
= 0; i
< el
->num_values
; i
++) {
319 ac
->reqs
[i
] = talloc_zero(ac
->reqs
, struct ldb_request
);
320 if (ac
->reqs
[i
] == NULL
)
321 return LDB_ERR_OPERATIONS_ERROR
;
322 ac
->reqs
[i
]->operation
= LDB_SEARCH
;
323 ac
->reqs
[i
]->op
.search
.base
= ldb_dn_explode(ac
->reqs
[i
], (const char *)el
->values
[i
].data
);
324 if (ac
->reqs
[i
]->op
.search
.base
== NULL
) {
325 ac
->asq_ret
= ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX
;
326 return asq_terminate(handle
);
328 ac
->reqs
[i
]->op
.search
.scope
= LDB_SCOPE_BASE
;
329 ac
->reqs
[i
]->op
.search
.tree
= ac
->base_req
->op
.search
.tree
;
330 ac
->reqs
[i
]->op
.search
.attrs
= ac
->req_attrs
;
332 ac
->reqs
[i
]->context
= ac
;
333 ac
->reqs
[i
]->callback
= asq_reqs_callback
;
334 ldb_set_timeout_from_prev_req(ac
->module
->ldb
, ac
->base_req
, ac
->reqs
[i
]);
337 ac
->step
= ASQ_SEARCH_MULTI
;
342 static int asq_wait_none(struct ldb_handle
*handle
)
344 struct asq_context
*ac
;
347 if (!handle
|| !handle
->private_data
) {
348 return LDB_ERR_OPERATIONS_ERROR
;
351 if (handle
->state
== LDB_ASYNC_DONE
) {
352 return handle
->status
;
355 handle
->state
= LDB_ASYNC_PENDING
;
356 handle
->status
= LDB_SUCCESS
;
358 ac
= talloc_get_type(handle
->private_data
, struct asq_context
);
362 case ASQ_SEARCH_BASE
:
363 ret
= ldb_wait(ac
->base_req
->handle
, LDB_WAIT_NONE
);
365 if (ret
!= LDB_SUCCESS
) {
366 handle
->status
= ret
;
370 if (ac
->base_req
->handle
->status
!= LDB_SUCCESS
) {
371 handle
->status
= ac
->base_req
->handle
->status
;
374 if (ac
->base_req
->handle
->state
!= LDB_ASYNC_DONE
) {
378 ret
= asq_requests(handle
);
380 /* no break nor return,
381 * the set of requests is performed in ASQ_SEARCH_MULTI
384 case ASQ_SEARCH_MULTI
:
386 if (ac
->reqs
[ac
->cur_req
]->handle
== NULL
) {
387 ret
= ldb_request(ac
->module
->ldb
, ac
->reqs
[ac
->cur_req
]);
388 if (ret
!= LDB_SUCCESS
) {
393 ret
= ldb_wait(ac
->reqs
[ac
->cur_req
]->handle
, LDB_WAIT_NONE
);
395 if (ret
!= LDB_SUCCESS
) {
396 handle
->status
= ret
;
399 if (ac
->reqs
[ac
->cur_req
]->handle
->status
!= LDB_SUCCESS
) {
400 handle
->status
= ac
->reqs
[ac
->cur_req
]->handle
->status
;
403 if (ac
->reqs
[ac
->cur_req
]->handle
->state
== LDB_ASYNC_DONE
) {
407 if (ac
->cur_req
< ac
->num_reqs
) {
411 return asq_terminate(handle
);
414 ret
= LDB_ERR_OPERATIONS_ERROR
;
421 handle
->state
= LDB_ASYNC_DONE
;
425 static int asq_wait_all(struct ldb_handle
*handle
)
429 while (handle
->state
!= LDB_ASYNC_DONE
) {
430 ret
= asq_wait_none(handle
);
431 if (ret
!= LDB_SUCCESS
) {
436 return handle
->status
;
439 static int asq_wait(struct ldb_handle
*handle
, enum ldb_wait_type type
)
441 if (type
== LDB_WAIT_ALL
) {
442 return asq_wait_all(handle
);
444 return asq_wait_none(handle
);
448 static int asq_init(struct ldb_module
*module
)
450 struct ldb_request
*req
;
453 req
= talloc_zero(module
, struct ldb_request
);
455 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "asq: Out of memory!\n");
456 return LDB_ERR_OPERATIONS_ERROR
;
459 req
->operation
= LDB_REQ_REGISTER_CONTROL
;
460 req
->op
.reg_control
.oid
= LDB_CONTROL_ASQ_OID
;
462 ret
= ldb_request(module
->ldb
, req
);
463 if (ret
!= LDB_SUCCESS
) {
464 ldb_debug(module
->ldb
, LDB_DEBUG_WARNING
, "asq: Unable to register control with rootdse!\n");
467 return ldb_next_init(module
);
471 static const struct ldb_module_ops asq_ops
= {
473 .search
= asq_search
,
475 .init_context
= asq_init
478 int ldb_asq_init(void)
480 return ldb_register_module(&asq_ops
);