/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- ldb_match_scope
- ldb_match_present
- ldb_match_comparison
- ldb_match_equality
- ldb_wildcard_compare
- ldb_match_substring
- ldb_comparator_and
- ldb_comparator_or
- ldb_match_extended
- ldb_match_message
- ldb_match_msg
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 "includes.h"
36 #include "ldb/include/includes.h"
37
38 /*
39 check if the scope matches in a search result
40 */
41 static int ldb_match_scope(struct ldb_context *ldb,
/* [<][>][^][v][top][bottom][index][help] */
42 const struct ldb_dn *base,
43 const struct ldb_dn *dn,
44 enum ldb_scope scope)
45 {
46 int ret = 0;
47
48 if (base == NULL || dn == NULL) {
49 return 1;
50 }
51
52 switch (scope) {
53 case LDB_SCOPE_BASE:
54 if (ldb_dn_compare(ldb, base, dn) == 0) {
55 ret = 1;
56 }
57 break;
58
59 case LDB_SCOPE_ONELEVEL:
60 if (ldb_dn_get_comp_num(dn) == (ldb_dn_get_comp_num(base) + 1)) {
61 if (ldb_dn_compare_base(ldb, base, dn) == 0) {
62 ret = 1;
63 }
64 }
65 break;
66
67 case LDB_SCOPE_SUBTREE:
68 default:
69 if (ldb_dn_compare_base(ldb, base, dn) == 0) {
70 ret = 1;
71 }
72 break;
73 }
74
75 return ret;
76 }
77
78
79 /*
80 match if node is present
81 */
82 static int ldb_match_present(struct ldb_context *ldb,
/* [<][>][^][v][top][bottom][index][help] */
83 const struct ldb_message *msg,
84 const struct ldb_parse_tree *tree,
85 enum ldb_scope scope)
86 {
87 if (ldb_attr_dn(tree->u.present.attr) == 0) {
88 return 1;
89 }
90
91 if (ldb_msg_find_element(msg, tree->u.present.attr)) {
92 return 1;
93 }
94
95 return 0;
96 }
97
98 static int ldb_match_comparison(struct ldb_context *ldb,
/* [<][>][^][v][top][bottom][index][help] */
99 const struct ldb_message *msg,
100 const struct ldb_parse_tree *tree,
101 enum ldb_scope scope,
102 enum ldb_parse_op comp_op)
103 {
104 unsigned int i;
105 struct ldb_message_element *el;
106 const struct ldb_attrib_handler *h;
107 int ret;
108
109 /* FIXME: APPROX comparison not handled yet */
110 if (comp_op == LDB_OP_APPROX) return 0;
111
112 el = ldb_msg_find_element(msg, tree->u.comparison.attr);
113 if (el == NULL) {
114 return 0;
115 }
116
117 h = ldb_attrib_handler(ldb, el->name);
118
119 for (i = 0; i < el->num_values; i++) {
120 ret = h->comparison_fn(ldb, ldb, &el->values[i], &tree->u.comparison.value);
121
122 if (ret == 0) {
123 return 1;
124 }
125 if (ret > 0 && comp_op == LDB_OP_GREATER) {
126 return 1;
127 }
128 if (ret < 0 && comp_op == LDB_OP_LESS) {
129 return 1;
130 }
131 }
132
133 return 0;
134 }
135
136 /*
137 match a simple leaf node
138 */
139 static int ldb_match_equality(struct ldb_context *ldb,
/* [<][>][^][v][top][bottom][index][help] */
140 const struct ldb_message *msg,
141 const struct ldb_parse_tree *tree,
142 enum ldb_scope scope)
143 {
144 unsigned int i;
145 struct ldb_message_element *el;
146 const struct ldb_attrib_handler *h;
147 struct ldb_dn *valuedn;
148 int ret;
149
150 if (ldb_attr_dn(tree->u.equality.attr) == 0) {
151 valuedn = ldb_dn_explode_casefold(ldb, ldb,
152 (char *)tree->u.equality.value.data);
153 if (valuedn == NULL) {
154 return 0;
155 }
156
157 ret = ldb_dn_compare(ldb, msg->dn, valuedn);
158
159 talloc_free(valuedn);
160
161 if (ret == 0) return 1;
162 return 0;
163 }
164
165 /* TODO: handle the "*" case derived from an extended search
166 operation without the attibute type defined */
167 el = ldb_msg_find_element(msg, tree->u.equality.attr);
168 if (el == NULL) {
169 return 0;
170 }
171
172 h = ldb_attrib_handler(ldb, el->name);
173
174 for (i=0;i<el->num_values;i++) {
175 if (h->comparison_fn(ldb, ldb, &tree->u.equality.value,
176 &el->values[i]) == 0) {
177 return 1;
178 }
179 }
180
181 return 0;
182 }
183
184 static int ldb_wildcard_compare(struct ldb_context *ldb,
/* [<][>][^][v][top][bottom][index][help] */
185 const struct ldb_parse_tree *tree,
186 const struct ldb_val value)
187 {
188 const struct ldb_attrib_handler *h;
189 struct ldb_val val;
190 struct ldb_val cnk;
191 struct ldb_val *chunk;
192 char *p, *g;
193 uint8_t *save_p = NULL;
194 int c = 0;
195
196 h = ldb_attrib_handler(ldb, tree->u.substring.attr);
197
198 if(h->canonicalise_fn(ldb, ldb, &value, &val) != 0)
199 return -1;
200
201 save_p = val.data;
202 cnk.data = NULL;
203
204 if ( ! tree->u.substring.start_with_wildcard ) {
205
206 chunk = tree->u.substring.chunks[c];
207 if(h->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto failed;
208
209 /* This deals with wildcard prefix searches on binary attributes (eg objectGUID) */
210 if (cnk.length > val.length) {
211 goto failed;
212 }
213 if (memcmp((char *)val.data, (char *)cnk.data, cnk.length) != 0) goto failed;
214 val.length -= cnk.length;
215 val.data += cnk.length;
216 c++;
217 talloc_free(cnk.data);
218 cnk.data = NULL;
219 }
220
221 while (tree->u.substring.chunks[c]) {
222
223 chunk = tree->u.substring.chunks[c];
224 if(h->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto failed;
225
226 /* FIXME: case of embedded nulls */
227 p = strstr((char *)val.data, (char *)cnk.data);
228 if (p == NULL) goto failed;
229 if ( (! tree->u.substring.chunks[c + 1]) && (! tree->u.substring.end_with_wildcard) ) {
230 do { /* greedy */
231 g = strstr((char *)p + cnk.length, (char *)cnk.data);
232 if (g) p = g;
233 } while(g);
234 }
235 val.length = val.length - (p - (char *)(val.data)) - cnk.length;
236 val.data = (uint8_t *)(p + cnk.length);
237 c++;
238 talloc_free(cnk.data);
239 cnk.data = NULL;
240 }
241
242 if ( (! tree->u.substring.end_with_wildcard) && (*(val.data) != 0) ) goto failed; /* last chunk have not reached end of string */
243 talloc_free(save_p);
244 return 1;
245
246 failed:
247 talloc_free(save_p);
248 talloc_free(cnk.data);
249 return 0;
250 }
251
252 /*
253 match a simple leaf node
254 */
255 static int ldb_match_substring(struct ldb_context *ldb,
/* [<][>][^][v][top][bottom][index][help] */
256 const struct ldb_message *msg,
257 const struct ldb_parse_tree *tree,
258 enum ldb_scope scope)
259 {
260 unsigned int i;
261 struct ldb_message_element *el;
262
263 el = ldb_msg_find_element(msg, tree->u.substring.attr);
264 if (el == NULL) {
265 return 0;
266 }
267
268 for (i = 0; i < el->num_values; i++) {
269 if (ldb_wildcard_compare(ldb, tree, el->values[i]) == 1) {
270 return 1;
271 }
272 }
273
274 return 0;
275 }
276
277
278 /*
279 bitwise-and comparator
280 */
281 static int ldb_comparator_and(const struct ldb_val *v1, const struct ldb_val *v2)
/* [<][>][^][v][top][bottom][index][help] */
282 {
283 uint64_t i1, i2;
284 i1 = strtoull((char *)v1->data, NULL, 0);
285 i2 = strtoull((char *)v2->data, NULL, 0);
286 return ((i1 & i2) == i2);
287 }
288
289 /*
290 bitwise-or comparator
291 */
292 static int ldb_comparator_or(const struct ldb_val *v1, const struct ldb_val *v2)
/* [<][>][^][v][top][bottom][index][help] */
293 {
294 uint64_t i1, i2;
295 i1 = strtoull((char *)v1->data, NULL, 0);
296 i2 = strtoull((char *)v2->data, NULL, 0);
297 return ((i1 & i2) != 0);
298 }
299
300
301 /*
302 extended match, handles things like bitops
303 */
304 static int ldb_match_extended(struct ldb_context *ldb,
/* [<][>][^][v][top][bottom][index][help] */
305 const struct ldb_message *msg,
306 const struct ldb_parse_tree *tree,
307 enum ldb_scope scope)
308 {
309 int i;
310 const struct {
311 const char *oid;
312 int (*comparator)(const struct ldb_val *, const struct ldb_val *);
313 } rules[] = {
314 { LDB_OID_COMPARATOR_AND, ldb_comparator_and},
315 { LDB_OID_COMPARATOR_OR, ldb_comparator_or}
316 };
317 int (*comp)(const struct ldb_val *, const struct ldb_val *) = NULL;
318 struct ldb_message_element *el;
319
320 if (tree->u.extended.dnAttributes) {
321 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: dnAttributes extended match not supported yet");
322 return -1;
323 }
324 if (tree->u.extended.rule_id == NULL) {
325 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-rule extended matches not supported yet");
326 return -1;
327 }
328 if (tree->u.extended.attr == NULL) {
329 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-attribute extended matches not supported yet");
330 return -1;
331 }
332
333 for (i=0;i<ARRAY_SIZE(rules);i++) {
334 if (strcmp(rules[i].oid, tree->u.extended.rule_id) == 0) {
335 comp = rules[i].comparator;
336 break;
337 }
338 }
339 if (comp == NULL) {
340 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: unknown extended rule_id %s\n",
341 tree->u.extended.rule_id);
342 return -1;
343 }
344
345 /* find the message element */
346 el = ldb_msg_find_element(msg, tree->u.extended.attr);
347 if (el == NULL) {
348 return 0;
349 }
350
351 for (i=0;i<el->num_values;i++) {
352 int ret = comp(&el->values[i], &tree->u.extended.value);
353 if (ret == -1 || ret == 1) return ret;
354 }
355
356 return 0;
357 }
358
359 /*
360 return 0 if the given parse tree matches the given message. Assumes
361 the message is in sorted order
362
363 return 1 if it matches, and 0 if it doesn't match
364
365 this is a recursive function, and does short-circuit evaluation
366 */
367 static int ldb_match_message(struct ldb_context *ldb,
/* [<][>][^][v][top][bottom][index][help] */
368 const struct ldb_message *msg,
369 const struct ldb_parse_tree *tree,
370 enum ldb_scope scope)
371 {
372 unsigned int i;
373 int v;
374
375 switch (tree->operation) {
376 case LDB_OP_AND:
377 for (i=0;i<tree->u.list.num_elements;i++) {
378 v = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope);
379 if (!v) return 0;
380 }
381 return 1;
382
383 case LDB_OP_OR:
384 for (i=0;i<tree->u.list.num_elements;i++) {
385 v = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope);
386 if (v) return 1;
387 }
388 return 0;
389
390 case LDB_OP_NOT:
391 return ! ldb_match_message(ldb, msg, tree->u.isnot.child, scope);
392
393 case LDB_OP_EQUALITY:
394 return ldb_match_equality(ldb, msg, tree, scope);
395
396 case LDB_OP_SUBSTRING:
397 return ldb_match_substring(ldb, msg, tree, scope);
398
399 case LDB_OP_GREATER:
400 return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_GREATER);
401
402 case LDB_OP_LESS:
403 return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_LESS);
404
405 case LDB_OP_PRESENT:
406 return ldb_match_present(ldb, msg, tree, scope);
407
408 case LDB_OP_APPROX:
409 return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_APPROX);
410
411 case LDB_OP_EXTENDED:
412 return ldb_match_extended(ldb, msg, tree, scope);
413
414 }
415
416 return 0;
417 }
418
419 int ldb_match_msg(struct ldb_context *ldb,
/* [<][>][^][v][top][bottom][index][help] */
420 const struct ldb_message *msg,
421 const struct ldb_parse_tree *tree,
422 const struct ldb_dn *base,
423 enum ldb_scope scope)
424 {
425 if ( ! ldb_match_scope(ldb, base, msg->dn, scope) ) {
426 return 0;
427 }
428
429 return ldb_match_message(ldb, msg, tree, scope);
430 }