Line data Source code
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 objects pointed by
30 : * the DNs contained in the references attribute
31 : *
32 : * Author: Simo Sorce
33 : */
34 :
35 : #include "replace.h"
36 : #include "system/filesys.h"
37 : #include "system/time.h"
38 : #include "ldb_module.h"
39 :
40 : struct asq_context {
41 :
42 : enum {ASQ_SEARCH_BASE, ASQ_SEARCH_MULTI} step;
43 :
44 : struct ldb_module *module;
45 : struct ldb_request *req;
46 :
47 : struct ldb_asq_control *asq_ctrl;
48 :
49 : const char * const *req_attrs;
50 : char *req_attribute;
51 : enum {
52 : ASQ_CTRL_SUCCESS = 0,
53 : ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX = 21,
54 : ASQ_CTRL_UNWILLING_TO_PERFORM = 53,
55 : ASQ_CTRL_AFFECTS_MULTIPLE_DSA = 71
56 : } asq_ret;
57 :
58 : struct ldb_reply *base_res;
59 :
60 : struct ldb_request **reqs;
61 : unsigned int num_reqs;
62 : unsigned int cur_req;
63 :
64 : struct ldb_control **controls;
65 : };
66 :
67 14 : static struct asq_context *asq_context_init(struct ldb_module *module, struct ldb_request *req)
68 : {
69 0 : struct ldb_context *ldb;
70 0 : struct asq_context *ac;
71 :
72 14 : ldb = ldb_module_get_ctx(module);
73 :
74 14 : ac = talloc_zero(req, struct asq_context);
75 14 : if (ac == NULL) {
76 0 : ldb_oom(ldb);
77 0 : return NULL;
78 : }
79 :
80 14 : ac->module = module;
81 14 : ac->req = req;
82 :
83 14 : return ac;
84 : }
85 :
86 : static int asq_search_continue(struct asq_context *ac);
87 :
88 14 : static int asq_search_terminate(struct asq_context *ac)
89 : {
90 0 : struct ldb_asq_control *asq;
91 0 : unsigned int i;
92 :
93 14 : if (ac->controls) {
94 0 : for (i = 0; ac->controls[i]; i++) /* count em */ ;
95 : } else {
96 14 : i = 0;
97 : }
98 :
99 14 : ac->controls = talloc_realloc(ac, ac->controls, struct ldb_control *, i + 2);
100 :
101 14 : if (ac->controls == NULL) {
102 0 : return LDB_ERR_OPERATIONS_ERROR;
103 : }
104 :
105 14 : ac->controls[i] = talloc(ac->controls, struct ldb_control);
106 14 : if (ac->controls[i] == NULL) {
107 0 : return LDB_ERR_OPERATIONS_ERROR;
108 : }
109 :
110 14 : ac->controls[i]->oid = LDB_CONTROL_ASQ_OID;
111 14 : ac->controls[i]->critical = 0;
112 :
113 14 : asq = talloc_zero(ac->controls[i], struct ldb_asq_control);
114 14 : if (asq == NULL)
115 0 : return LDB_ERR_OPERATIONS_ERROR;
116 :
117 14 : asq->result = ac->asq_ret;
118 :
119 14 : ac->controls[i]->data = asq;
120 :
121 14 : ac->controls[i + 1] = NULL;
122 :
123 14 : return ldb_module_done(ac->req, ac->controls, NULL, LDB_SUCCESS);
124 : }
125 :
126 28 : static int asq_base_callback(struct ldb_request *req, struct ldb_reply *ares)
127 : {
128 0 : struct asq_context *ac;
129 0 : int ret;
130 :
131 28 : ac = talloc_get_type(req->context, struct asq_context);
132 :
133 28 : if (!ares) {
134 0 : return ldb_module_done(ac->req, NULL, NULL,
135 : LDB_ERR_OPERATIONS_ERROR);
136 : }
137 28 : if (ares->error != LDB_SUCCESS) {
138 0 : return ldb_module_done(ac->req, ares->controls,
139 0 : ares->response, ares->error);
140 : }
141 :
142 28 : switch (ares->type) {
143 14 : case LDB_REPLY_ENTRY:
144 14 : ac->base_res = talloc_move(ac, &ares);
145 14 : break;
146 :
147 0 : case LDB_REPLY_REFERRAL:
148 : /* ignore referrals */
149 0 : talloc_free(ares);
150 0 : break;
151 :
152 14 : case LDB_REPLY_DONE:
153 :
154 14 : talloc_free(ares);
155 :
156 : /* next step */
157 14 : ret = asq_search_continue(ac);
158 14 : if (ret != LDB_SUCCESS) {
159 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
160 : }
161 14 : break;
162 :
163 : }
164 28 : return LDB_SUCCESS;
165 : }
166 :
167 186 : static int asq_reqs_callback(struct ldb_request *req, struct ldb_reply *ares)
168 : {
169 0 : struct asq_context *ac;
170 0 : int ret;
171 :
172 186 : ac = talloc_get_type(req->context, struct asq_context);
173 :
174 186 : if (!ares) {
175 0 : return ldb_module_done(ac->req, NULL, NULL,
176 : LDB_ERR_OPERATIONS_ERROR);
177 : }
178 186 : if (ares->error != LDB_SUCCESS) {
179 0 : return ldb_module_done(ac->req, ares->controls,
180 : ares->response, ares->error);
181 : }
182 :
183 186 : switch (ares->type) {
184 93 : 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 93 : ret = ldb_module_send_entry(ac->req, ares->message, ares->controls);
188 93 : if (ret != LDB_SUCCESS) {
189 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
190 : }
191 93 : talloc_free(ares);
192 93 : break;
193 :
194 0 : case LDB_REPLY_REFERRAL:
195 : /* ignore referrals */
196 0 : talloc_free(ares);
197 0 : break;
198 :
199 93 : case LDB_REPLY_DONE:
200 :
201 93 : talloc_free(ares);
202 :
203 93 : ret = asq_search_continue(ac);
204 93 : if (ret != LDB_SUCCESS) {
205 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
206 : }
207 93 : break;
208 : }
209 :
210 186 : return LDB_SUCCESS;
211 : }
212 :
213 14 : static int asq_build_first_request(struct asq_context *ac, struct ldb_request **base_req)
214 : {
215 0 : struct ldb_context *ldb;
216 0 : const char **base_attrs;
217 0 : int ret;
218 :
219 14 : ldb = ldb_module_get_ctx(ac->module);
220 :
221 14 : ac->req_attrs = ac->req->op.search.attrs;
222 14 : ac->req_attribute = talloc_strdup(ac, ac->asq_ctrl->source_attribute);
223 14 : if (ac->req_attribute == NULL)
224 0 : return LDB_ERR_OPERATIONS_ERROR;
225 :
226 14 : base_attrs = talloc_array(ac, const char *, 2);
227 14 : if (base_attrs == NULL) return LDB_ERR_OPERATIONS_ERROR;
228 :
229 14 : base_attrs[0] = talloc_strdup(base_attrs, ac->asq_ctrl->source_attribute);
230 14 : if (base_attrs[0] == NULL) return LDB_ERR_OPERATIONS_ERROR;
231 :
232 14 : base_attrs[1] = NULL;
233 :
234 14 : ret = ldb_build_search_req(base_req, ldb, ac,
235 14 : ac->req->op.search.base,
236 : LDB_SCOPE_BASE,
237 : NULL,
238 : (const char * const *)base_attrs,
239 : NULL,
240 : ac, asq_base_callback,
241 : ac->req);
242 14 : if (ret != LDB_SUCCESS) {
243 0 : return ret;
244 : }
245 :
246 14 : return LDB_SUCCESS;
247 : }
248 :
249 14 : static int asq_build_multiple_requests(struct asq_context *ac, bool *terminated)
250 : {
251 0 : struct ldb_context *ldb;
252 0 : struct ldb_control **saved_controls;
253 0 : struct ldb_control *control;
254 0 : struct ldb_dn *dn;
255 0 : struct ldb_message_element *el;
256 0 : unsigned int i;
257 0 : int ret;
258 :
259 14 : if (ac->base_res == NULL) {
260 0 : return LDB_ERR_NO_SUCH_OBJECT;
261 : }
262 :
263 14 : ldb = ldb_module_get_ctx(ac->module);
264 :
265 14 : el = ldb_msg_find_element(ac->base_res->message, ac->req_attribute);
266 : /* no values found */
267 14 : if (el == NULL) {
268 0 : ac->asq_ret = ASQ_CTRL_SUCCESS;
269 0 : *terminated = true;
270 0 : return asq_search_terminate(ac);
271 : }
272 :
273 14 : ac->num_reqs = el->num_values;
274 14 : ac->cur_req = 0;
275 14 : ac->reqs = talloc_array(ac, struct ldb_request *, ac->num_reqs);
276 14 : if (ac->reqs == NULL) {
277 0 : return LDB_ERR_OPERATIONS_ERROR;
278 : }
279 :
280 107 : for (i = 0; i < el->num_values; i++) {
281 :
282 93 : dn = ldb_dn_new(ac, ldb,
283 93 : (const char *)el->values[i].data);
284 93 : if ( ! ldb_dn_validate(dn)) {
285 0 : ac->asq_ret = ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX;
286 0 : *terminated = true;
287 0 : return asq_search_terminate(ac);
288 : }
289 :
290 93 : ret = ldb_build_search_req_ex(&ac->reqs[i],
291 : ldb, ac,
292 : dn, LDB_SCOPE_BASE,
293 93 : ac->req->op.search.tree,
294 : ac->req_attrs,
295 93 : ac->req->controls,
296 : ac, asq_reqs_callback,
297 : ac->req);
298 93 : if (ret != LDB_SUCCESS) {
299 0 : return ret;
300 : }
301 :
302 : /* remove the ASQ control itself */
303 93 : control = ldb_request_get_control(ac->req, LDB_CONTROL_ASQ_OID);
304 93 : if (!ldb_save_controls(control, ac->reqs[i], &saved_controls)) {
305 0 : return LDB_ERR_OPERATIONS_ERROR;
306 : }
307 : }
308 :
309 14 : return LDB_SUCCESS;
310 : }
311 :
312 107 : static int asq_search_continue(struct asq_context *ac)
313 : {
314 107 : bool terminated = false;
315 0 : int ret;
316 :
317 107 : switch (ac->step) {
318 14 : case ASQ_SEARCH_BASE:
319 :
320 : /* build up the requests call chain */
321 14 : ret = asq_build_multiple_requests(ac, &terminated);
322 14 : if (ret != LDB_SUCCESS || terminated) {
323 0 : return ret;
324 : }
325 :
326 14 : ac->step = ASQ_SEARCH_MULTI;
327 :
328 14 : return ldb_next_request(ac->module, ac->reqs[ac->cur_req]);
329 :
330 93 : case ASQ_SEARCH_MULTI:
331 :
332 93 : ac->cur_req++;
333 :
334 93 : if (ac->cur_req == ac->num_reqs) {
335 : /* done */
336 14 : return asq_search_terminate(ac);
337 : }
338 :
339 79 : return ldb_next_request(ac->module, ac->reqs[ac->cur_req]);
340 : }
341 :
342 0 : return LDB_ERR_OPERATIONS_ERROR;
343 : }
344 :
345 19970142 : static int asq_search(struct ldb_module *module, struct ldb_request *req)
346 : {
347 1144731 : struct ldb_request *base_req;
348 1144731 : struct ldb_control *control;
349 1144731 : struct asq_context *ac;
350 1144731 : int ret;
351 :
352 : /* check if there's an ASQ control */
353 19970142 : control = ldb_request_get_control(req, LDB_CONTROL_ASQ_OID);
354 19970142 : if (control == NULL) {
355 : /* not found go on */
356 19970128 : return ldb_next_request(module, req);
357 : }
358 :
359 14 : ac = asq_context_init(module, req);
360 14 : if (!ac) {
361 0 : return LDB_ERR_OPERATIONS_ERROR;
362 : }
363 :
364 : /* check the search is well formed */
365 14 : if (req->op.search.scope != LDB_SCOPE_BASE) {
366 0 : ac->asq_ret = ASQ_CTRL_UNWILLING_TO_PERFORM;
367 0 : return asq_search_terminate(ac);
368 : }
369 :
370 14 : ac->asq_ctrl = talloc_get_type(control->data, struct ldb_asq_control);
371 14 : if (!ac->asq_ctrl) {
372 0 : return LDB_ERR_PROTOCOL_ERROR;
373 : }
374 :
375 14 : ret = asq_build_first_request(ac, &base_req);
376 14 : if (ret != LDB_SUCCESS) {
377 0 : return ret;
378 : }
379 :
380 14 : ac->step = ASQ_SEARCH_BASE;
381 :
382 14 : return ldb_next_request(ac->module, base_req);
383 : }
384 :
385 182015 : static int asq_init(struct ldb_module *module)
386 : {
387 6027 : struct ldb_context *ldb;
388 6027 : int ret;
389 :
390 182015 : ldb = ldb_module_get_ctx(module);
391 :
392 182015 : ret = ldb_mod_register_control(module, LDB_CONTROL_ASQ_OID);
393 182015 : if (ret != LDB_SUCCESS) {
394 0 : ldb_debug(ldb, LDB_DEBUG_WARNING, "asq: Unable to register control with rootdse!");
395 : }
396 :
397 182015 : return ldb_next_init(module);
398 : }
399 :
400 : static const struct ldb_module_ops ldb_asq_module_ops = {
401 : .name = "asq",
402 : .search = asq_search,
403 : .init_context = asq_init
404 : };
405 :
406 6091 : int ldb_asq_init(const char *version)
407 : {
408 6091 : LDB_MODULE_CHECK_VERSION(version);
409 6091 : return ldb_register_module(&ldb_asq_module_ops);
410 : }
|