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 	struct ldb_context *ldb;
315 	bool terminated = false;
316 	int ret;
317 
318 	ldb = ldb_module_get_ctx(ac->module);
319 
320 	switch (ac->step) {
321 	case ASQ_SEARCH_BASE:
322 
323 		/* build up the requests call chain */
324 		ret = asq_build_multiple_requests(ac, &terminated);
325 		if (ret != LDB_SUCCESS || terminated) {
326 			return ret;
327 		}
328 
329 		ac->step = ASQ_SEARCH_MULTI;
330 
331 		return ldb_request(ldb, ac->reqs[ac->cur_req]);
332 
333 	case ASQ_SEARCH_MULTI:
334 
335 		ac->cur_req++;
336 
337 		if (ac->cur_req == ac->num_reqs) {
338 			/* done */
339 			return asq_search_terminate(ac);
340 		}
341 
342 		return ldb_request(ldb, ac->reqs[ac->cur_req]);
343 	}
344 
345 	return LDB_ERR_OPERATIONS_ERROR;
346 }
347 
asq_search(struct ldb_module * module,struct ldb_request * req)348 static int asq_search(struct ldb_module *module, struct ldb_request *req)
349 {
350 	struct ldb_context *ldb;
351 	struct ldb_request *base_req;
352 	struct ldb_control *control;
353 	struct asq_context *ac;
354 	int ret;
355 
356 	ldb = ldb_module_get_ctx(module);
357 
358 	/* check if there's an ASQ control */
359 	control = ldb_request_get_control(req, LDB_CONTROL_ASQ_OID);
360 	if (control == NULL) {
361 		/* not found go on */
362 		return ldb_next_request(module, req);
363 	}
364 
365 	ac = asq_context_init(module, req);
366 	if (!ac) {
367 		return LDB_ERR_OPERATIONS_ERROR;
368 	}
369 
370 	/* check the search is well formed */
371 	if (req->op.search.scope != LDB_SCOPE_BASE) {
372 		ac->asq_ret = ASQ_CTRL_UNWILLING_TO_PERFORM;
373 		return asq_search_terminate(ac);
374 	}
375 
376 	ac->asq_ctrl = talloc_get_type(control->data, struct ldb_asq_control);
377 	if (!ac->asq_ctrl) {
378 		return LDB_ERR_PROTOCOL_ERROR;
379 	}
380 
381 	ret = asq_build_first_request(ac, &base_req);
382 	if (ret != LDB_SUCCESS) {
383 		return ret;
384 	}
385 
386 	ac->step = ASQ_SEARCH_BASE;
387 
388 	return ldb_request(ldb, base_req);
389 }
390 
asq_init(struct ldb_module * module)391 static int asq_init(struct ldb_module *module)
392 {
393 	struct ldb_context *ldb;
394 	int ret;
395 
396 	ldb = ldb_module_get_ctx(module);
397 
398 	ret = ldb_mod_register_control(module, LDB_CONTROL_ASQ_OID);
399 	if (ret != LDB_SUCCESS) {
400 		ldb_debug(ldb, LDB_DEBUG_WARNING, "asq: Unable to register control with rootdse!");
401 	}
402 
403 	return ldb_next_init(module);
404 }
405 
406 static const struct ldb_module_ops ldb_asq_module_ops = {
407 	.name		   = "asq",
408 	.search		   = asq_search,
409 	.init_context	   = asq_init
410 };
411 
ldb_asq_init(const char * version)412 int ldb_asq_init(const char *version)
413 {
414 	LDB_MODULE_CHECK_VERSION(version);
415 	return ldb_register_module(&ldb_asq_module_ops);
416 }
417