LATER ldb: Use ldb_dn_compare_base_one in ldb_match_scope
[metze/samba/wip.git] / lib / ldb / common / ldb_match.c
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
37 /*
38   check if the scope matches in a search result
39 */
40 static int ldb_match_scope(struct ldb_context *ldb,
41                            struct ldb_dn *base,
42                            struct ldb_dn *dn,
43                            enum ldb_scope scope)
44 {
45         int ret = 0;
46
47         if (base == NULL || dn == NULL) {
48                 return 1;
49         }
50
51         switch (scope) {
52         case LDB_SCOPE_BASE:
53                 if (ldb_dn_compare(base, dn) == 0) {
54                         ret = 1;
55                 }
56                 break;
57
58         case LDB_SCOPE_ONELEVEL:
59                 /*
60                  * We used to check the number of components
61                  * so that we don't call ldb_dn_compare_base if
62                  * dn->comp_num != base->comp_num + 1
63                  * But ldb_dn_get_comp_num(dn) will first explode the DN
64                  * if it's not already exploded. Exploding is expensive.
65                  * This function is mainly used in indexes where DNs are not
66                  * exploded yet (it's just linearized strings).
67                  * ldb_dn_compare_base/ldb_dn_compare_base_one have a fast track
68                  * for comparing just linearized strings, so let's take
69                  * advantage of this.
70                  */
71                 if (ldb_dn_compare_base_one(base, dn) == 0)
72                 {
73                         ret = 1;
74                 }
75                 break;
76                 
77         case LDB_SCOPE_SUBTREE:
78         default:
79                 if (ldb_dn_compare_base(base, dn) == 0) {
80                         ret = 1;
81                 }
82                 break;
83         }
84
85         return ret;
86 }
87
88
89 /*
90   match if node is present
91 */
92 static int ldb_match_present(struct ldb_context *ldb, 
93                              const struct ldb_message *msg,
94                              const struct ldb_parse_tree *tree,
95                              enum ldb_scope scope, bool *matched)
96 {
97         const struct ldb_schema_attribute *a;
98         struct ldb_message_element *el;
99
100         if (ldb_attr_dn(tree->u.present.attr) == 0) {
101                 *matched = true;
102                 return LDB_SUCCESS;
103         }
104
105         el = ldb_msg_find_element(msg, tree->u.present.attr);
106         if (el == NULL) {
107                 *matched = false;
108                 return LDB_SUCCESS;
109         }
110
111         a = ldb_schema_attribute_by_name(ldb, el->name);
112         if (!a) {
113                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
114         }
115
116         if (a->syntax->operator_fn) {
117                 unsigned int i;
118                 for (i = 0; i < el->num_values; i++) {
119                         int ret = a->syntax->operator_fn(ldb, LDB_OP_PRESENT, a, &el->values[i], NULL, matched);
120                         if (ret != LDB_SUCCESS) return ret;
121                         if (*matched) return LDB_SUCCESS;
122                 }
123                 *matched = false;
124                 return LDB_SUCCESS;
125         }
126
127         *matched = true;
128         return LDB_SUCCESS;
129 }
130
131 static int ldb_match_comparison(struct ldb_context *ldb, 
132                                 const struct ldb_message *msg,
133                                 const struct ldb_parse_tree *tree,
134                                 enum ldb_scope scope,
135                                 enum ldb_parse_op comp_op, bool *matched)
136 {
137         unsigned int i;
138         struct ldb_message_element *el;
139         const struct ldb_schema_attribute *a;
140
141         /* FIXME: APPROX comparison not handled yet */
142         if (comp_op == LDB_OP_APPROX) {
143                 return LDB_ERR_INAPPROPRIATE_MATCHING;
144         }
145
146         el = ldb_msg_find_element(msg, tree->u.comparison.attr);
147         if (el == NULL) {
148                 *matched = false;
149                 return LDB_SUCCESS;
150         }
151
152         a = ldb_schema_attribute_by_name(ldb, el->name);
153         if (!a) {
154                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
155         }
156
157         for (i = 0; i < el->num_values; i++) {
158                 if (a->syntax->operator_fn) {
159                         int ret;
160                         ret = a->syntax->operator_fn(ldb, comp_op, a, &el->values[i], &tree->u.comparison.value, matched);
161                         if (ret != LDB_SUCCESS) return ret;
162                         if (*matched) return LDB_SUCCESS;
163                 } else {
164                         int ret = a->syntax->comparison_fn(ldb, ldb, &el->values[i], &tree->u.comparison.value);
165
166                         if (ret == 0) {
167                                 *matched = true;
168                                 return LDB_SUCCESS;
169                         }
170                         if (ret > 0 && comp_op == LDB_OP_GREATER) {
171                                 *matched = true;
172                                 return LDB_SUCCESS;
173                         }
174                         if (ret < 0 && comp_op == LDB_OP_LESS) {
175                                 *matched = true;
176                                 return LDB_SUCCESS;
177                         }
178                 }
179         }
180
181         *matched = false;
182         return LDB_SUCCESS;
183 }
184
185 /*
186   match a simple leaf node
187 */
188 static int ldb_match_equality(struct ldb_context *ldb, 
189                               const struct ldb_message *msg,
190                               const struct ldb_parse_tree *tree,
191                               enum ldb_scope scope,
192                               bool *matched)
193 {
194         unsigned int i;
195         struct ldb_message_element *el;
196         const struct ldb_schema_attribute *a;
197         struct ldb_dn *valuedn;
198         int ret;
199
200         if (ldb_attr_dn(tree->u.equality.attr) == 0) {
201                 valuedn = ldb_dn_from_ldb_val(ldb, ldb, &tree->u.equality.value);
202                 if (valuedn == NULL) {
203                         return LDB_ERR_INVALID_DN_SYNTAX;
204                 }
205
206                 ret = ldb_dn_compare(msg->dn, valuedn);
207
208                 talloc_free(valuedn);
209
210                 *matched = (ret == 0);
211                 return LDB_SUCCESS;
212         }
213
214         /* TODO: handle the "*" case derived from an extended search
215            operation without the attibute type defined */
216         el = ldb_msg_find_element(msg, tree->u.equality.attr);
217         if (el == NULL) {
218                 *matched = false;
219                 return LDB_SUCCESS;
220         }
221
222         a = ldb_schema_attribute_by_name(ldb, el->name);
223         if (a == NULL) {
224                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
225         }
226
227         for (i=0;i<el->num_values;i++) {
228                 if (a->syntax->operator_fn) {
229                         ret = a->syntax->operator_fn(ldb, LDB_OP_EQUALITY, a,
230                                                      &tree->u.equality.value, &el->values[i], matched);
231                         if (ret != LDB_SUCCESS) return ret;
232                         if (*matched) return LDB_SUCCESS;
233                 } else {
234                         if (a->syntax->comparison_fn(ldb, ldb, &tree->u.equality.value,
235                                                      &el->values[i]) == 0) {
236                                 *matched = true;
237                                 return LDB_SUCCESS;
238                         }
239                 }
240         }
241
242         *matched = false;
243         return LDB_SUCCESS;
244 }
245
246 static int ldb_wildcard_compare(struct ldb_context *ldb,
247                                 const struct ldb_parse_tree *tree,
248                                 const struct ldb_val value, bool *matched)
249 {
250         const struct ldb_schema_attribute *a;
251         struct ldb_val val;
252         struct ldb_val cnk;
253         struct ldb_val *chunk;
254         char *p, *g;
255         uint8_t *save_p = NULL;
256         unsigned int c = 0;
257
258         a = ldb_schema_attribute_by_name(ldb, tree->u.substring.attr);
259         if (!a) {
260                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
261         }
262
263         if (a->syntax->canonicalise_fn(ldb, ldb, &value, &val) != 0) {
264                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
265         }
266
267         save_p = val.data;
268         cnk.data = NULL;
269
270         if ( ! tree->u.substring.start_with_wildcard ) {
271
272                 chunk = tree->u.substring.chunks[c];
273                 if (a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto mismatch;
274
275                 /* This deals with wildcard prefix searches on binary attributes (eg objectGUID) */
276                 if (cnk.length > val.length) {
277                         goto mismatch;
278                 }
279                 if (memcmp((char *)val.data, (char *)cnk.data, cnk.length) != 0) goto mismatch;
280                 val.length -= cnk.length;
281                 val.data += cnk.length;
282                 c++;
283                 talloc_free(cnk.data);
284                 cnk.data = NULL;
285         }
286
287         while (tree->u.substring.chunks[c]) {
288
289                 chunk = tree->u.substring.chunks[c];
290                 if(a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto mismatch;
291
292                 /* FIXME: case of embedded nulls */
293                 p = strstr((char *)val.data, (char *)cnk.data);
294                 if (p == NULL) goto mismatch;
295                 if ( (! tree->u.substring.chunks[c + 1]) && (! tree->u.substring.end_with_wildcard) ) {
296                         do { /* greedy */
297                                 g = strstr((char *)p + cnk.length, (char *)cnk.data);
298                                 if (g) p = g;
299                         } while(g);
300                 }
301                 val.length = val.length - (p - (char *)(val.data)) - cnk.length;
302                 val.data = (uint8_t *)(p + cnk.length);
303                 c++;
304                 talloc_free(cnk.data);
305                 cnk.data = NULL;
306         }
307
308         /* last chunk may not have reached end of string */
309         if ( (! tree->u.substring.end_with_wildcard) && (*(val.data) != 0) ) goto mismatch;
310         talloc_free(save_p);
311         *matched = true;
312         return LDB_SUCCESS;
313
314 mismatch:
315         *matched = false;
316         talloc_free(save_p);
317         talloc_free(cnk.data);
318         return LDB_SUCCESS;
319 }
320
321 /*
322   match a simple leaf node
323 */
324 static int ldb_match_substring(struct ldb_context *ldb, 
325                                const struct ldb_message *msg,
326                                const struct ldb_parse_tree *tree,
327                                enum ldb_scope scope, bool *matched)
328 {
329         unsigned int i;
330         struct ldb_message_element *el;
331
332         el = ldb_msg_find_element(msg, tree->u.substring.attr);
333         if (el == NULL) {
334                 *matched = false;
335                 return LDB_SUCCESS;
336         }
337
338         for (i = 0; i < el->num_values; i++) {
339                 int ret;
340                 ret = ldb_wildcard_compare(ldb, tree, el->values[i], matched);
341                 if (ret != LDB_SUCCESS) return ret;
342                 if (*matched) return LDB_SUCCESS;
343         }
344
345         *matched = false;
346         return LDB_SUCCESS;
347 }
348
349
350 /*
351   bitwise-and comparator
352 */
353 static int ldb_comparator_bitmask(const char *oid, const struct ldb_val *v1, const struct ldb_val *v2,
354                                   bool *matched)
355 {
356         uint64_t i1, i2;
357         char ibuf[100];
358         char *endptr = NULL;
359
360         if (v1->length >= sizeof(ibuf)-1) {
361                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
362         }
363         memcpy(ibuf, (char *)v1->data, v1->length);
364         ibuf[v1->length] = 0;
365         i1 = strtoull(ibuf, &endptr, 0);
366         if (endptr != NULL) {
367                 if (endptr == ibuf || *endptr != 0) {
368                         return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
369                 }
370         }
371
372         if (v2->length >= sizeof(ibuf)-1) {
373                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
374         }
375         endptr = NULL;
376         memcpy(ibuf, (char *)v2->data, v2->length);
377         ibuf[v2->length] = 0;
378         i2 = strtoull(ibuf, &endptr, 0);
379         if (endptr != NULL) {
380                 if (endptr == ibuf || *endptr != 0) {
381                         return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
382                 }
383         }
384         if (strcmp(LDB_OID_COMPARATOR_AND, oid) == 0) {
385                 *matched = ((i1 & i2) == i2);
386         } else if (strcmp(LDB_OID_COMPARATOR_OR, oid) == 0) {
387                 *matched = ((i1 & i2) != 0);
388         } else {
389                 return LDB_ERR_INAPPROPRIATE_MATCHING;
390         }
391         return LDB_SUCCESS;
392 }
393
394 /*
395   always return false
396 */
397 static int ldb_comparator_false(const char *oid, const struct ldb_val *v1, const struct ldb_val *v2,
398                                 bool *matched)
399 {
400         *matched = false;
401         return LDB_SUCCESS;
402 }
403
404
405 /*
406   extended match, handles things like bitops
407 */
408 static int ldb_match_extended(struct ldb_context *ldb, 
409                               const struct ldb_message *msg,
410                               const struct ldb_parse_tree *tree,
411                               enum ldb_scope scope, bool *matched)
412 {
413         unsigned int i;
414         const struct {
415                 const char *oid;
416                 int (*comparator)(const char *, const struct ldb_val *, const struct ldb_val *, bool *);
417         } rules[] = {
418                 { LDB_OID_COMPARATOR_AND, ldb_comparator_bitmask},
419                 { LDB_OID_COMPARATOR_OR, ldb_comparator_bitmask},
420                 { SAMBA_LDAP_MATCH_ALWAYS_FALSE, ldb_comparator_false}
421         };
422         int (*comp)(const char *,const struct ldb_val *, const struct ldb_val *, bool *) = NULL;
423         struct ldb_message_element *el;
424
425         if (tree->u.extended.dnAttributes) {
426                 /* FIXME: We really need to find out what this ":dn" part in
427                  * an extended match means and how to handle it. For now print
428                  * only a warning to have s3 winbind and other tools working
429                  * against us. - Matthias */
430                 ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb: dnAttributes extended match not supported yet");
431         }
432         if (tree->u.extended.rule_id == NULL) {
433                 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-rule extended matches not supported yet");
434                 return LDB_ERR_INAPPROPRIATE_MATCHING;
435         }
436         if (tree->u.extended.attr == NULL) {
437                 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-attribute extended matches not supported yet");
438                 return LDB_ERR_INAPPROPRIATE_MATCHING;
439         }
440
441         for (i=0;i<ARRAY_SIZE(rules);i++) {
442                 if (strcmp(rules[i].oid, tree->u.extended.rule_id) == 0) {
443                         comp = rules[i].comparator;
444                         break;
445                 }
446         }
447         if (comp == NULL) {
448                 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: unknown extended rule_id %s",
449                           tree->u.extended.rule_id);
450                 return LDB_ERR_INAPPROPRIATE_MATCHING;
451         }
452
453         /* find the message element */
454         el = ldb_msg_find_element(msg, tree->u.extended.attr);
455         if (el == NULL) {
456                 *matched = false;
457                 return LDB_SUCCESS;
458         }
459
460         for (i=0;i<el->num_values;i++) {
461                 int ret = comp(tree->u.extended.rule_id, &el->values[i], &tree->u.extended.value, matched);
462                 if (ret != LDB_SUCCESS) return ret;
463                 if (*matched) return LDB_SUCCESS;
464         }
465
466         *matched = false;
467         return LDB_SUCCESS;
468 }
469
470 /*
471   return 0 if the given parse tree matches the given message. Assumes
472   the message is in sorted order
473
474   return 1 if it matches, and 0 if it doesn't match
475
476   this is a recursive function, and does short-circuit evaluation
477  */
478 static int ldb_match_message(struct ldb_context *ldb, 
479                              const struct ldb_message *msg,
480                              const struct ldb_parse_tree *tree,
481                              enum ldb_scope scope, bool *matched)
482 {
483         unsigned int i;
484         int ret;
485
486         *matched = false;
487
488         if (scope != LDB_SCOPE_BASE && ldb_dn_is_special(msg->dn)) {
489                 /* don't match special records except on base searches */
490                 return LDB_SUCCESS;
491         }
492
493         switch (tree->operation) {
494         case LDB_OP_AND:
495                 for (i=0;i<tree->u.list.num_elements;i++) {
496                         ret = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope, matched);
497                         if (ret != LDB_SUCCESS) return ret;
498                         if (!*matched) return LDB_SUCCESS;
499                 }
500                 *matched = true;
501                 return LDB_SUCCESS;
502
503         case LDB_OP_OR:
504                 for (i=0;i<tree->u.list.num_elements;i++) {
505                         ret = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope, matched);
506                         if (ret != LDB_SUCCESS) return ret;
507                         if (*matched) return LDB_SUCCESS;
508                 }
509                 *matched = false;
510                 return LDB_SUCCESS;
511
512         case LDB_OP_NOT:
513                 ret = ldb_match_message(ldb, msg, tree->u.isnot.child, scope, matched);
514                 if (ret != LDB_SUCCESS) return ret;
515                 *matched = ! *matched;
516                 return LDB_SUCCESS;
517
518         case LDB_OP_EQUALITY:
519                 return ldb_match_equality(ldb, msg, tree, scope, matched);
520
521         case LDB_OP_SUBSTRING:
522                 return ldb_match_substring(ldb, msg, tree, scope, matched);
523
524         case LDB_OP_GREATER:
525                 return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_GREATER, matched);
526
527         case LDB_OP_LESS:
528                 return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_LESS, matched);
529
530         case LDB_OP_PRESENT:
531                 return ldb_match_present(ldb, msg, tree, scope, matched);
532
533         case LDB_OP_APPROX:
534                 return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_APPROX, matched);
535
536         case LDB_OP_EXTENDED:
537                 return ldb_match_extended(ldb, msg, tree, scope, matched);
538         }
539
540         return LDB_ERR_INAPPROPRIATE_MATCHING;
541 }
542
543 int ldb_match_msg(struct ldb_context *ldb,
544                   const struct ldb_message *msg,
545                   const struct ldb_parse_tree *tree,
546                   struct ldb_dn *base,
547                   enum ldb_scope scope)
548 {
549         bool matched;
550         int ret;
551
552         if ( ! ldb_match_scope(ldb, base, msg->dn, scope) ) {
553                 return 0;
554         }
555
556         ret = ldb_match_message(ldb, msg, tree, scope, &matched);
557         if (ret != LDB_SUCCESS) {
558                 /* to match the old API, we need to consider this a
559                    failure to match */
560                 return 0;
561         }
562         return matched?1:0;
563 }
564
565 int ldb_match_msg_error(struct ldb_context *ldb,
566                         const struct ldb_message *msg,
567                         const struct ldb_parse_tree *tree,
568                         struct ldb_dn *base,
569                         enum ldb_scope scope,
570                         bool *matched)
571 {
572         if ( ! ldb_match_scope(ldb, base, msg->dn, scope) ) {
573                 *matched = false;
574                 return LDB_SUCCESS;
575         }
576
577         return ldb_match_message(ldb, msg, tree, scope, matched);
578 }
579
580 int ldb_match_msg_objectclass(const struct ldb_message *msg,
581                               const char *objectclass)
582 {
583         unsigned int i;
584         struct ldb_message_element *el = ldb_msg_find_element(msg, "objectClass");
585         if (!el) {
586                 return 0;
587         }
588         for (i=0; i < el->num_values; i++) {
589                 if (ldb_attr_cmp((const char *)el->values[i].data, objectclass) == 0) {
590                         return 1;
591                 }
592         }
593         return 0;
594 }
595
596
597