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 202 : 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 0 : struct ldb_context *ldb;
47 0 : struct ldb_parse_tree *list;
48 :
49 202 : ldb = ldb_module_get_ctx(module);
50 :
51 202 : list = talloc(mem_ctx, struct ldb_parse_tree);
52 202 : if (list == NULL){
53 0 : ldb_oom(ldb);
54 0 : return NULL;
55 : }
56 202 : list->operation = op;
57 :
58 202 : list->u.list.num_elements = 2;
59 202 : list->u.list.elements = talloc_array(list, struct ldb_parse_tree *, 2);
60 202 : if (!list->u.list.elements) {
61 0 : ldb_oom(ldb);
62 0 : return NULL;
63 : }
64 202 : list->u.list.elements[0] = talloc_steal(list, first_arm);
65 202 : list->u.list.elements[1] = talloc_steal(list, second_arm);
66 202 : return list;
67 : }
68 :
69 : /**
70 : * Make an equality or prefix match tree, from the attribute, operation and matching value supplied
71 : */
72 216 : 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 0 : struct ldb_context *ldb;
79 0 : struct ldb_parse_tree *match_tree;
80 :
81 216 : ldb = ldb_module_get_ctx(module);
82 :
83 216 : 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 216 : match_tree->operation = op;
88 216 : switch (op) {
89 202 : case LDB_OP_SUBSTRING:
90 202 : match_tree->u.substring.attr = attr;
91 :
92 202 : match_tree->u.substring.start_with_wildcard = 0;
93 202 : match_tree->u.substring.end_with_wildcard = 1;
94 202 : match_tree->u.substring.chunks = talloc_array(match_tree, struct ldb_val *, 2);
95 :
96 202 : if (match_tree->u.substring.chunks == NULL){
97 0 : talloc_free(match_tree);
98 0 : ldb_oom(ldb);
99 0 : return NULL;
100 : }
101 202 : match_tree->u.substring.chunks[0] = match;
102 202 : match_tree->u.substring.chunks[1] = NULL;
103 202 : 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 216 : 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 14 : 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 14 : struct ldb_parse_tree *tree = NULL;
135 14 : struct ldb_module *module = ac->module;
136 0 : struct ldb_parse_tree *match_tree;
137 0 : struct dsdb_attribute *cur;
138 0 : const struct dsdb_schema *schema;
139 0 : struct ldb_context *ldb;
140 0 : uint8_t *p;
141 0 : enum ldb_parse_op op;
142 :
143 14 : ldb = ldb_module_get_ctx(module);
144 :
145 14 : schema = dsdb_get_schema(ldb, ac);
146 14 : 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 14 : 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 13 : op = LDB_OP_SUBSTRING;
161 : }
162 21000 : for (cur = schema->attributes; cur; cur = cur->next) {
163 20986 : if (!(cur->searchFlags & SEARCH_FLAG_ANR)) continue;
164 196 : match_tree = make_match_tree(module, mem_ctx, op, cur->lDAPDisplayName, match);
165 :
166 196 : if (tree) {
167 : /* Inject an 'or' with the current tree */
168 182 : tree = make_parse_list(module, mem_ctx, LDB_OP_OR, tree, match_tree);
169 182 : if (tree == NULL) {
170 0 : return ldb_oom(ldb);
171 : }
172 : } else {
173 14 : 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 14 : p = memchr(match->data, ' ', match->length);
182 :
183 14 : if (p) {
184 0 : 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 14 : *ntree = tree;
225 14 : return LDB_SUCCESS;
226 : }
227 :
228 : /*
229 : replace any occurrences of an attribute with a new, generated attribute tree
230 : */
231 54 : 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 0 : int ret;
237 0 : unsigned int i;
238 :
239 54 : switch (tree->operation) {
240 20 : case LDB_OP_AND:
241 : case LDB_OP_OR:
242 60 : for (i=0;i<tree->u.list.num_elements;i++) {
243 40 : ret = anr_replace_subtrees(ac, tree->u.list.elements[i],
244 40 : attr, &tree->u.list.elements[i]);
245 40 : if (ret != LDB_SUCCESS) {
246 0 : return ret;
247 : }
248 40 : *ntree = tree;
249 : }
250 20 : 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 28 : case LDB_OP_EQUALITY:
259 28 : if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) {
260 14 : ret = anr_replace_value(ac, tree, &tree->u.equality.value, ntree);
261 14 : if (ret != LDB_SUCCESS) {
262 0 : return ret;
263 : }
264 : }
265 28 : break;
266 6 : case LDB_OP_SUBSTRING:
267 6 : 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 6 : break;
279 0 : default:
280 0 : break;
281 : }
282 :
283 54 : 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 61093847 : static int parse_tree_anr_present(struct ldb_parse_tree *tree, void *private_context)
295 : {
296 61093847 : struct anr_present_ctx *ctx = private_context;
297 61093847 : switch (tree->operation) {
298 4940014 : case LDB_OP_EQUALITY:
299 4940014 : if (ldb_attr_cmp(tree->u.equality.attr, ctx->attr) == 0) {
300 14 : ctx->found_anr = true;
301 : }
302 4763582 : break;
303 7437 : case LDB_OP_GREATER:
304 : case LDB_OP_LESS:
305 : case LDB_OP_APPROX:
306 7437 : if (ldb_attr_cmp(tree->u.comparison.attr, ctx->attr) == 0) {
307 0 : ctx->found_anr = true;
308 : }
309 7425 : break;
310 16742 : case LDB_OP_SUBSTRING:
311 16742 : if (ldb_attr_cmp(tree->u.substring.attr, ctx->attr) == 0) {
312 0 : ctx->found_anr = true;
313 : }
314 16742 : break;
315 32645420 : case LDB_OP_PRESENT:
316 32645420 : if (ldb_attr_cmp(tree->u.present.attr, ctx->attr) == 0) {
317 0 : ctx->found_anr = true;
318 : }
319 30627281 : break;
320 3166269 : case LDB_OP_EXTENDED:
321 3166269 : if (tree->u.extended.attr &&
322 3166269 : ldb_attr_cmp(tree->u.extended.attr, ctx->attr) == 0) {
323 0 : ctx->found_anr = true;
324 : }
325 3034194 : break;
326 19149784 : default:
327 19149784 : break;
328 : }
329 61093847 : return LDB_SUCCESS;
330 : }
331 :
332 :
333 63 : static int anr_search_callback(struct ldb_request *req, struct ldb_reply *ares)
334 : {
335 0 : struct anr_context *ac;
336 :
337 63 : ac = talloc_get_type(req->context, struct anr_context);
338 :
339 63 : if (!ares) {
340 0 : return ldb_module_done(ac->req, NULL, NULL,
341 : LDB_ERR_OPERATIONS_ERROR);
342 : }
343 63 : if (ares->error != LDB_SUCCESS) {
344 0 : return ldb_module_done(ac->req, ares->controls,
345 : ares->response, ares->error);
346 : }
347 :
348 63 : switch (ares->type) {
349 25 : case LDB_REPLY_ENTRY:
350 25 : return ldb_module_send_entry(ac->req, ares->message, ares->controls);
351 :
352 24 : case LDB_REPLY_REFERRAL:
353 24 : return ldb_module_send_referral(ac->req, ares->referral);
354 :
355 14 : case LDB_REPLY_DONE:
356 14 : return ldb_module_done(ac->req, ares->controls,
357 : ares->response, LDB_SUCCESS);
358 :
359 : }
360 0 : return LDB_SUCCESS;
361 : }
362 :
363 : /* search */
364 19969960 : static int anr_search(struct ldb_module *module, struct ldb_request *req)
365 : {
366 1144549 : struct ldb_context *ldb;
367 1144549 : struct ldb_parse_tree *anr_tree;
368 1144549 : struct ldb_request *down_req;
369 1144549 : struct anr_context *ac;
370 1144549 : struct anr_present_ctx ctx;
371 19969960 : const char *attr = "anr";
372 1144549 : int ret;
373 :
374 19969960 : ctx.found_anr = false;
375 19969960 : ctx.attr = attr;
376 :
377 19969960 : ldb_parse_tree_walk(req->op.search.tree,
378 : parse_tree_anr_present,
379 : &ctx);
380 :
381 19969960 : if (!ctx.found_anr) {
382 19969946 : return ldb_next_request(module, req);
383 : }
384 :
385 14 : ldb = ldb_module_get_ctx(module);
386 :
387 14 : ac = talloc(req, struct anr_context);
388 14 : if (!ac) {
389 0 : return ldb_oom(ldb);
390 : }
391 :
392 14 : ac->module = module;
393 14 : ac->req = req;
394 :
395 : #if 0
396 : printf("oldanr : %s\n", ldb_filter_from_tree (0, req->op.search.tree));
397 : #endif
398 :
399 : /* First make a copy, so we don't overwrite caller memory */
400 :
401 14 : anr_tree = ldb_parse_tree_copy_shallow(ac, req->op.search.tree);
402 :
403 14 : if (anr_tree == NULL) {
404 0 : return ldb_operr(ldb);
405 : }
406 :
407 : /* Now expand 'anr' out */
408 14 : ret = anr_replace_subtrees(ac, anr_tree, attr, &anr_tree);
409 14 : if (ret != LDB_SUCCESS) {
410 0 : return ldb_operr(ldb);
411 : }
412 :
413 14 : ret = ldb_build_search_req_ex(&down_req,
414 : ldb, ac,
415 : req->op.search.base,
416 : req->op.search.scope,
417 : anr_tree,
418 : req->op.search.attrs,
419 : req->controls,
420 : ac, anr_search_callback,
421 : req);
422 14 : LDB_REQ_SET_LOCATION(down_req);
423 14 : if (ret != LDB_SUCCESS) {
424 0 : return ldb_operr(ldb);
425 : }
426 14 : talloc_steal(down_req, anr_tree);
427 :
428 14 : return ldb_next_request(module, down_req);
429 : }
430 :
431 : static const struct ldb_module_ops ldb_anr_module_ops = {
432 : .name = "anr",
433 : .search = anr_search
434 : };
435 :
436 6040 : int ldb_anr_module_init(const char *version)
437 : {
438 6040 : LDB_MODULE_CHECK_VERSION(version);
439 6040 : return ldb_register_module(&ldb_anr_module_ops);
440 : }
|