4 Copyright (C) Andrew Tridgell 2004-2005
5 Copyright (C) Simo Sorce 2005
7 ** NOTE! The following LGPL license applies to the ldb
8 ** library. This does NOT imply that all of Samba is released
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.
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.
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/>.
28 * Component: ldb expression matching
30 * Description: ldb expression matching
32 * Author: Andrew Tridgell
35 #include "ldb_private.h"
36 #include "dlinklist.h"
39 check if the scope matches in a search result
41 static int ldb_match_scope(struct ldb_context
*ldb
,
48 if (base
== NULL
|| dn
== NULL
) {
54 if (ldb_dn_compare(base
, dn
) == 0) {
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) {
67 case LDB_SCOPE_SUBTREE
:
69 if (ldb_dn_compare_base(base
, dn
) == 0) {
80 match if node is present
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
)
87 const struct ldb_schema_attribute
*a
;
88 struct ldb_message_element
*el
;
90 if (ldb_attr_dn(tree
->u
.present
.attr
) == 0) {
95 el
= ldb_msg_find_element(msg
, tree
->u
.present
.attr
);
101 a
= ldb_schema_attribute_by_name(ldb
, el
->name
);
103 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX
;
106 if (a
->syntax
->operator_fn
) {
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
;
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
)
128 struct ldb_message_element
*el
;
129 const struct ldb_schema_attribute
*a
;
131 /* FIXME: APPROX comparison not handled yet */
132 if (comp_op
== LDB_OP_APPROX
) {
133 return LDB_ERR_INAPPROPRIATE_MATCHING
;
136 el
= ldb_msg_find_element(msg
, tree
->u
.comparison
.attr
);
142 a
= ldb_schema_attribute_by_name(ldb
, el
->name
);
144 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX
;
147 for (i
= 0; i
< el
->num_values
; i
++) {
148 if (a
->syntax
->operator_fn
) {
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
;
154 int ret
= a
->syntax
->comparison_fn(ldb
, ldb
, &el
->values
[i
], &tree
->u
.comparison
.value
);
160 if (ret
> 0 && comp_op
== LDB_OP_GREATER
) {
164 if (ret
< 0 && comp_op
== LDB_OP_LESS
) {
176 match a simple leaf node
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
,
185 struct ldb_message_element
*el
;
186 const struct ldb_schema_attribute
*a
;
187 struct ldb_dn
*valuedn
;
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
;
196 ret
= ldb_dn_compare(msg
->dn
, valuedn
);
198 talloc_free(valuedn
);
200 *matched
= (ret
== 0);
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
);
212 a
= ldb_schema_attribute_by_name(ldb
, el
->name
);
214 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX
;
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
;
224 if (a
->syntax
->comparison_fn(ldb
, ldb
, &tree
->u
.equality
.value
,
225 &el
->values
[i
]) == 0) {
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
)
240 const struct ldb_schema_attribute
*a
;
243 struct ldb_val
*chunk
;
244 uint8_t *save_p
= NULL
;
247 a
= ldb_schema_attribute_by_name(ldb
, tree
->u
.substring
.attr
);
249 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX
;
252 if (tree
->u
.substring
.chunks
== NULL
) {
257 if (a
->syntax
->canonicalise_fn(ldb
, ldb
, &value
, &val
) != 0) {
258 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX
;
264 if ( ! tree
->u
.substring
.start_with_wildcard
) {
266 chunk
= tree
->u
.substring
.chunks
[c
];
267 if (a
->syntax
->canonicalise_fn(ldb
, ldb
, chunk
, &cnk
) != 0) goto mismatch
;
269 /* This deals with wildcard prefix searches on binary attributes (eg objectGUID) */
270 if (cnk
.length
> val
.length
) {
274 * Empty strings are returned as length 0. Ensure
275 * we can cope with this.
277 if (cnk
.length
== 0) {
281 if (memcmp((char *)val
.data
, (char *)cnk
.data
, cnk
.length
) != 0) goto mismatch
;
282 val
.length
-= cnk
.length
;
283 val
.data
+= cnk
.length
;
285 talloc_free(cnk
.data
);
289 while (tree
->u
.substring
.chunks
[c
]) {
292 chunk
= tree
->u
.substring
.chunks
[c
];
293 if(a
->syntax
->canonicalise_fn(ldb
, ldb
, chunk
, &cnk
) != 0) goto mismatch
;
296 * Empty strings are returned as length 0. Ensure
297 * we can cope with this.
299 if (cnk
.length
== 0) {
303 * Values might be binary blobs. Don't use string
304 * search, but memory search instead.
306 p
= memmem((const void *)val
.data
,val
.length
,
307 (const void *)cnk
.data
, cnk
.length
);
308 if (p
== NULL
) goto mismatch
;
309 if ( (! tree
->u
.substring
.chunks
[c
+ 1]) && (! tree
->u
.substring
.end_with_wildcard
) ) {
312 g
= memmem(p
+ cnk
.length
,
313 val
.length
- (p
- val
.data
),
314 (const uint8_t *)cnk
.data
,
319 val
.length
= val
.length
- (p
- (uint8_t *)(val
.data
)) - cnk
.length
;
320 val
.data
= (uint8_t *)(p
+ cnk
.length
);
322 talloc_free(cnk
.data
);
326 /* last chunk may not have reached end of string */
327 if ( (! tree
->u
.substring
.end_with_wildcard
) && (*(val
.data
) != 0) ) goto mismatch
;
335 talloc_free(cnk
.data
);
340 match a simple leaf node
342 static int ldb_match_substring(struct ldb_context
*ldb
,
343 const struct ldb_message
*msg
,
344 const struct ldb_parse_tree
*tree
,
345 enum ldb_scope scope
, bool *matched
)
348 struct ldb_message_element
*el
;
350 el
= ldb_msg_find_element(msg
, tree
->u
.substring
.attr
);
356 for (i
= 0; i
< el
->num_values
; i
++) {
358 ret
= ldb_wildcard_compare(ldb
, tree
, el
->values
[i
], matched
);
359 if (ret
!= LDB_SUCCESS
) return ret
;
360 if (*matched
) return LDB_SUCCESS
;
369 bitwise and/or comparator depending on oid
371 static int ldb_comparator_bitmask(const char *oid
, const struct ldb_val
*v1
, const struct ldb_val
*v2
,
378 if (v1
->length
>= sizeof(ibuf
)-1) {
379 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX
;
381 memcpy(ibuf
, (char *)v1
->data
, v1
->length
);
382 ibuf
[v1
->length
] = 0;
383 i1
= strtoull(ibuf
, &endptr
, 0);
384 if (endptr
!= NULL
) {
385 if (endptr
== ibuf
|| *endptr
!= 0) {
386 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX
;
390 if (v2
->length
>= sizeof(ibuf
)-1) {
391 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX
;
394 memcpy(ibuf
, (char *)v2
->data
, v2
->length
);
395 ibuf
[v2
->length
] = 0;
396 i2
= strtoull(ibuf
, &endptr
, 0);
397 if (endptr
!= NULL
) {
398 if (endptr
== ibuf
|| *endptr
!= 0) {
399 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX
;
402 if (strcmp(LDB_OID_COMPARATOR_AND
, oid
) == 0) {
403 *matched
= ((i1
& i2
) == i2
);
404 } else if (strcmp(LDB_OID_COMPARATOR_OR
, oid
) == 0) {
405 *matched
= ((i1
& i2
) != 0);
407 return LDB_ERR_INAPPROPRIATE_MATCHING
;
412 static int ldb_match_bitmask(struct ldb_context
*ldb
,
414 const struct ldb_message
*msg
,
415 const char *attribute_to_match
,
416 const struct ldb_val
*value_to_match
,
420 struct ldb_message_element
*el
;
422 /* find the message element */
423 el
= ldb_msg_find_element(msg
, attribute_to_match
);
429 for (i
=0;i
<el
->num_values
;i
++) {
431 struct ldb_val
*v
= &el
->values
[i
];
433 ret
= ldb_comparator_bitmask(oid
, v
, value_to_match
, matched
);
434 if (ret
!= LDB_SUCCESS
) {
449 static int ldb_comparator_false(struct ldb_context
*ldb
,
451 const struct ldb_message
*msg
,
452 const char *attribute_to_match
,
453 const struct ldb_val
*value_to_match
,
461 static const struct ldb_extended_match_rule
*ldb_find_extended_match_rule(struct ldb_context
*ldb
,
464 struct ldb_extended_match_entry
*extended_match_rule
;
466 for (extended_match_rule
= ldb
->extended_match_rules
;
468 extended_match_rule
= extended_match_rule
->next
) {
469 if (strcmp(extended_match_rule
->rule
->oid
, oid
) == 0) {
470 return extended_match_rule
->rule
;
479 extended match, handles things like bitops
481 static int ldb_match_extended(struct ldb_context
*ldb
,
482 const struct ldb_message
*msg
,
483 const struct ldb_parse_tree
*tree
,
484 enum ldb_scope scope
, bool *matched
)
486 const struct ldb_extended_match_rule
*rule
;
488 if (tree
->u
.extended
.dnAttributes
) {
489 /* FIXME: We really need to find out what this ":dn" part in
490 * an extended match means and how to handle it. For now print
491 * only a warning to have s3 winbind and other tools working
492 * against us. - Matthias */
493 ldb_debug(ldb
, LDB_DEBUG_WARNING
, "ldb: dnAttributes extended match not supported yet");
495 if (tree
->u
.extended
.rule_id
== NULL
) {
496 ldb_debug(ldb
, LDB_DEBUG_ERROR
, "ldb: no-rule extended matches not supported yet");
497 return LDB_ERR_INAPPROPRIATE_MATCHING
;
499 if (tree
->u
.extended
.attr
== NULL
) {
500 ldb_debug(ldb
, LDB_DEBUG_ERROR
, "ldb: no-attribute extended matches not supported yet");
501 return LDB_ERR_INAPPROPRIATE_MATCHING
;
504 rule
= ldb_find_extended_match_rule(ldb
, tree
->u
.extended
.rule_id
);
507 ldb_debug(ldb
, LDB_DEBUG_ERROR
, "ldb: unknown extended rule_id %s",
508 tree
->u
.extended
.rule_id
);
512 return rule
->callback(ldb
, rule
->oid
, msg
,
513 tree
->u
.extended
.attr
,
514 &tree
->u
.extended
.value
, matched
);
518 return 0 if the given parse tree matches the given message. Assumes
519 the message is in sorted order
521 return 1 if it matches, and 0 if it doesn't match
523 this is a recursive function, and does short-circuit evaluation
525 static int ldb_match_message(struct ldb_context
*ldb
,
526 const struct ldb_message
*msg
,
527 const struct ldb_parse_tree
*tree
,
528 enum ldb_scope scope
, bool *matched
)
535 if (scope
!= LDB_SCOPE_BASE
&& ldb_dn_is_special(msg
->dn
)) {
536 /* don't match special records except on base searches */
540 switch (tree
->operation
) {
542 for (i
=0;i
<tree
->u
.list
.num_elements
;i
++) {
543 ret
= ldb_match_message(ldb
, msg
, tree
->u
.list
.elements
[i
], scope
, matched
);
544 if (ret
!= LDB_SUCCESS
) return ret
;
545 if (!*matched
) return LDB_SUCCESS
;
551 for (i
=0;i
<tree
->u
.list
.num_elements
;i
++) {
552 ret
= ldb_match_message(ldb
, msg
, tree
->u
.list
.elements
[i
], scope
, matched
);
553 if (ret
!= LDB_SUCCESS
) return ret
;
554 if (*matched
) return LDB_SUCCESS
;
560 ret
= ldb_match_message(ldb
, msg
, tree
->u
.isnot
.child
, scope
, matched
);
561 if (ret
!= LDB_SUCCESS
) return ret
;
562 *matched
= ! *matched
;
565 case LDB_OP_EQUALITY
:
566 return ldb_match_equality(ldb
, msg
, tree
, scope
, matched
);
568 case LDB_OP_SUBSTRING
:
569 return ldb_match_substring(ldb
, msg
, tree
, scope
, matched
);
572 return ldb_match_comparison(ldb
, msg
, tree
, scope
, LDB_OP_GREATER
, matched
);
575 return ldb_match_comparison(ldb
, msg
, tree
, scope
, LDB_OP_LESS
, matched
);
578 return ldb_match_present(ldb
, msg
, tree
, scope
, matched
);
581 return ldb_match_comparison(ldb
, msg
, tree
, scope
, LDB_OP_APPROX
, matched
);
583 case LDB_OP_EXTENDED
:
584 return ldb_match_extended(ldb
, msg
, tree
, scope
, matched
);
587 return LDB_ERR_INAPPROPRIATE_MATCHING
;
590 int ldb_match_msg(struct ldb_context
*ldb
,
591 const struct ldb_message
*msg
,
592 const struct ldb_parse_tree
*tree
,
594 enum ldb_scope scope
)
599 if ( ! ldb_match_scope(ldb
, base
, msg
->dn
, scope
) ) {
603 ret
= ldb_match_message(ldb
, msg
, tree
, scope
, &matched
);
604 if (ret
!= LDB_SUCCESS
) {
605 /* to match the old API, we need to consider this a
612 int ldb_match_msg_error(struct ldb_context
*ldb
,
613 const struct ldb_message
*msg
,
614 const struct ldb_parse_tree
*tree
,
616 enum ldb_scope scope
,
619 if ( ! ldb_match_scope(ldb
, base
, msg
->dn
, scope
) ) {
624 return ldb_match_message(ldb
, msg
, tree
, scope
, matched
);
627 int ldb_match_msg_objectclass(const struct ldb_message
*msg
,
628 const char *objectclass
)
631 struct ldb_message_element
*el
= ldb_msg_find_element(msg
, "objectClass");
635 for (i
=0; i
< el
->num_values
; i
++) {
636 if (ldb_attr_cmp((const char *)el
->values
[i
].data
, objectclass
) == 0) {
643 _PRIVATE_
int ldb_register_extended_match_rules(struct ldb_context
*ldb
)
645 struct ldb_extended_match_rule
*bitmask_and
;
646 struct ldb_extended_match_rule
*bitmask_or
;
647 struct ldb_extended_match_rule
*always_false
;
650 /* Register bitmask-and match */
651 bitmask_and
= talloc_zero(ldb
, struct ldb_extended_match_rule
);
652 if (bitmask_and
== NULL
) {
653 return LDB_ERR_OPERATIONS_ERROR
;
656 bitmask_and
->oid
= LDB_OID_COMPARATOR_AND
;
657 bitmask_and
->callback
= ldb_match_bitmask
;
659 ret
= ldb_register_extended_match_rule(ldb
, bitmask_and
);
660 if (ret
!= LDB_SUCCESS
) {
664 /* Register bitmask-or match */
665 bitmask_or
= talloc_zero(ldb
, struct ldb_extended_match_rule
);
666 if (bitmask_or
== NULL
) {
667 return LDB_ERR_OPERATIONS_ERROR
;
670 bitmask_or
->oid
= LDB_OID_COMPARATOR_OR
;
671 bitmask_or
->callback
= ldb_match_bitmask
;
673 ret
= ldb_register_extended_match_rule(ldb
, bitmask_or
);
674 if (ret
!= LDB_SUCCESS
) {
678 /* Register always-false match */
679 always_false
= talloc_zero(ldb
, struct ldb_extended_match_rule
);
680 if (always_false
== NULL
) {
681 return LDB_ERR_OPERATIONS_ERROR
;
684 always_false
->oid
= SAMBA_LDAP_MATCH_ALWAYS_FALSE
;
685 always_false
->callback
= ldb_comparator_false
;
687 ret
= ldb_register_extended_match_rule(ldb
, always_false
);
688 if (ret
!= LDB_SUCCESS
) {
696 register a new ldb backend
698 if override is true, then override any existing backend for this prefix
700 int ldb_register_extended_match_rule(struct ldb_context
*ldb
,
701 const struct ldb_extended_match_rule
*rule
)
703 const struct ldb_extended_match_rule
*lookup_rule
;
704 struct ldb_extended_match_entry
*entry
;
706 lookup_rule
= ldb_find_extended_match_rule(ldb
, rule
->oid
);
708 return LDB_ERR_ENTRY_ALREADY_EXISTS
;
711 entry
= talloc_zero(ldb
, struct ldb_extended_match_entry
);
713 return LDB_ERR_OPERATIONS_ERROR
;
716 DLIST_ADD_END(ldb
->extended_match_rules
, entry
);