LDB:asq module - change counters to "unsigned" where appropriate
[Samba/cd1.git] / source4 / lib / ldb / modules / asq.c
blob6d1e88b67b8f1a4d22c4c7a2d723879396dab82c
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 objects pointed by
30 * 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 unsigned int num_reqs;
59 unsigned 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 unsigned 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 ret;
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 unsigned int i;
254 int ret;
256 if (ac->base_res == NULL) {
257 return LDB_ERR_NO_SUCH_OBJECT;
260 ldb = ldb_module_get_ctx(ac->module);
262 el = ldb_msg_find_element(ac->base_res->message, ac->req_attribute);
263 /* no values found */
264 if (el == NULL) {
265 ac->asq_ret = ASQ_CTRL_SUCCESS;
266 *terminated = true;
267 return asq_search_terminate(ac);
270 ac->num_reqs = el->num_values;
271 ac->cur_req = 0;
272 ac->reqs = talloc_array(ac, struct ldb_request *, ac->num_reqs);
273 if (ac->reqs == NULL) {
274 return LDB_ERR_OPERATIONS_ERROR;
277 for (i = 0; i < el->num_values; i++) {
279 dn = ldb_dn_new(ac, ldb,
280 (const char *)el->values[i].data);
281 if ( ! ldb_dn_validate(dn)) {
282 ac->asq_ret = ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX;
283 *terminated = true;
284 return asq_search_terminate(ac);
287 ret = ldb_build_search_req_ex(&ac->reqs[i],
288 ldb, ac,
289 dn, LDB_SCOPE_BASE,
290 ac->req->op.search.tree,
291 ac->req_attrs,
292 ac->req->controls,
293 ac, asq_reqs_callback,
294 ac->req);
295 if (ret != LDB_SUCCESS) {
296 return ret;
299 /* remove the ASQ control itself */
300 control = ldb_request_get_control(ac->req, LDB_CONTROL_ASQ_OID);
301 if (!save_controls(control, ac->reqs[i], &saved_controls)) {
302 return LDB_ERR_OPERATIONS_ERROR;
306 return LDB_SUCCESS;
309 static int asq_search_continue(struct asq_context *ac)
311 struct ldb_context *ldb;
312 bool terminated = false;
313 int ret;
315 ldb = ldb_module_get_ctx(ac->module);
317 switch (ac->step) {
318 case ASQ_SEARCH_BASE:
320 /* build up the requests call chain */
321 ret = asq_build_multiple_requests(ac, &terminated);
322 if (ret != LDB_SUCCESS || terminated) {
323 return ret;
326 ac->step = ASQ_SEARCH_MULTI;
328 return ldb_request(ldb, ac->reqs[ac->cur_req]);
330 case ASQ_SEARCH_MULTI:
332 ac->cur_req++;
334 if (ac->cur_req == ac->num_reqs) {
335 /* done */
336 return asq_search_terminate(ac);
339 return ldb_request(ldb, ac->reqs[ac->cur_req]);
342 return LDB_ERR_OPERATIONS_ERROR;
345 static int asq_search(struct ldb_module *module, struct ldb_request *req)
347 struct ldb_context *ldb;
348 struct ldb_request *base_req;
349 struct ldb_control *control;
350 struct asq_context *ac;
351 int ret;
353 ldb = ldb_module_get_ctx(module);
355 /* check if there's an ASQ control */
356 control = ldb_request_get_control(req, LDB_CONTROL_ASQ_OID);
357 if (control == NULL) {
358 /* not found go on */
359 return ldb_next_request(module, req);
362 ac = asq_context_init(module, req);
363 if (!ac) {
364 return LDB_ERR_OPERATIONS_ERROR;
367 /* check the search is well formed */
368 if (req->op.search.scope != LDB_SCOPE_BASE) {
369 ac->asq_ret = ASQ_CTRL_UNWILLING_TO_PERFORM;
370 return asq_search_terminate(ac);
373 ac->asq_ctrl = talloc_get_type(control->data, struct ldb_asq_control);
374 if (!ac->asq_ctrl) {
375 return LDB_ERR_PROTOCOL_ERROR;
378 ret = asq_build_first_request(ac, &base_req);
379 if (ret != LDB_SUCCESS) {
380 return ret;
383 ac->step = ASQ_SEARCH_BASE;
385 return ldb_request(ldb, base_req);
388 static int asq_init(struct ldb_module *module)
390 struct ldb_context *ldb;
391 int ret;
393 ldb = ldb_module_get_ctx(module);
395 ret = ldb_mod_register_control(module, LDB_CONTROL_ASQ_OID);
396 if (ret != LDB_SUCCESS) {
397 ldb_debug(ldb, LDB_DEBUG_WARNING, "asq: Unable to register control with rootdse!");
400 return ldb_next_init(module);
403 const struct ldb_module_ops ldb_asq_module_ops = {
404 .name = "asq",
405 .search = asq_search,
406 .init_context = asq_init