Line data Source code
1 : /*
2 : ldb database library
3 :
4 : Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007
5 : Copyright (C) Simo Sorce <idra@samba.org> 2008
6 : Copyright (C) Andrew Tridgell 2004
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : /*
23 : * Name: ldb
24 : *
25 : * Component: ldb anr module
26 : *
27 : * Description: module to implement 'ambiguous name resolution'
28 : *
29 : * Author: Andrew Bartlett
30 : */
31 :
32 : #include "includes.h"
33 : #include "ldb_module.h"
34 : #include "dsdb/samdb/samdb.h"
35 : #include "dsdb/samdb/ldb_modules/util.h"
36 :
37 : #undef strcasecmp
38 :
39 : /**
40 : * Make a and 'and' or 'or' tree from the two supplied elements
41 : */
42 124 : static struct ldb_parse_tree *make_parse_list(struct ldb_module *module,
43 : TALLOC_CTX *mem_ctx, enum ldb_parse_op op,
44 : struct ldb_parse_tree *first_arm, struct ldb_parse_tree *second_arm)
45 : {
46 : struct ldb_context *ldb;
47 : struct ldb_parse_tree *list;
48 :
49 124 : ldb = ldb_module_get_ctx(module);
50 :
51 124 : list = talloc(mem_ctx, struct ldb_parse_tree);
52 124 : if (list == NULL){
53 0 : ldb_oom(ldb);
54 0 : return NULL;
55 : }
56 124 : list->operation = op;
57 :
58 124 : list->u.list.num_elements = 2;
59 124 : list->u.list.elements = talloc_array(list, struct ldb_parse_tree *, 2);
60 124 : if (!list->u.list.elements) {
61 0 : ldb_oom(ldb);
62 0 : return NULL;
63 : }
64 124 : list->u.list.elements[0] = talloc_steal(list, first_arm);
65 124 : list->u.list.elements[1] = talloc_steal(list, second_arm);
66 124 : return list;
67 : }
68 :
69 : /**
70 : * Make an equality or prefix match tree, from the attribute, operation and matching value supplied
71 : */
72 132 : static struct ldb_parse_tree *make_match_tree(struct ldb_module *module,
73 : TALLOC_CTX *mem_ctx,
74 : enum ldb_parse_op op,
75 : const char *attr,
76 : struct ldb_val *match)
77 : {
78 : struct ldb_context *ldb;
79 : struct ldb_parse_tree *match_tree;
80 :
81 132 : ldb = ldb_module_get_ctx(module);
82 :
83 132 : match_tree = talloc(mem_ctx, struct ldb_parse_tree);
84 :
85 : /* Depending on what type of match was selected, fill in the right part of the union */
86 :
87 132 : match_tree->operation = op;
88 132 : switch (op) {
89 118 : case LDB_OP_SUBSTRING:
90 118 : match_tree->u.substring.attr = attr;
91 :
92 118 : match_tree->u.substring.start_with_wildcard = 0;
93 118 : match_tree->u.substring.end_with_wildcard = 1;
94 118 : match_tree->u.substring.chunks = talloc_array(match_tree, struct ldb_val *, 2);
95 :
96 118 : if (match_tree->u.substring.chunks == NULL){
97 0 : talloc_free(match_tree);
98 0 : ldb_oom(ldb);
99 0 : return NULL;
100 : }
101 118 : match_tree->u.substring.chunks[0] = match;
102 118 : match_tree->u.substring.chunks[1] = NULL;
103 118 : break;
104 14 : case LDB_OP_EQUALITY:
105 14 : match_tree->u.equality.attr = attr;
106 14 : match_tree->u.equality.value = *match;
107 14 : break;
108 0 : default:
109 0 : talloc_free(match_tree);
110 0 : return NULL;
111 : }
112 132 : return match_tree;
113 : }
114 :
115 : struct anr_context {
116 : bool found_anr;
117 : struct ldb_module *module;
118 : struct ldb_request *req;
119 : };
120 :
121 : /**
122 : * Given the match for an 'ambigious name resolution' query, create a
123 : * parse tree with an 'or' of all the anr attributes in the schema.
124 : */
125 :
126 : /**
127 : * Callback function to do the heavy lifting for the parse tree walker
128 : */
129 8 : static int anr_replace_value(struct anr_context *ac,
130 : TALLOC_CTX *mem_ctx,
131 : struct ldb_val *match,
132 : struct ldb_parse_tree **ntree)
133 : {
134 8 : struct ldb_parse_tree *tree = NULL;
135 8 : struct ldb_module *module = ac->module;
136 : struct ldb_parse_tree *match_tree;
137 : struct dsdb_attribute *cur;
138 : const struct dsdb_schema *schema;
139 : struct ldb_context *ldb;
140 : uint8_t *p;
141 : enum ldb_parse_op op;
142 :
143 8 : ldb = ldb_module_get_ctx(module);
144 :
145 8 : schema = dsdb_get_schema(ldb, ac);
146 8 : if (!schema) {
147 0 : ldb_asprintf_errstring(ldb, "no schema with which to construct anr filter");
148 0 : return LDB_ERR_OPERATIONS_ERROR;
149 : }
150 :
151 9 : if (match->length > 1 && match->data[0] == '=') {
152 1 : struct ldb_val *match2 = talloc(mem_ctx, struct ldb_val);
153 1 : if (match2 == NULL){
154 0 : return ldb_oom(ldb);
155 : }
156 1 : *match2 = data_blob_const(match->data+1, match->length - 1);
157 1 : match = match2;
158 1 : op = LDB_OP_EQUALITY;
159 : } else {
160 7 : op = LDB_OP_SUBSTRING;
161 : }
162 11792 : for (cur = schema->attributes; cur; cur = cur->next) {
163 11784 : if (!(cur->searchFlags & SEARCH_FLAG_ANR)) continue;
164 112 : match_tree = make_match_tree(module, mem_ctx, op, cur->lDAPDisplayName, match);
165 :
166 112 : if (tree) {
167 : /* Inject an 'or' with the current tree */
168 104 : tree = make_parse_list(module, mem_ctx, LDB_OP_OR, tree, match_tree);
169 104 : if (tree == NULL) {
170 0 : return ldb_oom(ldb);
171 : }
172 : } else {
173 8 : tree = match_tree;
174 : }
175 : }
176 :
177 :
178 : /* If the search term has a space in it,
179 : split it up at the first space. */
180 :
181 8 : p = memchr(match->data, ' ', match->length);
182 :
183 8 : if (p) {
184 : struct ldb_parse_tree *first_split_filter, *second_split_filter, *split_filters, *match_tree_1, *match_tree_2;
185 5 : struct ldb_val *first_match = talloc(tree, struct ldb_val);
186 5 : struct ldb_val *second_match = talloc(tree, struct ldb_val);
187 5 : if (!first_match || !second_match) {
188 0 : return ldb_oom(ldb);
189 : }
190 5 : *first_match = data_blob_const(match->data, p-match->data);
191 5 : *second_match = data_blob_const(p+1, match->length - (p-match->data) - 1);
192 :
193 : /* Add (|(&(givenname=first)(sn=second))(&(givenname=second)(sn=first))) */
194 :
195 5 : match_tree_1 = make_match_tree(module, mem_ctx, op, "givenName", first_match);
196 5 : match_tree_2 = make_match_tree(module, mem_ctx, op, "sn", second_match);
197 :
198 5 : first_split_filter = make_parse_list(module, ac, LDB_OP_AND, match_tree_1, match_tree_2);
199 5 : if (first_split_filter == NULL){
200 0 : return ldb_oom(ldb);
201 : }
202 :
203 5 : match_tree_1 = make_match_tree(module, mem_ctx, op, "sn", first_match);
204 5 : match_tree_2 = make_match_tree(module, mem_ctx, op, "givenName", second_match);
205 :
206 5 : second_split_filter = make_parse_list(module, ac, LDB_OP_AND, match_tree_1, match_tree_2);
207 5 : if (second_split_filter == NULL){
208 0 : return ldb_oom(ldb);
209 : }
210 :
211 5 : split_filters = make_parse_list(module, mem_ctx, LDB_OP_OR,
212 : first_split_filter, second_split_filter);
213 5 : if (split_filters == NULL) {
214 0 : return ldb_oom(ldb);
215 : }
216 :
217 5 : if (tree) {
218 : /* Inject an 'or' with the current tree */
219 5 : tree = make_parse_list(module, mem_ctx, LDB_OP_OR, tree, split_filters);
220 : } else {
221 0 : tree = split_filters;
222 : }
223 : }
224 8 : *ntree = tree;
225 8 : return LDB_SUCCESS;
226 : }
227 :
228 : /*
229 : replace any occurances of an attribute with a new, generated attribute tree
230 : */
231 24 : static int anr_replace_subtrees(struct anr_context *ac,
232 : struct ldb_parse_tree *tree,
233 : const char *attr,
234 : struct ldb_parse_tree **ntree)
235 : {
236 : int ret;
237 : unsigned int i;
238 :
239 24 : switch (tree->operation) {
240 8 : case LDB_OP_AND:
241 : case LDB_OP_OR:
242 24 : for (i=0;i<tree->u.list.num_elements;i++) {
243 16 : ret = anr_replace_subtrees(ac, tree->u.list.elements[i],
244 16 : attr, &tree->u.list.elements[i]);
245 16 : if (ret != LDB_SUCCESS) {
246 0 : return ret;
247 : }
248 16 : *ntree = tree;
249 : }
250 8 : break;
251 0 : case LDB_OP_NOT:
252 0 : ret = anr_replace_subtrees(ac, tree->u.isnot.child, attr, &tree->u.isnot.child);
253 0 : if (ret != LDB_SUCCESS) {
254 0 : return ret;
255 : }
256 0 : *ntree = tree;
257 0 : break;
258 16 : case LDB_OP_EQUALITY:
259 16 : if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) {
260 8 : ret = anr_replace_value(ac, tree, &tree->u.equality.value, ntree);
261 8 : if (ret != LDB_SUCCESS) {
262 0 : return ret;
263 : }
264 : }
265 16 : break;
266 0 : case LDB_OP_SUBSTRING:
267 0 : if (ldb_attr_cmp(tree->u.substring.attr, attr) == 0) {
268 0 : if (tree->u.substring.start_with_wildcard == 0 &&
269 0 : tree->u.substring.end_with_wildcard == 1 &&
270 0 : tree->u.substring.chunks[0] != NULL &&
271 0 : tree->u.substring.chunks[1] == NULL) {
272 0 : ret = anr_replace_value(ac, tree, tree->u.substring.chunks[0], ntree);
273 0 : if (ret != LDB_SUCCESS) {
274 0 : return ret;
275 : }
276 : }
277 : }
278 0 : break;
279 0 : default:
280 0 : break;
281 : }
282 :
283 24 : return LDB_SUCCESS;
284 : }
285 :
286 : struct anr_present_ctx {
287 : bool found_anr;
288 : const char *attr;
289 : };
290 :
291 : /*
292 : callback to determine if ANR is in use at all
293 : */
294 36270288 : static int parse_tree_anr_present(struct ldb_parse_tree *tree, void *private_context)
295 : {
296 36270288 : struct anr_present_ctx *ctx = private_context;
297 36270288 : switch (tree->operation) {
298 2755343 : case LDB_OP_EQUALITY:
299 : case LDB_OP_GREATER:
300 : case LDB_OP_LESS:
301 : case LDB_OP_APPROX:
302 2755343 : if (ldb_attr_cmp(tree->u.equality.attr, ctx->attr) == 0) {
303 8 : ctx->found_anr = true;
304 : }
305 2755343 : break;
306 15589 : case LDB_OP_SUBSTRING:
307 15589 : if (ldb_attr_cmp(tree->u.substring.attr, ctx->attr) == 0) {
308 0 : ctx->found_anr = true;
309 : }
310 15589 : break;
311 20309028 : case LDB_OP_PRESENT:
312 20309028 : if (ldb_attr_cmp(tree->u.present.attr, ctx->attr) == 0) {
313 0 : ctx->found_anr = true;
314 : }
315 20309028 : break;
316 1174176 : case LDB_OP_EXTENDED:
317 2299229 : if (tree->u.extended.attr &&
318 1174176 : ldb_attr_cmp(tree->u.extended.attr, ctx->attr) == 0) {
319 0 : ctx->found_anr = true;
320 : }
321 1174176 : break;
322 12016152 : default:
323 12016152 : break;
324 : }
325 36270288 : return LDB_SUCCESS;
326 : }
327 :
328 :
329 47 : static int anr_search_callback(struct ldb_request *req, struct ldb_reply *ares)
330 : {
331 : struct anr_context *ac;
332 :
333 47 : ac = talloc_get_type(req->context, struct anr_context);
334 :
335 47 : if (!ares) {
336 0 : return ldb_module_done(ac->req, NULL, NULL,
337 : LDB_ERR_OPERATIONS_ERROR);
338 : }
339 47 : if (ares->error != LDB_SUCCESS) {
340 0 : return ldb_module_done(ac->req, ares->controls,
341 : ares->response, ares->error);
342 : }
343 :
344 47 : switch (ares->type) {
345 15 : case LDB_REPLY_ENTRY:
346 15 : return ldb_module_send_entry(ac->req, ares->message, ares->controls);
347 :
348 24 : case LDB_REPLY_REFERRAL:
349 24 : return ldb_module_send_referral(ac->req, ares->referral);
350 :
351 8 : case LDB_REPLY_DONE:
352 8 : return ldb_module_done(ac->req, ares->controls,
353 : ares->response, LDB_SUCCESS);
354 :
355 : }
356 0 : return LDB_SUCCESS;
357 : }
358 :
359 : /* search */
360 11972046 : static int anr_search(struct ldb_module *module, struct ldb_request *req)
361 : {
362 : struct ldb_context *ldb;
363 : struct ldb_parse_tree *anr_tree;
364 : struct ldb_request *down_req;
365 : struct anr_context *ac;
366 : struct anr_present_ctx ctx;
367 11972046 : const char *attr = "anr";
368 : int ret;
369 :
370 11972046 : ctx.found_anr = false;
371 11972046 : ctx.attr = attr;
372 :
373 11972046 : ldb_parse_tree_walk(req->op.search.tree,
374 : parse_tree_anr_present,
375 : &ctx);
376 :
377 11972046 : if (!ctx.found_anr) {
378 11972038 : return ldb_next_request(module, req);
379 : }
380 :
381 8 : ldb = ldb_module_get_ctx(module);
382 :
383 8 : ac = talloc(req, struct anr_context);
384 8 : if (!ac) {
385 0 : return ldb_oom(ldb);
386 : }
387 :
388 8 : ac->module = module;
389 8 : ac->req = req;
390 :
391 : #if 0
392 : printf("oldanr : %s\n", ldb_filter_from_tree (0, req->op.search.tree));
393 : #endif
394 :
395 : /* First make a copy, so we don't overwrite caller memory */
396 :
397 8 : anr_tree = ldb_parse_tree_copy_shallow(ac, req->op.search.tree);
398 :
399 8 : if (anr_tree == NULL) {
400 0 : return ldb_operr(ldb);
401 : }
402 :
403 : /* Now expand 'anr' out */
404 8 : ret = anr_replace_subtrees(ac, anr_tree, attr, &anr_tree);
405 8 : if (ret != LDB_SUCCESS) {
406 0 : return ldb_operr(ldb);
407 : }
408 :
409 8 : ret = ldb_build_search_req_ex(&down_req,
410 : ldb, ac,
411 : req->op.search.base,
412 : req->op.search.scope,
413 : anr_tree,
414 : req->op.search.attrs,
415 : req->controls,
416 : ac, anr_search_callback,
417 : req);
418 8 : LDB_REQ_SET_LOCATION(down_req);
419 8 : if (ret != LDB_SUCCESS) {
420 0 : return ldb_operr(ldb);
421 : }
422 8 : talloc_steal(down_req, anr_tree);
423 :
424 8 : return ldb_next_request(module, down_req);
425 : }
426 :
427 : static const struct ldb_module_ops ldb_anr_module_ops = {
428 : .name = "anr",
429 : .search = anr_search
430 : };
431 :
432 4310 : int ldb_anr_module_init(const char *version)
433 : {
434 4310 : LDB_MODULE_CHECK_VERSION(version);
435 4310 : return ldb_register_module(&ldb_anr_module_ops);
436 : }
|