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