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
35 #include "ldb_module.h"
39 enum {ASQ_SEARCH_BASE
, ASQ_SEARCH_MULTI
} step
;
41 struct ldb_module
*module
;
42 struct ldb_request
*req
;
44 struct ldb_asq_control
*asq_ctrl
;
46 const char * const *req_attrs
;
50 ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX
= 21,
51 ASQ_CTRL_UNWILLING_TO_PERFORM
= 53,
52 ASQ_CTRL_AFFECTS_MULTIPLE_DSA
= 71
55 struct ldb_reply
*base_res
;
57 struct ldb_request
**reqs
;
61 struct ldb_control
**controls
;
64 static struct asq_context
*asq_context_init(struct ldb_module
*module
, struct ldb_request
*req
)
66 struct ldb_context
*ldb
;
67 struct asq_context
*ac
;
69 ldb
= ldb_module_get_ctx(module
);
71 ac
= talloc_zero(req
, struct asq_context
);
83 static int asq_search_continue(struct asq_context
*ac
);
85 static int asq_search_terminate(struct asq_context
*ac
)
87 struct ldb_asq_control
*asq
;
91 for (i
= 0; ac
->controls
[i
]; i
++) /* count em */ ;
96 ac
->controls
= talloc_realloc(ac
, ac
->controls
, struct ldb_control
*, i
+ 2);
98 if (ac
->controls
== NULL
) {
99 return LDB_ERR_OPERATIONS_ERROR
;
102 ac
->controls
[i
] = talloc(ac
->controls
, struct ldb_control
);
103 if (ac
->controls
[i
] == NULL
) {
104 return LDB_ERR_OPERATIONS_ERROR
;
107 ac
->controls
[i
]->oid
= LDB_CONTROL_ASQ_OID
;
108 ac
->controls
[i
]->critical
= 0;
110 asq
= talloc_zero(ac
->controls
[i
], struct ldb_asq_control
);
112 return LDB_ERR_OPERATIONS_ERROR
;
114 asq
->result
= ac
->asq_ret
;
116 ac
->controls
[i
]->data
= asq
;
118 ac
->controls
[i
+ 1] = NULL
;
120 return ldb_module_done(ac
->req
, ac
->controls
, NULL
, LDB_SUCCESS
);
123 static int asq_base_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
125 struct asq_context
*ac
;
128 ac
= talloc_get_type(req
->context
, struct asq_context
);
131 return ldb_module_done(ac
->req
, NULL
, NULL
,
132 LDB_ERR_OPERATIONS_ERROR
);
134 if (ares
->error
!= LDB_SUCCESS
) {
135 return ldb_module_done(ac
->req
, ares
->controls
,
136 ares
->response
, ares
->error
);
139 switch (ares
->type
) {
140 case LDB_REPLY_ENTRY
:
141 ac
->base_res
= talloc_move(ac
, &ares
);
144 case LDB_REPLY_REFERRAL
:
145 /* ignore referrals */
154 ret
= asq_search_continue(ac
);
155 if (ret
!= LDB_SUCCESS
) {
156 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
164 static int asq_reqs_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
166 struct asq_context
*ac
;
169 ac
= talloc_get_type(req
->context
, struct asq_context
);
172 return ldb_module_done(ac
->req
, NULL
, NULL
,
173 LDB_ERR_OPERATIONS_ERROR
);
175 if (ares
->error
!= LDB_SUCCESS
) {
176 return ldb_module_done(ac
->req
, ares
->controls
,
177 ares
->response
, ares
->error
);
180 switch (ares
->type
) {
181 case LDB_REPLY_ENTRY
:
182 /* pass the message up to the original callback as we
183 * do not have to elaborate on it any further */
184 ret
= ldb_module_send_entry(ac
->req
, ares
->message
, ares
->controls
);
185 if (ret
!= LDB_SUCCESS
) {
186 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
191 case LDB_REPLY_REFERRAL
:
192 /* ignore referrals */
200 ret
= asq_search_continue(ac
);
201 if (ret
!= LDB_SUCCESS
) {
202 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
210 static int asq_build_first_request(struct asq_context
*ac
, struct ldb_request
**base_req
)
212 struct ldb_context
*ldb
;
213 const char **base_attrs
;
216 ldb
= ldb_module_get_ctx(ac
->module
);
218 ac
->req_attrs
= ac
->req
->op
.search
.attrs
;
219 ac
->req_attribute
= talloc_strdup(ac
, ac
->asq_ctrl
->source_attribute
);
220 if (ac
->req_attribute
== NULL
)
221 return LDB_ERR_OPERATIONS_ERROR
;
223 base_attrs
= talloc_array(ac
, const 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
;
231 ret
= ldb_build_search_req(base_req
, ldb
, ac
,
232 ac
->req
->op
.search
.base
,
235 (const char * const *)base_attrs
,
237 ac
, asq_base_callback
,
239 if (ret
!= LDB_SUCCESS
) {
240 return LDB_ERR_OPERATIONS_ERROR
;
246 static int asq_build_multiple_requests(struct asq_context
*ac
, bool *terminated
)
248 struct ldb_context
*ldb
;
249 struct ldb_control
**saved_controls
;
250 struct ldb_control
*control
;
252 struct ldb_message_element
*el
;
255 if (ac
->base_res
== NULL
) {
256 return LDB_ERR_NO_SUCH_OBJECT
;
259 ldb
= ldb_module_get_ctx(ac
->module
);
261 el
= ldb_msg_find_element(ac
->base_res
->message
, ac
->req_attribute
);
262 /* no values found */
264 ac
->asq_ret
= ASQ_CTRL_SUCCESS
;
266 return asq_search_terminate(ac
);
269 ac
->num_reqs
= el
->num_values
;
271 ac
->reqs
= talloc_array(ac
, struct ldb_request
*, ac
->num_reqs
);
272 if (ac
->reqs
== NULL
) {
273 return LDB_ERR_OPERATIONS_ERROR
;
276 for (i
= 0; i
< el
->num_values
; i
++) {
278 dn
= ldb_dn_new(ac
, ldb
,
279 (const char *)el
->values
[i
].data
);
280 if ( ! ldb_dn_validate(dn
)) {
281 ac
->asq_ret
= ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX
;
283 return asq_search_terminate(ac
);
286 ret
= ldb_build_search_req_ex(&ac
->reqs
[i
],
289 ac
->req
->op
.search
.tree
,
292 ac
, asq_reqs_callback
,
294 if (ret
!= LDB_SUCCESS
) {
295 return LDB_ERR_OPERATIONS_ERROR
;
298 /* remove the ASQ control itself */
299 control
= ldb_request_get_control(ac
->req
, LDB_CONTROL_ASQ_OID
);
300 if (!save_controls(control
, ac
->reqs
[i
], &saved_controls
)) {
301 return LDB_ERR_OPERATIONS_ERROR
;
308 static int asq_search_continue(struct asq_context
*ac
)
310 struct ldb_context
*ldb
;
311 bool terminated
= false;
314 ldb
= ldb_module_get_ctx(ac
->module
);
317 case ASQ_SEARCH_BASE
:
319 /* build up the requests call chain */
320 ret
= asq_build_multiple_requests(ac
, &terminated
);
321 if (ret
!= LDB_SUCCESS
|| terminated
) {
325 ac
->step
= ASQ_SEARCH_MULTI
;
327 return ldb_request(ldb
, ac
->reqs
[ac
->cur_req
]);
329 case ASQ_SEARCH_MULTI
:
333 if (ac
->cur_req
== ac
->num_reqs
) {
335 return asq_search_terminate(ac
);
338 return ldb_request(ldb
, ac
->reqs
[ac
->cur_req
]);
341 return LDB_ERR_OPERATIONS_ERROR
;
344 static int asq_search(struct ldb_module
*module
, struct ldb_request
*req
)
346 struct ldb_context
*ldb
;
347 struct ldb_request
*base_req
;
348 struct ldb_control
*control
;
349 struct asq_context
*ac
;
352 ldb
= ldb_module_get_ctx(module
);
354 /* check if there's an ASQ control */
355 control
= ldb_request_get_control(req
, LDB_CONTROL_ASQ_OID
);
356 if (control
== NULL
) {
357 /* not found go on */
358 return ldb_next_request(module
, req
);
361 ac
= asq_context_init(module
, req
);
363 return LDB_ERR_OPERATIONS_ERROR
;
366 /* check the search is well formed */
367 if (req
->op
.search
.scope
!= LDB_SCOPE_BASE
) {
368 ac
->asq_ret
= ASQ_CTRL_UNWILLING_TO_PERFORM
;
369 return asq_search_terminate(ac
);
372 ac
->asq_ctrl
= talloc_get_type(control
->data
, struct ldb_asq_control
);
374 return LDB_ERR_PROTOCOL_ERROR
;
377 ret
= asq_build_first_request(ac
, &base_req
);
378 if (ret
!= LDB_SUCCESS
) {
382 ac
->step
= ASQ_SEARCH_BASE
;
384 return ldb_request(ldb
, base_req
);
387 static int asq_init(struct ldb_module
*module
)
389 struct ldb_context
*ldb
;
392 ldb
= ldb_module_get_ctx(module
);
394 ret
= ldb_mod_register_control(module
, LDB_CONTROL_ASQ_OID
);
395 if (ret
!= LDB_SUCCESS
) {
396 ldb_debug(ldb
, LDB_DEBUG_WARNING
, "asq: Unable to register control with rootdse!");
399 return ldb_next_init(module
);
402 const struct ldb_module_ops ldb_asq_module_ops
= {
404 .search
= asq_search
,
405 .init_context
= asq_init