ldb: Allow to register extended match rules
[obnox/samba/samba-obnox.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 #include "dlinklist.h"
37
38 /*
39   check if the scope matches in a search result
40 */
41 static int ldb_match_scope(struct ldb_context *ldb,
42                            struct ldb_dn *base,
43                            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(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(base, dn) == 0) {
62                                 ret = 1;
63                         }
64                 }
65                 break;
66                 
67         case LDB_SCOPE_SUBTREE:
68         default:
69                 if (ldb_dn_compare_base(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, 
83                              const struct ldb_message *msg,
84                              const struct ldb_parse_tree *tree,
85                              enum ldb_scope scope, bool *matched)
86 {
87         const struct ldb_schema_attribute *a;
88         struct ldb_message_element *el;
89
90         if (ldb_attr_dn(tree->u.present.attr) == 0) {
91                 *matched = true;
92                 return LDB_SUCCESS;
93         }
94
95         el = ldb_msg_find_element(msg, tree->u.present.attr);
96         if (el == NULL) {
97                 *matched = false;
98                 return LDB_SUCCESS;
99         }
100
101         a = ldb_schema_attribute_by_name(ldb, el->name);
102         if (!a) {
103                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
104         }
105
106         if (a->syntax->operator_fn) {
107                 unsigned int i;
108                 for (i = 0; i < el->num_values; i++) {
109                         int ret = a->syntax->operator_fn(ldb, LDB_OP_PRESENT, a, &el->values[i], NULL, matched);
110                         if (ret != LDB_SUCCESS) return ret;
111                         if (*matched) return LDB_SUCCESS;
112                 }
113                 *matched = false;
114                 return LDB_SUCCESS;
115         }
116
117         *matched = true;
118         return LDB_SUCCESS;
119 }
120
121 static int ldb_match_comparison(struct ldb_context *ldb, 
122                                 const struct ldb_message *msg,
123                                 const struct ldb_parse_tree *tree,
124                                 enum ldb_scope scope,
125                                 enum ldb_parse_op comp_op, bool *matched)
126 {
127         unsigned int i;
128         struct ldb_message_element *el;
129         const struct ldb_schema_attribute *a;
130
131         /* FIXME: APPROX comparison not handled yet */
132         if (comp_op == LDB_OP_APPROX) {
133                 return LDB_ERR_INAPPROPRIATE_MATCHING;
134         }
135
136         el = ldb_msg_find_element(msg, tree->u.comparison.attr);
137         if (el == NULL) {
138                 *matched = false;
139                 return LDB_SUCCESS;
140         }
141
142         a = ldb_schema_attribute_by_name(ldb, el->name);
143         if (!a) {
144                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
145         }
146
147         for (i = 0; i < el->num_values; i++) {
148                 if (a->syntax->operator_fn) {
149                         int ret;
150                         ret = a->syntax->operator_fn(ldb, comp_op, a, &el->values[i], &tree->u.comparison.value, matched);
151                         if (ret != LDB_SUCCESS) return ret;
152                         if (*matched) return LDB_SUCCESS;
153                 } else {
154                         int ret = a->syntax->comparison_fn(ldb, ldb, &el->values[i], &tree->u.comparison.value);
155
156                         if (ret == 0) {
157                                 *matched = true;
158                                 return LDB_SUCCESS;
159                         }
160                         if (ret > 0 && comp_op == LDB_OP_GREATER) {
161                                 *matched = true;
162                                 return LDB_SUCCESS;
163                         }
164                         if (ret < 0 && comp_op == LDB_OP_LESS) {
165                                 *matched = true;
166                                 return LDB_SUCCESS;
167                         }
168                 }
169         }
170
171         *matched = false;
172         return LDB_SUCCESS;
173 }
174
175 /*
176   match a simple leaf node
177 */
178 static int ldb_match_equality(struct ldb_context *ldb, 
179                               const struct ldb_message *msg,
180                               const struct ldb_parse_tree *tree,
181                               enum ldb_scope scope,
182                               bool *matched)
183 {
184         unsigned int i;
185         struct ldb_message_element *el;
186         const struct ldb_schema_attribute *a;
187         struct ldb_dn *valuedn;
188         int ret;
189
190         if (ldb_attr_dn(tree->u.equality.attr) == 0) {
191                 valuedn = ldb_dn_from_ldb_val(ldb, ldb, &tree->u.equality.value);
192                 if (valuedn == NULL) {
193                         return LDB_ERR_INVALID_DN_SYNTAX;
194                 }
195
196                 ret = ldb_dn_compare(msg->dn, valuedn);
197
198                 talloc_free(valuedn);
199
200                 *matched = (ret == 0);
201                 return LDB_SUCCESS;
202         }
203
204         /* TODO: handle the "*" case derived from an extended search
205            operation without the attibute type defined */
206         el = ldb_msg_find_element(msg, tree->u.equality.attr);
207         if (el == NULL) {
208                 *matched = false;
209                 return LDB_SUCCESS;
210         }
211
212         a = ldb_schema_attribute_by_name(ldb, el->name);
213         if (a == NULL) {
214                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
215         }
216
217         for (i=0;i<el->num_values;i++) {
218                 if (a->syntax->operator_fn) {
219                         ret = a->syntax->operator_fn(ldb, LDB_OP_EQUALITY, a,
220                                                      &tree->u.equality.value, &el->values[i], matched);
221                         if (ret != LDB_SUCCESS) return ret;
222                         if (*matched) return LDB_SUCCESS;
223                 } else {
224                         if (a->syntax->comparison_fn(ldb, ldb, &tree->u.equality.value,
225                                                      &el->values[i]) == 0) {
226                                 *matched = true;
227                                 return LDB_SUCCESS;
228                         }
229                 }
230         }
231
232         *matched = false;
233         return LDB_SUCCESS;
234 }
235
236 static int ldb_wildcard_compare(struct ldb_context *ldb,
237                                 const struct ldb_parse_tree *tree,
238                                 const struct ldb_val value, bool *matched)
239 {
240         const struct ldb_schema_attribute *a;
241         struct ldb_val val;
242         struct ldb_val cnk;
243         struct ldb_val *chunk;
244         char *p, *g;
245         uint8_t *save_p = NULL;
246         unsigned int c = 0;
247
248         a = ldb_schema_attribute_by_name(ldb, tree->u.substring.attr);
249         if (!a) {
250                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
251         }
252
253         if (tree->u.substring.chunks == NULL) {
254                 *matched = false;
255                 return LDB_SUCCESS;
256         }
257
258         if (a->syntax->canonicalise_fn(ldb, ldb, &value, &val) != 0) {
259                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
260         }
261
262         save_p = val.data;
263         cnk.data = NULL;
264
265         if ( ! tree->u.substring.start_with_wildcard ) {
266
267                 chunk = tree->u.substring.chunks[c];
268                 if (a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto mismatch;
269
270                 /* This deals with wildcard prefix searches on binary attributes (eg objectGUID) */
271                 if (cnk.length > val.length) {
272                         goto mismatch;
273                 }
274                 if (memcmp((char *)val.data, (char *)cnk.data, cnk.length) != 0) goto mismatch;
275                 val.length -= cnk.length;
276                 val.data += cnk.length;
277                 c++;
278                 talloc_free(cnk.data);
279                 cnk.data = NULL;
280         }
281
282         while (tree->u.substring.chunks[c]) {
283
284                 chunk = tree->u.substring.chunks[c];
285                 if(a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto mismatch;
286
287                 /* FIXME: case of embedded nulls */
288                 p = strstr((char *)val.data, (char *)cnk.data);
289                 if (p == NULL) goto mismatch;
290                 if ( (! tree->u.substring.chunks[c + 1]) && (! tree->u.substring.end_with_wildcard) ) {
291                         do { /* greedy */
292                                 g = strstr((char *)p + cnk.length, (char *)cnk.data);
293                                 if (g) p = g;
294                         } while(g);
295                 }
296                 val.length = val.length - (p - (char *)(val.data)) - cnk.length;
297                 val.data = (uint8_t *)(p + cnk.length);
298                 c++;
299                 talloc_free(cnk.data);
300                 cnk.data = NULL;
301         }
302
303         /* last chunk may not have reached end of string */
304         if ( (! tree->u.substring.end_with_wildcard) && (*(val.data) != 0) ) goto mismatch;
305         talloc_free(save_p);
306         *matched = true;
307         return LDB_SUCCESS;
308
309 mismatch:
310         *matched = false;
311         talloc_free(save_p);
312         talloc_free(cnk.data);
313         return LDB_SUCCESS;
314 }
315
316 /*
317   match a simple leaf node
318 */
319 static int ldb_match_substring(struct ldb_context *ldb, 
320                                const struct ldb_message *msg,
321                                const struct ldb_parse_tree *tree,
322                                enum ldb_scope scope, bool *matched)
323 {
324         unsigned int i;
325         struct ldb_message_element *el;
326
327         el = ldb_msg_find_element(msg, tree->u.substring.attr);
328         if (el == NULL) {
329                 *matched = false;
330                 return LDB_SUCCESS;
331         }
332
333         for (i = 0; i < el->num_values; i++) {
334                 int ret;
335                 ret = ldb_wildcard_compare(ldb, tree, el->values[i], matched);
336                 if (ret != LDB_SUCCESS) return ret;
337                 if (*matched) return LDB_SUCCESS;
338         }
339
340         *matched = false;
341         return LDB_SUCCESS;
342 }
343
344
345 /*
346   bitwise and/or comparator depending on oid
347 */
348 static int ldb_comparator_bitmask(const char *oid, const struct ldb_val *v1, const struct ldb_val *v2,
349                                   bool *matched)
350 {
351         uint64_t i1, i2;
352         char ibuf[100];
353         char *endptr = NULL;
354
355         if (v1->length >= sizeof(ibuf)-1) {
356                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
357         }
358         memcpy(ibuf, (char *)v1->data, v1->length);
359         ibuf[v1->length] = 0;
360         i1 = strtoull(ibuf, &endptr, 0);
361         if (endptr != NULL) {
362                 if (endptr == ibuf || *endptr != 0) {
363                         return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
364                 }
365         }
366
367         if (v2->length >= sizeof(ibuf)-1) {
368                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
369         }
370         endptr = NULL;
371         memcpy(ibuf, (char *)v2->data, v2->length);
372         ibuf[v2->length] = 0;
373         i2 = strtoull(ibuf, &endptr, 0);
374         if (endptr != NULL) {
375                 if (endptr == ibuf || *endptr != 0) {
376                         return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
377                 }
378         }
379         if (strcmp(LDB_OID_COMPARATOR_AND, oid) == 0) {
380                 *matched = ((i1 & i2) == i2);
381         } else if (strcmp(LDB_OID_COMPARATOR_OR, oid) == 0) {
382                 *matched = ((i1 & i2) != 0);
383         } else {
384                 return LDB_ERR_INAPPROPRIATE_MATCHING;
385         }
386         return LDB_SUCCESS;
387 }
388
389 static int ldb_match_bitmask(struct ldb_context *ldb,
390                              const char *oid,
391                              const struct ldb_message *msg,
392                              const char *attribute_to_match,
393                              const struct ldb_val *value_to_match,
394                              bool *matched)
395 {
396         unsigned int i;
397         struct ldb_message_element *el;
398
399         /* find the message element */
400         el = ldb_msg_find_element(msg, attribute_to_match);
401         if (el == NULL) {
402                 *matched = false;
403                 return LDB_SUCCESS;
404         }
405
406         for (i=0;i<el->num_values;i++) {
407                 int ret;
408                 struct ldb_val *v = &el->values[i];
409
410                 ret = ldb_comparator_bitmask(oid, v, value_to_match, matched);
411                 if (ret != LDB_SUCCESS) {
412                         return ret;
413                 }
414                 if (*matched) {
415                         return LDB_SUCCESS;
416                 }
417         }
418
419         *matched = false;
420         return LDB_SUCCESS;
421 }
422
423 /*
424   always return false
425 */
426 static int ldb_comparator_false(struct ldb_context *ldb,
427                                 const char *oid,
428                                 const struct ldb_message *msg,
429                                 const char *attribute_to_match,
430                                 const struct ldb_val *value_to_match,
431                                 bool *matched)
432 {
433         *matched = false;
434         return LDB_SUCCESS;
435 }
436
437
438 static const struct ldb_extended_match_rule *ldb_find_extended_match_rule(struct ldb_context *ldb,
439                                                                           const char *oid)
440 {
441         struct ldb_extended_match_entry *extended_match_rule;
442
443         for (extended_match_rule = ldb->extended_match_rules;
444              extended_match_rule;
445              extended_match_rule = extended_match_rule->next) {
446                 if (strcmp(extended_match_rule->rule->oid, oid) == 0) {
447                         return extended_match_rule->rule;
448                 }
449         }
450
451         return NULL;
452 }
453
454
455 /*
456   extended match, handles things like bitops
457 */
458 static int ldb_match_extended(struct ldb_context *ldb, 
459                               const struct ldb_message *msg,
460                               const struct ldb_parse_tree *tree,
461                               enum ldb_scope scope, bool *matched)
462 {
463         const struct ldb_extended_match_rule *rule;
464
465         if (tree->u.extended.dnAttributes) {
466                 /* FIXME: We really need to find out what this ":dn" part in
467                  * an extended match means and how to handle it. For now print
468                  * only a warning to have s3 winbind and other tools working
469                  * against us. - Matthias */
470                 ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb: dnAttributes extended match not supported yet");
471         }
472         if (tree->u.extended.rule_id == NULL) {
473                 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-rule extended matches not supported yet");
474                 return LDB_ERR_INAPPROPRIATE_MATCHING;
475         }
476         if (tree->u.extended.attr == NULL) {
477                 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-attribute extended matches not supported yet");
478                 return LDB_ERR_INAPPROPRIATE_MATCHING;
479         }
480
481         rule = ldb_find_extended_match_rule(ldb, tree->u.extended.rule_id);
482         if (rule == NULL) {
483                 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: unknown extended rule_id %s",
484                           tree->u.extended.rule_id);
485                 return LDB_ERR_INAPPROPRIATE_MATCHING;
486         }
487
488         return rule->callback(ldb, rule->oid, msg,
489                               tree->u.extended.attr,
490                               &tree->u.extended.value, matched);
491 }
492
493 /*
494   return 0 if the given parse tree matches the given message. Assumes
495   the message is in sorted order
496
497   return 1 if it matches, and 0 if it doesn't match
498
499   this is a recursive function, and does short-circuit evaluation
500  */
501 static int ldb_match_message(struct ldb_context *ldb, 
502                              const struct ldb_message *msg,
503                              const struct ldb_parse_tree *tree,
504                              enum ldb_scope scope, bool *matched)
505 {
506         unsigned int i;
507         int ret;
508
509         *matched = false;
510
511         if (scope != LDB_SCOPE_BASE && ldb_dn_is_special(msg->dn)) {
512                 /* don't match special records except on base searches */
513                 return LDB_SUCCESS;
514         }
515
516         switch (tree->operation) {
517         case LDB_OP_AND:
518                 for (i=0;i<tree->u.list.num_elements;i++) {
519                         ret = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope, matched);
520                         if (ret != LDB_SUCCESS) return ret;
521                         if (!*matched) return LDB_SUCCESS;
522                 }
523                 *matched = true;
524                 return LDB_SUCCESS;
525
526         case LDB_OP_OR:
527                 for (i=0;i<tree->u.list.num_elements;i++) {
528                         ret = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope, matched);
529                         if (ret != LDB_SUCCESS) return ret;
530                         if (*matched) return LDB_SUCCESS;
531                 }
532                 *matched = false;
533                 return LDB_SUCCESS;
534
535         case LDB_OP_NOT:
536                 ret = ldb_match_message(ldb, msg, tree->u.isnot.child, scope, matched);
537                 if (ret != LDB_SUCCESS) return ret;
538                 *matched = ! *matched;
539                 return LDB_SUCCESS;
540
541         case LDB_OP_EQUALITY:
542                 return ldb_match_equality(ldb, msg, tree, scope, matched);
543
544         case LDB_OP_SUBSTRING:
545                 return ldb_match_substring(ldb, msg, tree, scope, matched);
546
547         case LDB_OP_GREATER:
548                 return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_GREATER, matched);
549
550         case LDB_OP_LESS:
551                 return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_LESS, matched);
552
553         case LDB_OP_PRESENT:
554                 return ldb_match_present(ldb, msg, tree, scope, matched);
555
556         case LDB_OP_APPROX:
557                 return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_APPROX, matched);
558
559         case LDB_OP_EXTENDED:
560                 return ldb_match_extended(ldb, msg, tree, scope, matched);
561         }
562
563         return LDB_ERR_INAPPROPRIATE_MATCHING;
564 }
565
566 int ldb_match_msg(struct ldb_context *ldb,
567                   const struct ldb_message *msg,
568                   const struct ldb_parse_tree *tree,
569                   struct ldb_dn *base,
570                   enum ldb_scope scope)
571 {
572         bool matched;
573         int ret;
574
575         if ( ! ldb_match_scope(ldb, base, msg->dn, scope) ) {
576                 return 0;
577         }
578
579         ret = ldb_match_message(ldb, msg, tree, scope, &matched);
580         if (ret != LDB_SUCCESS) {
581                 /* to match the old API, we need to consider this a
582                    failure to match */
583                 return 0;
584         }
585         return matched?1:0;
586 }
587
588 int ldb_match_msg_error(struct ldb_context *ldb,
589                         const struct ldb_message *msg,
590                         const struct ldb_parse_tree *tree,
591                         struct ldb_dn *base,
592                         enum ldb_scope scope,
593                         bool *matched)
594 {
595         if ( ! ldb_match_scope(ldb, base, msg->dn, scope) ) {
596                 *matched = false;
597                 return LDB_SUCCESS;
598         }
599
600         return ldb_match_message(ldb, msg, tree, scope, matched);
601 }
602
603 int ldb_match_msg_objectclass(const struct ldb_message *msg,
604                               const char *objectclass)
605 {
606         unsigned int i;
607         struct ldb_message_element *el = ldb_msg_find_element(msg, "objectClass");
608         if (!el) {
609                 return 0;
610         }
611         for (i=0; i < el->num_values; i++) {
612                 if (ldb_attr_cmp((const char *)el->values[i].data, objectclass) == 0) {
613                         return 1;
614                 }
615         }
616         return 0;
617 }
618
619 _PRIVATE_ int ldb_register_extended_match_rules(struct ldb_context *ldb)
620 {
621         struct ldb_extended_match_rule *bitmask_and;
622         struct ldb_extended_match_rule *bitmask_or;
623         struct ldb_extended_match_rule *always_false;
624         int ret;
625
626         /* Register bitmask-and match */
627         bitmask_and = talloc_zero(ldb, struct ldb_extended_match_rule);
628         if (bitmask_and == NULL) {
629                 return LDB_ERR_OPERATIONS_ERROR;
630         }
631
632         bitmask_and->oid = LDB_OID_COMPARATOR_AND;
633         bitmask_and->callback = ldb_match_bitmask;
634
635         ret = ldb_register_extended_match_rule(ldb, bitmask_and);
636         if (ret != LDB_SUCCESS) {
637                 return ret;
638         }
639
640         /* Register bitmask-or match */
641         bitmask_or = talloc_zero(ldb, struct ldb_extended_match_rule);
642         if (bitmask_or == NULL) {
643                 return LDB_ERR_OPERATIONS_ERROR;
644         }
645
646         bitmask_or->oid = LDB_OID_COMPARATOR_OR;
647         bitmask_or->callback = ldb_match_bitmask;
648
649         ret = ldb_register_extended_match_rule(ldb, bitmask_or);
650         if (ret != LDB_SUCCESS) {
651                 return ret;
652         }
653
654         /* Register always-false match */
655         always_false = talloc_zero(ldb, struct ldb_extended_match_rule);
656         if (always_false == NULL) {
657                 return LDB_ERR_OPERATIONS_ERROR;
658         }
659
660         always_false->oid = SAMBA_LDAP_MATCH_ALWAYS_FALSE;
661         always_false->callback = ldb_comparator_false;
662
663         ret = ldb_register_extended_match_rule(ldb, always_false);
664         if (ret != LDB_SUCCESS) {
665                 return ret;
666         }
667
668         return LDB_SUCCESS;
669 }
670
671 /*
672   register a new ldb backend
673
674   if override is true, then override any existing backend for this prefix
675 */
676 int ldb_register_extended_match_rule(struct ldb_context *ldb,
677                                      const struct ldb_extended_match_rule *rule)
678 {
679         const struct ldb_extended_match_rule *lookup_rule;
680         struct ldb_extended_match_entry *entry;
681
682         lookup_rule = ldb_find_extended_match_rule(ldb, rule->oid);
683         if (lookup_rule) {
684                 return LDB_ERR_ENTRY_ALREADY_EXISTS;
685         }
686
687         entry = talloc_zero(ldb, struct ldb_extended_match_entry);
688         if (!entry) {
689                 return LDB_ERR_OPERATIONS_ERROR;
690         }
691         entry->rule = rule;
692         DLIST_ADD_END(ldb->extended_match_rules, entry, struct ldb_extended_match_entry);
693
694         return LDB_SUCCESS;
695 }
696