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