/src/samba/lib/ldb/common/ldb_match.c
Line | Count | Source |
1 | | /* |
2 | | ldb database library |
3 | | |
4 | | Copyright (C) Andrew Tridgell 2004-2005 |
5 | | Copyright (C) Simo Sorce 2005 |
6 | | |
7 | | ** NOTE! The following LGPL license applies to the ldb |
8 | | ** library. This does NOT imply that all of Samba is released |
9 | | ** under the LGPL |
10 | | |
11 | | This library is free software; you can redistribute it and/or |
12 | | modify it under the terms of the GNU Lesser General Public |
13 | | License as published by the Free Software Foundation; either |
14 | | version 3 of the License, or (at your option) any later version. |
15 | | |
16 | | This library is distributed in the hope that it will be useful, |
17 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
19 | | Lesser General Public License for more details. |
20 | | |
21 | | You should have received a copy of the GNU Lesser General Public |
22 | | License along with this library; if not, see <http://www.gnu.org/licenses/>. |
23 | | */ |
24 | | |
25 | | /* |
26 | | * Name: ldb |
27 | | * |
28 | | * Component: ldb expression matching |
29 | | * |
30 | | * Description: ldb expression matching |
31 | | * |
32 | | * Author: Andrew Tridgell |
33 | | */ |
34 | | |
35 | | #include "ldb_private.h" |
36 | | #include "dlinklist.h" |
37 | | #include "ldb_handlers.h" |
38 | | |
39 | | /* |
40 | | check if the scope matches in a search result |
41 | | */ |
42 | | int ldb_match_scope(struct ldb_context *ldb, |
43 | | struct ldb_dn *base, |
44 | | struct ldb_dn *dn, |
45 | | enum ldb_scope scope) |
46 | 0 | { |
47 | 0 | int ret = 0; |
48 | |
|
49 | 0 | if (base == NULL || dn == NULL) { |
50 | 0 | return 1; |
51 | 0 | } |
52 | | |
53 | 0 | switch (scope) { |
54 | 0 | case LDB_SCOPE_BASE: |
55 | 0 | if (ldb_dn_compare(base, dn) == 0) { |
56 | 0 | ret = 1; |
57 | 0 | } |
58 | 0 | break; |
59 | | |
60 | 0 | case LDB_SCOPE_ONELEVEL: |
61 | 0 | if (ldb_dn_get_comp_num(dn) == (ldb_dn_get_comp_num(base) + 1)) { |
62 | 0 | if (ldb_dn_compare_base(base, dn) == 0) { |
63 | 0 | ret = 1; |
64 | 0 | } |
65 | 0 | } |
66 | 0 | break; |
67 | | |
68 | 0 | case LDB_SCOPE_SUBTREE: |
69 | 0 | default: |
70 | 0 | if (ldb_dn_compare_base(base, dn) == 0) { |
71 | 0 | ret = 1; |
72 | 0 | } |
73 | 0 | break; |
74 | 0 | } |
75 | | |
76 | 0 | return ret; |
77 | 0 | } |
78 | | |
79 | | |
80 | | /* |
81 | | match if node is present |
82 | | */ |
83 | | static int ldb_match_present(struct ldb_context *ldb, |
84 | | const struct ldb_message *msg, |
85 | | const struct ldb_parse_tree *tree, |
86 | | enum ldb_scope scope, bool *matched) |
87 | 0 | { |
88 | 0 | const struct ldb_schema_attribute *a; |
89 | 0 | struct ldb_message_element *el; |
90 | |
|
91 | 0 | if (ldb_attr_dn(tree->u.present.attr) == 0) { |
92 | 0 | *matched = true; |
93 | 0 | return LDB_SUCCESS; |
94 | 0 | } |
95 | | |
96 | 0 | el = ldb_msg_find_element(msg, tree->u.present.attr); |
97 | 0 | if (el == NULL) { |
98 | 0 | *matched = false; |
99 | 0 | return LDB_SUCCESS; |
100 | 0 | } |
101 | | |
102 | 0 | a = ldb_schema_attribute_by_name(ldb, el->name); |
103 | 0 | if (!a) { |
104 | 0 | return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; |
105 | 0 | } |
106 | | |
107 | 0 | if (a->syntax->operator_fn) { |
108 | 0 | unsigned int i; |
109 | 0 | for (i = 0; i < el->num_values; i++) { |
110 | 0 | int ret = a->syntax->operator_fn(ldb, LDB_OP_PRESENT, a, &el->values[i], NULL, matched); |
111 | 0 | if (ret != LDB_SUCCESS) return ret; |
112 | 0 | if (*matched) return LDB_SUCCESS; |
113 | 0 | } |
114 | 0 | *matched = false; |
115 | 0 | return LDB_SUCCESS; |
116 | 0 | } |
117 | | |
118 | 0 | *matched = true; |
119 | 0 | return LDB_SUCCESS; |
120 | 0 | } |
121 | | |
122 | | static int ldb_match_comparison(struct ldb_context *ldb, |
123 | | const struct ldb_message *msg, |
124 | | const struct ldb_parse_tree *tree, |
125 | | enum ldb_scope scope, |
126 | | enum ldb_parse_op comp_op, bool *matched) |
127 | 0 | { |
128 | 0 | unsigned int i; |
129 | 0 | struct ldb_message_element *el; |
130 | 0 | const struct ldb_schema_attribute *a; |
131 | | |
132 | | /* FIXME: APPROX comparison not handled yet */ |
133 | 0 | if (comp_op == LDB_OP_APPROX) { |
134 | 0 | return LDB_ERR_INAPPROPRIATE_MATCHING; |
135 | 0 | } |
136 | | |
137 | 0 | el = ldb_msg_find_element(msg, tree->u.comparison.attr); |
138 | 0 | if (el == NULL) { |
139 | 0 | *matched = false; |
140 | 0 | return LDB_SUCCESS; |
141 | 0 | } |
142 | | |
143 | 0 | a = ldb_schema_attribute_by_name(ldb, el->name); |
144 | 0 | if (!a) { |
145 | 0 | return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; |
146 | 0 | } |
147 | | |
148 | 0 | for (i = 0; i < el->num_values; i++) { |
149 | 0 | if (a->syntax->operator_fn) { |
150 | 0 | int ret; |
151 | 0 | ret = a->syntax->operator_fn(ldb, comp_op, a, &el->values[i], &tree->u.comparison.value, matched); |
152 | 0 | if (ret != LDB_SUCCESS) return ret; |
153 | 0 | if (*matched) return LDB_SUCCESS; |
154 | 0 | } else { |
155 | 0 | int ret = a->syntax->comparison_fn(ldb, ldb, &el->values[i], &tree->u.comparison.value); |
156 | |
|
157 | 0 | if (ret == 0) { |
158 | 0 | *matched = true; |
159 | 0 | return LDB_SUCCESS; |
160 | 0 | } |
161 | 0 | if (ret > 0 && comp_op == LDB_OP_GREATER) { |
162 | 0 | *matched = true; |
163 | 0 | return LDB_SUCCESS; |
164 | 0 | } |
165 | 0 | if (ret < 0 && comp_op == LDB_OP_LESS) { |
166 | 0 | *matched = true; |
167 | 0 | return LDB_SUCCESS; |
168 | 0 | } |
169 | 0 | } |
170 | 0 | } |
171 | | |
172 | 0 | *matched = false; |
173 | 0 | return LDB_SUCCESS; |
174 | 0 | } |
175 | | |
176 | | /* |
177 | | match a simple leaf node |
178 | | */ |
179 | | static int ldb_match_equality(struct ldb_context *ldb, |
180 | | const struct ldb_message *msg, |
181 | | const struct ldb_parse_tree *tree, |
182 | | enum ldb_scope scope, |
183 | | bool *matched) |
184 | 0 | { |
185 | 0 | unsigned int i; |
186 | 0 | struct ldb_message_element *el; |
187 | 0 | const struct ldb_schema_attribute *a; |
188 | 0 | struct ldb_dn *valuedn; |
189 | 0 | int ret; |
190 | |
|
191 | 0 | if (ldb_attr_dn(tree->u.equality.attr) == 0) { |
192 | 0 | valuedn = ldb_dn_from_ldb_val(ldb, ldb, &tree->u.equality.value); |
193 | 0 | if (valuedn == NULL) { |
194 | 0 | return LDB_ERR_INVALID_DN_SYNTAX; |
195 | 0 | } |
196 | | |
197 | 0 | ret = ldb_dn_compare(msg->dn, valuedn); |
198 | |
|
199 | 0 | talloc_free(valuedn); |
200 | |
|
201 | 0 | *matched = (ret == 0); |
202 | 0 | return LDB_SUCCESS; |
203 | 0 | } |
204 | | |
205 | | /* TODO: handle the "*" case derived from an extended search |
206 | | operation without the attribute type defined */ |
207 | 0 | el = ldb_msg_find_element(msg, tree->u.equality.attr); |
208 | 0 | if (el == NULL) { |
209 | 0 | *matched = false; |
210 | 0 | return LDB_SUCCESS; |
211 | 0 | } |
212 | | |
213 | 0 | a = ldb_schema_attribute_by_name(ldb, el->name); |
214 | 0 | if (a == NULL) { |
215 | 0 | return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; |
216 | 0 | } |
217 | | |
218 | 0 | for (i=0;i<el->num_values;i++) { |
219 | 0 | if (a->syntax->operator_fn) { |
220 | 0 | ret = a->syntax->operator_fn(ldb, LDB_OP_EQUALITY, a, |
221 | 0 | &tree->u.equality.value, &el->values[i], matched); |
222 | 0 | if (ret != LDB_SUCCESS) return ret; |
223 | 0 | if (*matched) return LDB_SUCCESS; |
224 | 0 | } else { |
225 | 0 | if (a->syntax->comparison_fn(ldb, ldb, &tree->u.equality.value, |
226 | 0 | &el->values[i]) == 0) { |
227 | 0 | *matched = true; |
228 | 0 | return LDB_SUCCESS; |
229 | 0 | } |
230 | 0 | } |
231 | 0 | } |
232 | | |
233 | 0 | *matched = false; |
234 | 0 | return LDB_SUCCESS; |
235 | 0 | } |
236 | | |
237 | | static int ldb_wildcard_compare(struct ldb_context *ldb, |
238 | | const struct ldb_parse_tree *tree, |
239 | | const struct ldb_val value, bool *matched) |
240 | 0 | { |
241 | 0 | const struct ldb_schema_attribute *a; |
242 | 0 | struct ldb_val val; |
243 | 0 | struct ldb_val cnk; |
244 | 0 | struct ldb_val *chunk; |
245 | 0 | uint8_t *save_p = NULL; |
246 | 0 | unsigned int c = 0; |
247 | |
|
248 | 0 | if (tree->operation != LDB_OP_SUBSTRING) { |
249 | 0 | *matched = false; |
250 | 0 | return LDB_ERR_INAPPROPRIATE_MATCHING; |
251 | 0 | } |
252 | | |
253 | 0 | a = ldb_schema_attribute_by_name(ldb, tree->u.substring.attr); |
254 | 0 | if (!a) { |
255 | 0 | return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; |
256 | 0 | } |
257 | | |
258 | 0 | if (tree->u.substring.chunks == NULL) { |
259 | 0 | *matched = false; |
260 | 0 | return LDB_SUCCESS; |
261 | 0 | } |
262 | | |
263 | | /* No need to just copy this value for a binary match */ |
264 | 0 | if (a->syntax->canonicalise_fn != ldb_handler_copy) { |
265 | 0 | if (a->syntax->canonicalise_fn(ldb, ldb, &value, &val) != 0) { |
266 | 0 | return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; |
267 | 0 | } |
268 | | |
269 | | /* |
270 | | * Only set save_p if we allocate (call |
271 | | * a->syntax->canonicalise_fn()), as we |
272 | | * talloc_free(save_p) below to clean up |
273 | | */ |
274 | 0 | save_p = val.data; |
275 | 0 | } else { |
276 | 0 | val = value; |
277 | 0 | } |
278 | | |
279 | 0 | cnk.data = NULL; |
280 | |
|
281 | 0 | if ( ! tree->u.substring.start_with_wildcard ) { |
282 | 0 | uint8_t *cnk_to_free = NULL; |
283 | |
|
284 | 0 | chunk = tree->u.substring.chunks[c]; |
285 | | /* No need to just copy this value for a binary match */ |
286 | 0 | if (a->syntax->canonicalise_fn != ldb_handler_copy) { |
287 | 0 | if (a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) { |
288 | 0 | goto mismatch; |
289 | 0 | } |
290 | | |
291 | 0 | cnk_to_free = cnk.data; |
292 | 0 | } else { |
293 | 0 | cnk = *chunk; |
294 | 0 | } |
295 | | |
296 | | /* This deals with wildcard prefix searches on binary attributes (eg objectGUID) */ |
297 | 0 | if (cnk.length > val.length) { |
298 | 0 | TALLOC_FREE(cnk_to_free); |
299 | 0 | goto mismatch; |
300 | 0 | } |
301 | | /* |
302 | | * Empty strings are returned as length 0. Ensure |
303 | | * we can cope with this. |
304 | | */ |
305 | 0 | if (cnk.length == 0) { |
306 | 0 | TALLOC_FREE(cnk_to_free); |
307 | 0 | goto mismatch; |
308 | 0 | } |
309 | | |
310 | 0 | if (memcmp((char *)val.data, (char *)cnk.data, cnk.length) != 0) { |
311 | 0 | TALLOC_FREE(cnk_to_free); |
312 | 0 | goto mismatch; |
313 | 0 | } |
314 | | |
315 | 0 | val.length -= cnk.length; |
316 | 0 | val.data += cnk.length; |
317 | 0 | c++; |
318 | 0 | TALLOC_FREE(cnk_to_free); |
319 | 0 | cnk.data = NULL; |
320 | 0 | } |
321 | | |
322 | 0 | while (tree->u.substring.chunks[c]) { |
323 | 0 | uint8_t *p; |
324 | 0 | uint8_t *cnk_to_free = NULL; |
325 | |
|
326 | 0 | chunk = tree->u.substring.chunks[c]; |
327 | | /* No need to just copy this value for a binary match */ |
328 | 0 | if (a->syntax->canonicalise_fn != ldb_handler_copy) { |
329 | 0 | if (a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) { |
330 | 0 | goto mismatch; |
331 | 0 | } |
332 | | |
333 | 0 | cnk_to_free = cnk.data; |
334 | 0 | } else { |
335 | 0 | cnk = *chunk; |
336 | 0 | } |
337 | | /* |
338 | | * Empty strings are returned as length 0. Ensure |
339 | | * we can cope with this. |
340 | | */ |
341 | 0 | if (cnk.length == 0) { |
342 | 0 | TALLOC_FREE(cnk_to_free); |
343 | 0 | goto mismatch; |
344 | 0 | } |
345 | 0 | if (cnk.length > val.length) { |
346 | 0 | TALLOC_FREE(cnk_to_free); |
347 | 0 | goto mismatch; |
348 | 0 | } |
349 | | |
350 | 0 | if ( (tree->u.substring.chunks[c + 1]) == NULL && |
351 | 0 | (! tree->u.substring.end_with_wildcard) ) { |
352 | | /* |
353 | | * The last bit, after all the asterisks, must match |
354 | | * exactly the last bit of the string. |
355 | | */ |
356 | 0 | int cmp; |
357 | 0 | p = val.data + val.length - cnk.length; |
358 | 0 | cmp = memcmp(p, |
359 | 0 | cnk.data, |
360 | 0 | cnk.length); |
361 | 0 | TALLOC_FREE(cnk_to_free); |
362 | |
|
363 | 0 | if (cmp != 0) { |
364 | 0 | goto mismatch; |
365 | 0 | } |
366 | 0 | } else { |
367 | | /* |
368 | | * Values might be binary blobs. Don't use string |
369 | | * search, but memory search instead. |
370 | | */ |
371 | 0 | p = memmem((const void *)val.data, val.length, |
372 | 0 | (const void *)cnk.data, cnk.length); |
373 | 0 | if (p == NULL) { |
374 | 0 | TALLOC_FREE(cnk_to_free); |
375 | 0 | goto mismatch; |
376 | 0 | } |
377 | | /* move val to the end of the match */ |
378 | 0 | p += cnk.length; |
379 | 0 | val.length -= (p - val.data); |
380 | 0 | val.data = p; |
381 | 0 | TALLOC_FREE(cnk_to_free); |
382 | 0 | } |
383 | 0 | c++; |
384 | 0 | } |
385 | | |
386 | 0 | talloc_free(save_p); |
387 | 0 | *matched = true; |
388 | 0 | return LDB_SUCCESS; |
389 | | |
390 | 0 | mismatch: |
391 | 0 | *matched = false; |
392 | 0 | talloc_free(save_p); |
393 | 0 | return LDB_SUCCESS; |
394 | 0 | } |
395 | | |
396 | | /* |
397 | | match a simple leaf node |
398 | | */ |
399 | | static int ldb_match_substring(struct ldb_context *ldb, |
400 | | const struct ldb_message *msg, |
401 | | const struct ldb_parse_tree *tree, |
402 | | enum ldb_scope scope, bool *matched) |
403 | 0 | { |
404 | 0 | unsigned int i; |
405 | 0 | struct ldb_message_element *el; |
406 | |
|
407 | 0 | el = ldb_msg_find_element(msg, tree->u.substring.attr); |
408 | 0 | if (el == NULL) { |
409 | 0 | *matched = false; |
410 | 0 | return LDB_SUCCESS; |
411 | 0 | } |
412 | | |
413 | 0 | for (i = 0; i < el->num_values; i++) { |
414 | 0 | int ret; |
415 | 0 | ret = ldb_wildcard_compare(ldb, tree, el->values[i], matched); |
416 | 0 | if (ret != LDB_SUCCESS) return ret; |
417 | 0 | if (*matched) return LDB_SUCCESS; |
418 | 0 | } |
419 | | |
420 | 0 | *matched = false; |
421 | 0 | return LDB_SUCCESS; |
422 | 0 | } |
423 | | |
424 | | |
425 | | /* |
426 | | bitwise and/or comparator depending on oid |
427 | | */ |
428 | | static int ldb_comparator_bitmask(const char *oid, const struct ldb_val *v1, const struct ldb_val *v2, |
429 | | bool *matched) |
430 | 0 | { |
431 | 0 | uint64_t i1, i2; |
432 | 0 | char ibuf[100]; |
433 | 0 | char *endptr = NULL; |
434 | |
|
435 | 0 | if (v1->length >= sizeof(ibuf)-1) { |
436 | 0 | return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; |
437 | 0 | } |
438 | 0 | memcpy(ibuf, (char *)v1->data, v1->length); |
439 | 0 | ibuf[v1->length] = 0; |
440 | 0 | i1 = strtoull(ibuf, &endptr, 0); |
441 | 0 | if (endptr != NULL) { |
442 | 0 | if (endptr == ibuf || *endptr != 0) { |
443 | 0 | return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; |
444 | 0 | } |
445 | 0 | } |
446 | | |
447 | 0 | if (v2->length >= sizeof(ibuf)-1) { |
448 | 0 | return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; |
449 | 0 | } |
450 | 0 | endptr = NULL; |
451 | 0 | memcpy(ibuf, (char *)v2->data, v2->length); |
452 | 0 | ibuf[v2->length] = 0; |
453 | 0 | i2 = strtoull(ibuf, &endptr, 0); |
454 | 0 | if (endptr != NULL) { |
455 | 0 | if (endptr == ibuf || *endptr != 0) { |
456 | 0 | return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; |
457 | 0 | } |
458 | 0 | } |
459 | 0 | if (strcmp(LDB_OID_COMPARATOR_AND, oid) == 0) { |
460 | 0 | *matched = ((i1 & i2) == i2); |
461 | 0 | } else if (strcmp(LDB_OID_COMPARATOR_OR, oid) == 0) { |
462 | 0 | *matched = ((i1 & i2) != 0); |
463 | 0 | } else { |
464 | 0 | return LDB_ERR_INAPPROPRIATE_MATCHING; |
465 | 0 | } |
466 | 0 | return LDB_SUCCESS; |
467 | 0 | } |
468 | | |
469 | | static int ldb_match_bitmask(struct ldb_context *ldb, |
470 | | const char *oid, |
471 | | const struct ldb_message *msg, |
472 | | const char *attribute_to_match, |
473 | | const struct ldb_val *value_to_match, |
474 | | bool *matched) |
475 | 0 | { |
476 | 0 | unsigned int i; |
477 | 0 | struct ldb_message_element *el; |
478 | | |
479 | | /* find the message element */ |
480 | 0 | el = ldb_msg_find_element(msg, attribute_to_match); |
481 | 0 | if (el == NULL) { |
482 | 0 | *matched = false; |
483 | 0 | return LDB_SUCCESS; |
484 | 0 | } |
485 | | |
486 | 0 | for (i=0;i<el->num_values;i++) { |
487 | 0 | int ret; |
488 | 0 | struct ldb_val *v = &el->values[i]; |
489 | |
|
490 | 0 | ret = ldb_comparator_bitmask(oid, v, value_to_match, matched); |
491 | 0 | if (ret != LDB_SUCCESS) { |
492 | 0 | return ret; |
493 | 0 | } |
494 | 0 | if (*matched) { |
495 | 0 | return LDB_SUCCESS; |
496 | 0 | } |
497 | 0 | } |
498 | | |
499 | 0 | *matched = false; |
500 | 0 | return LDB_SUCCESS; |
501 | 0 | } |
502 | | |
503 | | /* |
504 | | always return false |
505 | | */ |
506 | | static int ldb_comparator_false(struct ldb_context *ldb, |
507 | | const char *oid, |
508 | | const struct ldb_message *msg, |
509 | | const char *attribute_to_match, |
510 | | const struct ldb_val *value_to_match, |
511 | | bool *matched) |
512 | 0 | { |
513 | 0 | *matched = false; |
514 | 0 | return LDB_SUCCESS; |
515 | 0 | } |
516 | | |
517 | | |
518 | | static const struct ldb_extended_match_rule *ldb_find_extended_match_rule(struct ldb_context *ldb, |
519 | | const char *oid) |
520 | 0 | { |
521 | 0 | struct ldb_extended_match_entry *extended_match_rule; |
522 | |
|
523 | 0 | for (extended_match_rule = ldb->extended_match_rules; |
524 | 0 | extended_match_rule; |
525 | 0 | extended_match_rule = extended_match_rule->next) { |
526 | 0 | if (strcmp(extended_match_rule->rule->oid, oid) == 0) { |
527 | 0 | return extended_match_rule->rule; |
528 | 0 | } |
529 | 0 | } |
530 | | |
531 | 0 | return NULL; |
532 | 0 | } |
533 | | |
534 | | |
535 | | /* |
536 | | extended match, handles things like bitops |
537 | | */ |
538 | | static int ldb_match_extended(struct ldb_context *ldb, |
539 | | const struct ldb_message *msg, |
540 | | const struct ldb_parse_tree *tree, |
541 | | enum ldb_scope scope, bool *matched) |
542 | 0 | { |
543 | 0 | const struct ldb_extended_match_rule *rule; |
544 | |
|
545 | 0 | if (tree->u.extended.dnAttributes) { |
546 | | /* FIXME: We really need to find out what this ":dn" part in |
547 | | * an extended match means and how to handle it. For now print |
548 | | * only a warning to have s3 winbind and other tools working |
549 | | * against us. - Matthias */ |
550 | 0 | ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb: dnAttributes extended match not supported yet"); |
551 | 0 | } |
552 | 0 | if (tree->u.extended.rule_id == NULL) { |
553 | 0 | ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-rule extended matches not supported yet"); |
554 | 0 | return LDB_ERR_INAPPROPRIATE_MATCHING; |
555 | 0 | } |
556 | 0 | if (tree->u.extended.attr == NULL) { |
557 | 0 | ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-attribute extended matches not supported yet"); |
558 | 0 | return LDB_ERR_INAPPROPRIATE_MATCHING; |
559 | 0 | } |
560 | | |
561 | 0 | rule = ldb_find_extended_match_rule(ldb, tree->u.extended.rule_id); |
562 | 0 | if (rule == NULL) { |
563 | 0 | *matched = false; |
564 | 0 | ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: unknown extended rule_id %s", |
565 | 0 | tree->u.extended.rule_id); |
566 | 0 | return LDB_SUCCESS; |
567 | 0 | } |
568 | | |
569 | 0 | return rule->callback(ldb, rule->oid, msg, |
570 | 0 | tree->u.extended.attr, |
571 | 0 | &tree->u.extended.value, matched); |
572 | 0 | } |
573 | | |
574 | | static bool ldb_must_suppress_match(const struct ldb_message *msg, |
575 | | const struct ldb_parse_tree *tree) |
576 | 0 | { |
577 | 0 | const char *attr = NULL; |
578 | 0 | struct ldb_message_element *el = NULL; |
579 | |
|
580 | 0 | attr = ldb_parse_tree_get_attr(tree); |
581 | 0 | if (attr == NULL) { |
582 | 0 | return false; |
583 | 0 | } |
584 | | |
585 | | /* find the message element */ |
586 | 0 | el = ldb_msg_find_element(msg, attr); |
587 | 0 | if (el == NULL) { |
588 | 0 | return false; |
589 | 0 | } |
590 | | |
591 | 0 | return ldb_msg_element_is_inaccessible(el); |
592 | 0 | } |
593 | | |
594 | | /* |
595 | | Check if a particular message will match the given filter |
596 | | |
597 | | set *matched to true if it matches, false otherwise |
598 | | |
599 | | returns LDB_SUCCESS or an error |
600 | | |
601 | | this is a recursive function, and does short-circuit evaluation |
602 | | */ |
603 | | int ldb_match_message(struct ldb_context *ldb, |
604 | | const struct ldb_message *msg, |
605 | | const struct ldb_parse_tree *tree, |
606 | | enum ldb_scope scope, bool *matched) |
607 | 0 | { |
608 | 0 | unsigned int i; |
609 | 0 | int ret; |
610 | |
|
611 | 0 | *matched = false; |
612 | |
|
613 | 0 | if (scope != LDB_SCOPE_BASE && ldb_dn_is_special(msg->dn)) { |
614 | | /* don't match special records except on base searches */ |
615 | 0 | return LDB_SUCCESS; |
616 | 0 | } |
617 | | |
618 | | /* |
619 | | * Suppress matches on confidential attributes (handled |
620 | | * manually in extended matches as these can do custom things |
621 | | * like read other parts of the DB or other attributes). |
622 | | */ |
623 | 0 | if (tree->operation != LDB_OP_EXTENDED) { |
624 | 0 | if (ldb_must_suppress_match(msg, tree)) { |
625 | 0 | return LDB_SUCCESS; |
626 | 0 | } |
627 | 0 | } |
628 | | |
629 | 0 | switch (tree->operation) { |
630 | 0 | case LDB_OP_AND: |
631 | 0 | for (i=0;i<tree->u.list.num_elements;i++) { |
632 | 0 | ret = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope, matched); |
633 | 0 | if (ret != LDB_SUCCESS) return ret; |
634 | 0 | if (!*matched) return LDB_SUCCESS; |
635 | 0 | } |
636 | 0 | *matched = true; |
637 | 0 | return LDB_SUCCESS; |
638 | | |
639 | 0 | case LDB_OP_OR: |
640 | 0 | for (i=0;i<tree->u.list.num_elements;i++) { |
641 | 0 | ret = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope, matched); |
642 | 0 | if (ret != LDB_SUCCESS) return ret; |
643 | 0 | if (*matched) return LDB_SUCCESS; |
644 | 0 | } |
645 | 0 | *matched = false; |
646 | 0 | return LDB_SUCCESS; |
647 | | |
648 | 0 | case LDB_OP_NOT: |
649 | 0 | ret = ldb_match_message(ldb, msg, tree->u.isnot.child, scope, matched); |
650 | 0 | if (ret != LDB_SUCCESS) return ret; |
651 | 0 | *matched = ! *matched; |
652 | 0 | return LDB_SUCCESS; |
653 | | |
654 | 0 | case LDB_OP_EQUALITY: |
655 | 0 | return ldb_match_equality(ldb, msg, tree, scope, matched); |
656 | | |
657 | 0 | case LDB_OP_SUBSTRING: |
658 | 0 | return ldb_match_substring(ldb, msg, tree, scope, matched); |
659 | | |
660 | 0 | case LDB_OP_GREATER: |
661 | 0 | return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_GREATER, matched); |
662 | | |
663 | 0 | case LDB_OP_LESS: |
664 | 0 | return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_LESS, matched); |
665 | | |
666 | 0 | case LDB_OP_PRESENT: |
667 | 0 | return ldb_match_present(ldb, msg, tree, scope, matched); |
668 | | |
669 | 0 | case LDB_OP_APPROX: |
670 | 0 | return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_APPROX, matched); |
671 | | |
672 | 0 | case LDB_OP_EXTENDED: |
673 | 0 | return ldb_match_extended(ldb, msg, tree, scope, matched); |
674 | 0 | } |
675 | | |
676 | 0 | return LDB_ERR_INAPPROPRIATE_MATCHING; |
677 | 0 | } |
678 | | |
679 | | /* |
680 | | return 0 if the given parse tree matches the given message. Assumes |
681 | | the message is in sorted order |
682 | | |
683 | | return 1 if it matches, and 0 if it doesn't match |
684 | | */ |
685 | | |
686 | | int ldb_match_msg(struct ldb_context *ldb, |
687 | | const struct ldb_message *msg, |
688 | | const struct ldb_parse_tree *tree, |
689 | | struct ldb_dn *base, |
690 | | enum ldb_scope scope) |
691 | 0 | { |
692 | 0 | bool matched; |
693 | 0 | int ret; |
694 | |
|
695 | 0 | if ( ! ldb_match_scope(ldb, base, msg->dn, scope) ) { |
696 | 0 | return 0; |
697 | 0 | } |
698 | | |
699 | 0 | ret = ldb_match_message(ldb, msg, tree, scope, &matched); |
700 | 0 | if (ret != LDB_SUCCESS) { |
701 | | /* to match the old API, we need to consider this a |
702 | | failure to match */ |
703 | 0 | return 0; |
704 | 0 | } |
705 | 0 | return matched?1:0; |
706 | 0 | } |
707 | | |
708 | | int ldb_match_msg_error(struct ldb_context *ldb, |
709 | | const struct ldb_message *msg, |
710 | | const struct ldb_parse_tree *tree, |
711 | | struct ldb_dn *base, |
712 | | enum ldb_scope scope, |
713 | | bool *matched) |
714 | 0 | { |
715 | 0 | if ( ! ldb_match_scope(ldb, base, msg->dn, scope) ) { |
716 | 0 | *matched = false; |
717 | 0 | return LDB_SUCCESS; |
718 | 0 | } |
719 | | |
720 | 0 | return ldb_match_message(ldb, msg, tree, scope, matched); |
721 | 0 | } |
722 | | |
723 | | int ldb_match_msg_objectclass(const struct ldb_message *msg, |
724 | | const char *objectclass) |
725 | 0 | { |
726 | 0 | unsigned int i; |
727 | 0 | struct ldb_message_element *el = ldb_msg_find_element(msg, "objectClass"); |
728 | 0 | if (!el) { |
729 | 0 | return 0; |
730 | 0 | } |
731 | 0 | for (i=0; i < el->num_values; i++) { |
732 | 0 | if (ldb_attr_cmp((const char *)el->values[i].data, objectclass) == 0) { |
733 | 0 | return 1; |
734 | 0 | } |
735 | 0 | } |
736 | 0 | return 0; |
737 | 0 | } |
738 | | |
739 | | _PRIVATE_ int ldb_register_extended_match_rules(struct ldb_context *ldb) |
740 | 0 | { |
741 | 0 | struct ldb_extended_match_rule *bitmask_and; |
742 | 0 | struct ldb_extended_match_rule *bitmask_or; |
743 | 0 | struct ldb_extended_match_rule *always_false; |
744 | 0 | int ret; |
745 | | |
746 | | /* Register bitmask-and match */ |
747 | 0 | bitmask_and = talloc_zero(ldb, struct ldb_extended_match_rule); |
748 | 0 | if (bitmask_and == NULL) { |
749 | 0 | return LDB_ERR_OPERATIONS_ERROR; |
750 | 0 | } |
751 | | |
752 | 0 | bitmask_and->oid = LDB_OID_COMPARATOR_AND; |
753 | 0 | bitmask_and->callback = ldb_match_bitmask; |
754 | |
|
755 | 0 | ret = ldb_register_extended_match_rule(ldb, bitmask_and); |
756 | 0 | if (ret != LDB_SUCCESS) { |
757 | 0 | return ret; |
758 | 0 | } |
759 | | |
760 | | /* Register bitmask-or match */ |
761 | 0 | bitmask_or = talloc_zero(ldb, struct ldb_extended_match_rule); |
762 | 0 | if (bitmask_or == NULL) { |
763 | 0 | return LDB_ERR_OPERATIONS_ERROR; |
764 | 0 | } |
765 | | |
766 | 0 | bitmask_or->oid = LDB_OID_COMPARATOR_OR; |
767 | 0 | bitmask_or->callback = ldb_match_bitmask; |
768 | |
|
769 | 0 | ret = ldb_register_extended_match_rule(ldb, bitmask_or); |
770 | 0 | if (ret != LDB_SUCCESS) { |
771 | 0 | return ret; |
772 | 0 | } |
773 | | |
774 | | /* Register always-false match */ |
775 | 0 | always_false = talloc_zero(ldb, struct ldb_extended_match_rule); |
776 | 0 | if (always_false == NULL) { |
777 | 0 | return LDB_ERR_OPERATIONS_ERROR; |
778 | 0 | } |
779 | | |
780 | 0 | always_false->oid = SAMBA_LDAP_MATCH_ALWAYS_FALSE; |
781 | 0 | always_false->callback = ldb_comparator_false; |
782 | |
|
783 | 0 | ret = ldb_register_extended_match_rule(ldb, always_false); |
784 | 0 | if (ret != LDB_SUCCESS) { |
785 | 0 | return ret; |
786 | 0 | } |
787 | | |
788 | 0 | return LDB_SUCCESS; |
789 | 0 | } |
790 | | |
791 | | /* |
792 | | register a new ldb extended matching rule |
793 | | */ |
794 | | int ldb_register_extended_match_rule(struct ldb_context *ldb, |
795 | | const struct ldb_extended_match_rule *rule) |
796 | 0 | { |
797 | 0 | const struct ldb_extended_match_rule *lookup_rule; |
798 | 0 | struct ldb_extended_match_entry *entry; |
799 | |
|
800 | 0 | lookup_rule = ldb_find_extended_match_rule(ldb, rule->oid); |
801 | 0 | if (lookup_rule) { |
802 | 0 | return LDB_ERR_ENTRY_ALREADY_EXISTS; |
803 | 0 | } |
804 | | |
805 | 0 | entry = talloc_zero(ldb, struct ldb_extended_match_entry); |
806 | 0 | if (!entry) { |
807 | 0 | return LDB_ERR_OPERATIONS_ERROR; |
808 | 0 | } |
809 | 0 | entry->rule = rule; |
810 | 0 | DLIST_ADD_END(ldb->extended_match_rules, entry); |
811 | |
|
812 | 0 | return LDB_SUCCESS; |
813 | 0 | } |
814 | | |
815 | | int ldb_register_redact_callback(struct ldb_context *ldb, |
816 | | ldb_redact_fn redact_fn, |
817 | | struct ldb_module *module) |
818 | 0 | { |
819 | 0 | if (ldb->redact.callback != NULL) { |
820 | 0 | return LDB_ERR_ENTRY_ALREADY_EXISTS; |
821 | 0 | } |
822 | | |
823 | 0 | ldb->redact.callback = redact_fn; |
824 | 0 | ldb->redact.module = module; |
825 | 0 | return LDB_SUCCESS; |
826 | 0 | } |