s4:ldb:modules: Correct typos.
[Samba/aatanasov.git] / source4 / lib / ldb / modules / asq.c
blobdd5afd868cd3fa144b9908f31bae4065a9b46603
1 /*
2 ldb database library
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
8 ** under the LGPL
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/>.
25 * Name: ldb
27 * Component: ldb attribute scoped query control module
29 * Description: this module searches all the the objects pointed
30 * by the DNs contained in the references attribute
32 * Author: Simo Sorce
35 #include "ldb_module.h"
37 struct asq_context {
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;
47 char *req_attribute;
48 enum {
49 ASQ_CTRL_SUCCESS = 0,
50 ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX = 21,
51 ASQ_CTRL_UNWILLING_TO_PERFORM = 53,
52 ASQ_CTRL_AFFECTS_MULTIPLE_DSA = 71
53 } asq_ret;
55 struct ldb_reply *base_res;
57 struct ldb_request **reqs;
58 int num_reqs;
59 int cur_req;
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);
72 if (ac == NULL) {
73 ldb_oom(ldb);
74 return NULL;
77 ac->module = module;
78 ac->req = req;
80 return ac;
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;
88 int i;
90 if (ac->controls) {
91 for (i = 0; ac->controls[i]; i++) /* count em */ ;
92 } else {
93 i = 0;
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);
111 if (asq == NULL)
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;
126 int ret;
128 ac = talloc_get_type(req->context, struct asq_context);
130 if (!ares) {
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);
142 break;
144 case LDB_REPLY_REFERRAL:
145 /* ignore referrals */
146 talloc_free(ares);
147 break;
149 case LDB_REPLY_DONE:
151 talloc_free(ares);
153 /* next step */
154 ret = asq_search_continue(ac);
155 if (ret != LDB_SUCCESS) {
156 return ldb_module_done(ac->req, NULL, NULL, ret);
158 break;
161 return LDB_SUCCESS;
164 static int asq_reqs_callback(struct ldb_request *req, struct ldb_reply *ares)
166 struct asq_context *ac;
167 int ret;
169 ac = talloc_get_type(req->context, struct asq_context);
171 if (!ares) {
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);
188 talloc_free(ares);
189 break;
191 case LDB_REPLY_REFERRAL:
192 /* ignore referrals */
193 talloc_free(ares);
194 break;
196 case LDB_REPLY_DONE:
198 talloc_free(ares);
200 ret = asq_search_continue(ac);
201 if (ret != LDB_SUCCESS) {
202 return ldb_module_done(ac->req, NULL, NULL, ret);
204 break;
207 return LDB_SUCCESS;
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;
214 int ret;
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,
233 LDB_SCOPE_BASE,
234 NULL,
235 (const char * const *)base_attrs,
236 NULL,
237 ac, asq_base_callback,
238 ac->req);
239 if (ret != LDB_SUCCESS) {
240 return LDB_ERR_OPERATIONS_ERROR;
243 return LDB_SUCCESS;
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;
251 struct ldb_dn *dn;
252 struct ldb_message_element *el;
253 int ret, i;
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 */
263 if (el == NULL) {
264 ac->asq_ret = ASQ_CTRL_SUCCESS;
265 *terminated = true;
266 return asq_search_terminate(ac);
269 ac->num_reqs = el->num_values;
270 ac->cur_req = 0;
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;
282 *terminated = true;
283 return asq_search_terminate(ac);
286 ret = ldb_build_search_req_ex(&ac->reqs[i],
287 ldb, ac,
288 dn, LDB_SCOPE_BASE,
289 ac->req->op.search.tree,
290 ac->req_attrs,
291 ac->req->controls,
292 ac, asq_reqs_callback,
293 ac->req);
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;
305 return LDB_SUCCESS;
308 static int asq_search_continue(struct asq_context *ac)
310 struct ldb_context *ldb;
311 bool terminated = false;
312 int ret;
314 ldb = ldb_module_get_ctx(ac->module);
316 switch (ac->step) {
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) {
322 return ret;
325 ac->step = ASQ_SEARCH_MULTI;
327 return ldb_request(ldb, ac->reqs[ac->cur_req]);
329 case ASQ_SEARCH_MULTI:
331 ac->cur_req++;
333 if (ac->cur_req == ac->num_reqs) {
334 /* done */
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;
350 int ret;
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);
362 if (!ac) {
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);
373 if (!ac->asq_ctrl) {
374 return LDB_ERR_PROTOCOL_ERROR;
377 ret = asq_build_first_request(ac, &base_req);
378 if (ret != LDB_SUCCESS) {
379 return ret;
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;
390 int ret;
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!\n");
399 return ldb_next_init(module);
402 const struct ldb_module_ops ldb_asq_module_ops = {
403 .name = "asq",
404 .search = asq_search,
405 .init_context = asq_init