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 if (ret
!= LDB_SUCCESS
) {
249 static int asq_build_multiple_requests(struct asq_context
*ac
, bool *terminated
)
251 struct ldb_context
*ldb
;
252 struct ldb_control
**saved_controls
;
253 struct ldb_control
*control
;
255 struct ldb_message_element
*el
;
259 if (ac
->base_res
== NULL
) {
260 return LDB_ERR_NO_SUCH_OBJECT
;
263 ldb
= ldb_module_get_ctx(ac
->module
);
265 el
= ldb_msg_find_element(ac
->base_res
->message
, ac
->req_attribute
);
266 /* no values found */
268 ac
->asq_ret
= ASQ_CTRL_SUCCESS
;
270 return asq_search_terminate(ac
);
273 ac
->num_reqs
= el
->num_values
;
275 ac
->reqs
= talloc_array(ac
, struct ldb_request
*, ac
->num_reqs
);
276 if (ac
->reqs
== NULL
) {
277 return LDB_ERR_OPERATIONS_ERROR
;
280 for (i
= 0; i
< el
->num_values
; i
++) {
282 dn
= ldb_dn_new(ac
, ldb
,
283 (const char *)el
->values
[i
].data
);
284 if ( ! ldb_dn_validate(dn
)) {
285 ac
->asq_ret
= ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX
;
287 return asq_search_terminate(ac
);
290 ret
= ldb_build_search_req_ex(&ac
->reqs
[i
],
293 ac
->req
->op
.search
.tree
,
296 ac
, asq_reqs_callback
,
298 if (ret
!= LDB_SUCCESS
) {
302 /* remove the ASQ control itself */
303 control
= ldb_request_get_control(ac
->req
, LDB_CONTROL_ASQ_OID
);
304 if (!ldb_save_controls(control
, ac
->reqs
[i
], &saved_controls
)) {
305 return LDB_ERR_OPERATIONS_ERROR
;
312 static int asq_search_continue(struct asq_context
*ac
)
314 struct ldb_context
*ldb
;
315 bool terminated
= false;
318 ldb
= ldb_module_get_ctx(ac
->module
);
321 case ASQ_SEARCH_BASE
:
323 /* build up the requests call chain */
324 ret
= asq_build_multiple_requests(ac
, &terminated
);
325 if (ret
!= LDB_SUCCESS
|| terminated
) {
329 ac
->step
= ASQ_SEARCH_MULTI
;
331 return ldb_request(ldb
, ac
->reqs
[ac
->cur_req
]);
333 case ASQ_SEARCH_MULTI
:
337 if (ac
->cur_req
== ac
->num_reqs
) {
339 return asq_search_terminate(ac
);
342 return ldb_request(ldb
, ac
->reqs
[ac
->cur_req
]);
345 return LDB_ERR_OPERATIONS_ERROR
;
348 static int asq_search(struct ldb_module
*module
, struct ldb_request
*req
)
350 struct ldb_context
*ldb
;
351 struct ldb_request
*base_req
;
352 struct ldb_control
*control
;
353 struct asq_context
*ac
;
356 ldb
= ldb_module_get_ctx(module
);
358 /* check if there's an ASQ control */
359 control
= ldb_request_get_control(req
, LDB_CONTROL_ASQ_OID
);
360 if (control
== NULL
) {
361 /* not found go on */
362 return ldb_next_request(module
, req
);
365 ac
= asq_context_init(module
, req
);
367 return LDB_ERR_OPERATIONS_ERROR
;
370 /* check the search is well formed */
371 if (req
->op
.search
.scope
!= LDB_SCOPE_BASE
) {
372 ac
->asq_ret
= ASQ_CTRL_UNWILLING_TO_PERFORM
;
373 return asq_search_terminate(ac
);
376 ac
->asq_ctrl
= talloc_get_type(control
->data
, struct ldb_asq_control
);
378 return LDB_ERR_PROTOCOL_ERROR
;
381 ret
= asq_build_first_request(ac
, &base_req
);
382 if (ret
!= LDB_SUCCESS
) {
386 ac
->step
= ASQ_SEARCH_BASE
;
388 return ldb_request(ldb
, base_req
);
391 static int asq_init(struct ldb_module
*module
)
393 struct ldb_context
*ldb
;
396 ldb
= ldb_module_get_ctx(module
);
398 ret
= ldb_mod_register_control(module
, LDB_CONTROL_ASQ_OID
);
399 if (ret
!= LDB_SUCCESS
) {
400 ldb_debug(ldb
, LDB_DEBUG_WARNING
, "asq: Unable to register control with rootdse!");
403 return ldb_next_init(module
);
406 static const struct ldb_module_ops ldb_asq_module_ops
= {
408 .search
= asq_search
,
409 .init_context
= asq_init
412 int ldb_asq_init(const char *version
)
414 LDB_MODULE_CHECK_VERSION(version
);
415 return ldb_register_module(&ldb_asq_module_ops
);