remove all '\n' from ldb_debug
[ira/wip.git] / source4 / lib / ldb / modules / asq.c
1 /* 
2    ldb database library
3
4    Copyright (C) Simo Sorce  2005-2008
5
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
9    
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.
14
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.
19
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/>.
22 */
23
24 /*
25  *  Name: ldb
26  *
27  *  Component: ldb attribute scoped query control module
28  *
29  *  Description: this module searches all the the objects pointed
30  *               by the DNs contained in the references attribute
31  *
32  *  Author: Simo Sorce
33  */
34
35 #include "ldb_module.h"
36
37 struct asq_context {
38
39         enum {ASQ_SEARCH_BASE, ASQ_SEARCH_MULTI} step;
40
41         struct ldb_module *module;
42         struct ldb_request *req;
43
44         struct ldb_asq_control *asq_ctrl;
45
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;
54
55         struct ldb_reply *base_res;
56
57         struct ldb_request **reqs;
58         int num_reqs;
59         int cur_req;
60
61         struct ldb_control **controls;
62 };
63
64 static struct asq_context *asq_context_init(struct ldb_module *module, struct ldb_request *req)
65 {
66         struct ldb_context *ldb;
67         struct asq_context *ac;
68
69         ldb = ldb_module_get_ctx(module);
70
71         ac = talloc_zero(req, struct asq_context);
72         if (ac == NULL) {
73                 ldb_oom(ldb);
74                 return NULL;
75         }
76
77         ac->module = module;
78         ac->req = req;
79
80         return ac;
81 }
82
83 static int asq_search_continue(struct asq_context *ac);
84
85 static int asq_search_terminate(struct asq_context *ac)
86 {
87         struct ldb_asq_control *asq;
88         int i;
89
90         if (ac->controls) {
91                 for (i = 0; ac->controls[i]; i++) /* count em */ ;
92         } else {
93                 i = 0;
94         }
95
96         ac->controls = talloc_realloc(ac, ac->controls, struct ldb_control *, i + 2);
97
98         if (ac->controls == NULL) {
99                 return LDB_ERR_OPERATIONS_ERROR;
100         }
101
102         ac->controls[i] = talloc(ac->controls, struct ldb_control);
103         if (ac->controls[i] == NULL) {
104                 return LDB_ERR_OPERATIONS_ERROR;
105         }
106
107         ac->controls[i]->oid = LDB_CONTROL_ASQ_OID;
108         ac->controls[i]->critical = 0;
109
110         asq = talloc_zero(ac->controls[i], struct ldb_asq_control);
111         if (asq == NULL)
112                 return LDB_ERR_OPERATIONS_ERROR;
113
114         asq->result = ac->asq_ret;
115
116         ac->controls[i]->data = asq;
117
118         ac->controls[i + 1] = NULL;
119
120         return ldb_module_done(ac->req, ac->controls, NULL, LDB_SUCCESS);
121 }
122
123 static int asq_base_callback(struct ldb_request *req, struct ldb_reply *ares)
124 {
125         struct asq_context *ac;
126         int ret;
127
128         ac = talloc_get_type(req->context, struct asq_context);
129
130         if (!ares) {
131                 return ldb_module_done(ac->req, NULL, NULL,
132                                         LDB_ERR_OPERATIONS_ERROR);
133         }
134         if (ares->error != LDB_SUCCESS) {
135                 return ldb_module_done(ac->req, ares->controls,
136                                         ares->response, ares->error);
137         }
138
139         switch (ares->type) {
140         case LDB_REPLY_ENTRY:
141                 ac->base_res = talloc_move(ac, &ares);
142                 break;
143
144         case LDB_REPLY_REFERRAL:
145                 /* ignore referrals */
146                 talloc_free(ares);
147                 break;
148
149         case LDB_REPLY_DONE:
150
151                 talloc_free(ares);
152
153                 /* next step */
154                 ret = asq_search_continue(ac);
155                 if (ret != LDB_SUCCESS) {
156                         return ldb_module_done(ac->req, NULL, NULL, ret);
157                 }
158                 break;
159
160         }
161         return LDB_SUCCESS;
162 }
163
164 static int asq_reqs_callback(struct ldb_request *req, struct ldb_reply *ares)
165 {
166         struct asq_context *ac;
167         int ret;
168
169         ac = talloc_get_type(req->context, struct asq_context);
170
171         if (!ares) {
172                 return ldb_module_done(ac->req, NULL, NULL,
173                                         LDB_ERR_OPERATIONS_ERROR);
174         }
175         if (ares->error != LDB_SUCCESS) {
176                 return ldb_module_done(ac->req, ares->controls,
177                                         ares->response, ares->error);
178         }
179
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);
187                 }
188                 talloc_free(ares);
189                 break;
190
191         case LDB_REPLY_REFERRAL:
192                 /* ignore referrals */
193                 talloc_free(ares);
194                 break;
195
196         case LDB_REPLY_DONE:
197
198                 talloc_free(ares);
199
200                 ret = asq_search_continue(ac);
201                 if (ret != LDB_SUCCESS) {
202                         return ldb_module_done(ac->req, NULL, NULL, ret);
203                 }
204                 break;
205         }
206
207         return LDB_SUCCESS;
208 }
209
210 static int asq_build_first_request(struct asq_context *ac, struct ldb_request **base_req)
211 {
212         struct ldb_context *ldb;
213         const char **base_attrs;
214         int ret;
215
216         ldb = ldb_module_get_ctx(ac->module);
217
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;
222
223         base_attrs = talloc_array(ac, const char *, 2);
224         if (base_attrs == NULL) return LDB_ERR_OPERATIONS_ERROR;
225
226         base_attrs[0] = talloc_strdup(base_attrs, ac->asq_ctrl->source_attribute);
227         if (base_attrs[0] == NULL) return LDB_ERR_OPERATIONS_ERROR;
228
229         base_attrs[1] = NULL;
230
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;
241         }
242
243         return LDB_SUCCESS;
244 }
245
246 static int asq_build_multiple_requests(struct asq_context *ac, bool *terminated)
247 {
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;
254
255         if (ac->base_res == NULL) {
256                 return LDB_ERR_NO_SUCH_OBJECT;
257         }
258
259         ldb = ldb_module_get_ctx(ac->module);
260
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);
267         }
268
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;
274         }
275
276         for (i = 0; i < el->num_values; i++) {
277
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);
284                 }
285
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;
296                 }
297
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;
302                 }
303         }
304
305         return LDB_SUCCESS;
306 }
307
308 static int asq_search_continue(struct asq_context *ac)
309 {
310         struct ldb_context *ldb;
311         bool terminated = false;
312         int ret;
313
314         ldb = ldb_module_get_ctx(ac->module);
315
316         switch (ac->step) {
317         case ASQ_SEARCH_BASE:
318
319                 /* build up the requests call chain */
320                 ret = asq_build_multiple_requests(ac, &terminated);
321                 if (ret != LDB_SUCCESS || terminated) {
322                         return ret;
323                 }
324
325                 ac->step = ASQ_SEARCH_MULTI;
326
327                 return ldb_request(ldb, ac->reqs[ac->cur_req]);
328
329         case ASQ_SEARCH_MULTI:
330
331                 ac->cur_req++;
332
333                 if (ac->cur_req == ac->num_reqs) {
334                         /* done */
335                         return asq_search_terminate(ac);
336                 }
337
338                 return ldb_request(ldb, ac->reqs[ac->cur_req]);
339         }
340
341         return LDB_ERR_OPERATIONS_ERROR;
342 }
343
344 static int asq_search(struct ldb_module *module, struct ldb_request *req)
345 {
346         struct ldb_context *ldb;
347         struct ldb_request *base_req;
348         struct ldb_control *control;
349         struct asq_context *ac;
350         int ret;
351
352         ldb = ldb_module_get_ctx(module);
353
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);
359         }
360
361         ac = asq_context_init(module, req);
362         if (!ac) {
363                 return LDB_ERR_OPERATIONS_ERROR;
364         }
365
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);
370         }
371
372         ac->asq_ctrl = talloc_get_type(control->data, struct ldb_asq_control);
373         if (!ac->asq_ctrl) {
374                 return LDB_ERR_PROTOCOL_ERROR;
375         }
376
377         ret = asq_build_first_request(ac, &base_req);
378         if (ret != LDB_SUCCESS) {
379                 return ret;
380         }
381
382         ac->step = ASQ_SEARCH_BASE;
383
384         return ldb_request(ldb, base_req);
385 }
386
387 static int asq_init(struct ldb_module *module)
388 {
389         struct ldb_context *ldb;
390         int ret;
391
392         ldb = ldb_module_get_ctx(module);
393
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!");
397         }
398
399         return ldb_next_init(module);
400 }
401
402 const struct ldb_module_ops ldb_asq_module_ops = {
403         .name              = "asq",
404         .search            = asq_search,
405         .init_context      = asq_init
406 };