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"
37 #include "ldb_handlers.h"
40 check if the scope matches in a search result
42 int ldb_match_scope(struct ldb_context
*ldb
,
49 if (base
== NULL
|| dn
== NULL
) {
55 if (ldb_dn_compare(base
, dn
) == 0) {
60 case LDB_SCOPE_ONELEVEL
:
61 if (ldb_dn_get_comp_num(dn
) == (ldb_dn_get_comp_num(base
) + 1)) {
62 if (ldb_dn_compare_base(base
, dn
) == 0) {
68 case LDB_SCOPE_SUBTREE
:
70 if (ldb_dn_compare_base(base
, dn
) == 0) {
81 match if node is present
83 static int ldb_match_present(struct ldb_context
*ldb
,
84 const struct ldb_message
*msg
,
85 const struct ldb_parse_tree
*tree
,
86 enum ldb_scope scope
, bool *matched
)
88 const struct ldb_schema_attribute
*a
;
89 struct ldb_message_element
*el
;
91 if (ldb_attr_dn(tree
->u
.present
.attr
) == 0) {
96 el
= ldb_msg_find_element(msg
, tree
->u
.present
.attr
);
102 a
= ldb_schema_attribute_by_name(ldb
, el
->name
);
104 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX
;
107 if (a
->syntax
->operator_fn
) {
109 for (i
= 0; i
< el
->num_values
; i
++) {
110 int ret
= a
->syntax
->operator_fn(ldb
, LDB_OP_PRESENT
, a
, &el
->values
[i
], NULL
, matched
);
111 if (ret
!= LDB_SUCCESS
) return ret
;
112 if (*matched
) return LDB_SUCCESS
;
122 static int ldb_match_comparison(struct ldb_context
*ldb
,
123 const struct ldb_message
*msg
,
124 const struct ldb_parse_tree
*tree
,
125 enum ldb_scope scope
,
126 enum ldb_parse_op comp_op
, bool *matched
)
129 struct ldb_message_element
*el
;
130 const struct ldb_schema_attribute
*a
;
132 /* FIXME: APPROX comparison not handled yet */
133 if (comp_op
== LDB_OP_APPROX
) {
134 return LDB_ERR_INAPPROPRIATE_MATCHING
;
137 el
= ldb_msg_find_element(msg
, tree
->u
.comparison
.attr
);
143 a
= ldb_schema_attribute_by_name(ldb
, el
->name
);
145 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX
;
148 for (i
= 0; i
< el
->num_values
; i
++) {
149 if (a
->syntax
->operator_fn
) {
151 ret
= a
->syntax
->operator_fn(ldb
, comp_op
, a
, &el
->values
[i
], &tree
->u
.comparison
.value
, matched
);
152 if (ret
!= LDB_SUCCESS
) return ret
;
153 if (*matched
) return LDB_SUCCESS
;
155 int ret
= a
->syntax
->comparison_fn(ldb
, ldb
, &el
->values
[i
], &tree
->u
.comparison
.value
);
161 if (ret
> 0 && comp_op
== LDB_OP_GREATER
) {
165 if (ret
< 0 && comp_op
== LDB_OP_LESS
) {
177 match a simple leaf node
179 static int ldb_match_equality(struct ldb_context
*ldb
,
180 const struct ldb_message
*msg
,
181 const struct ldb_parse_tree
*tree
,
182 enum ldb_scope scope
,
186 struct ldb_message_element
*el
;
187 const struct ldb_schema_attribute
*a
;
188 struct ldb_dn
*valuedn
;
191 if (ldb_attr_dn(tree
->u
.equality
.attr
) == 0) {
192 valuedn
= ldb_dn_from_ldb_val(ldb
, ldb
, &tree
->u
.equality
.value
);
193 if (valuedn
== NULL
) {
194 return LDB_ERR_INVALID_DN_SYNTAX
;
197 ret
= ldb_dn_compare(msg
->dn
, valuedn
);
199 talloc_free(valuedn
);
201 *matched
= (ret
== 0);
205 /* TODO: handle the "*" case derived from an extended search
206 operation without the attribute type defined */
207 el
= ldb_msg_find_element(msg
, tree
->u
.equality
.attr
);
213 a
= ldb_schema_attribute_by_name(ldb
, el
->name
);
215 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX
;
218 for (i
=0;i
<el
->num_values
;i
++) {
219 if (a
->syntax
->operator_fn
) {
220 ret
= a
->syntax
->operator_fn(ldb
, LDB_OP_EQUALITY
, a
,
221 &tree
->u
.equality
.value
, &el
->values
[i
], matched
);
222 if (ret
!= LDB_SUCCESS
) return ret
;
223 if (*matched
) return LDB_SUCCESS
;
225 if (a
->syntax
->comparison_fn(ldb
, ldb
, &tree
->u
.equality
.value
,
226 &el
->values
[i
]) == 0) {
237 static int ldb_wildcard_compare(struct ldb_context
*ldb
,
238 const struct ldb_parse_tree
*tree
,
239 const struct ldb_val value
, bool *matched
)
241 const struct ldb_schema_attribute
*a
;
244 struct ldb_val
*chunk
;
245 uint8_t *save_p
= NULL
;
248 if (tree
->operation
!= LDB_OP_SUBSTRING
) {
250 return LDB_ERR_INAPPROPRIATE_MATCHING
;
253 a
= ldb_schema_attribute_by_name(ldb
, tree
->u
.substring
.attr
);
255 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX
;
258 if (tree
->u
.substring
.chunks
== NULL
) {
263 /* No need to just copy this value for a binary match */
264 if (a
->syntax
->canonicalise_fn
!= ldb_handler_copy
) {
265 if (a
->syntax
->canonicalise_fn(ldb
, ldb
, &value
, &val
) != 0) {
266 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX
;
270 * Only set save_p if we allocate (call
271 * a->syntax->canonicalise_fn()), as we
272 * talloc_free(save_p) below to clean up
281 if ( ! tree
->u
.substring
.start_with_wildcard
) {
282 uint8_t *cnk_to_free
= NULL
;
284 chunk
= tree
->u
.substring
.chunks
[c
];
285 /* No need to just copy this value for a binary match */
286 if (a
->syntax
->canonicalise_fn
!= ldb_handler_copy
) {
287 if (a
->syntax
->canonicalise_fn(ldb
, ldb
, chunk
, &cnk
) != 0) {
291 cnk_to_free
= cnk
.data
;
296 /* This deals with wildcard prefix searches on binary attributes (eg objectGUID) */
297 if (cnk
.length
> val
.length
) {
298 TALLOC_FREE(cnk_to_free
);
302 * Empty strings are returned as length 0. Ensure
303 * we can cope with this.
305 if (cnk
.length
== 0) {
306 TALLOC_FREE(cnk_to_free
);
310 if (memcmp((char *)val
.data
, (char *)cnk
.data
, cnk
.length
) != 0) {
311 TALLOC_FREE(cnk_to_free
);
315 val
.length
-= cnk
.length
;
316 val
.data
+= cnk
.length
;
318 TALLOC_FREE(cnk_to_free
);
322 while (tree
->u
.substring
.chunks
[c
]) {
324 uint8_t *cnk_to_free
= NULL
;
326 chunk
= tree
->u
.substring
.chunks
[c
];
327 /* No need to just copy this value for a binary match */
328 if (a
->syntax
->canonicalise_fn
!= ldb_handler_copy
) {
329 if (a
->syntax
->canonicalise_fn(ldb
, ldb
, chunk
, &cnk
) != 0) {
333 cnk_to_free
= cnk
.data
;
338 * Empty strings are returned as length 0. Ensure
339 * we can cope with this.
341 if (cnk
.length
== 0) {
342 TALLOC_FREE(cnk_to_free
);
345 if (cnk
.length
> val
.length
) {
346 TALLOC_FREE(cnk_to_free
);
350 if ( (tree
->u
.substring
.chunks
[c
+ 1]) == NULL
&&
351 (! tree
->u
.substring
.end_with_wildcard
) ) {
353 * The last bit, after all the asterisks, must match
354 * exactly the last bit of the string.
357 p
= val
.data
+ val
.length
- cnk
.length
;
361 TALLOC_FREE(cnk_to_free
);
368 * Values might be binary blobs. Don't use string
369 * search, but memory search instead.
371 p
= memmem((const void *)val
.data
, val
.length
,
372 (const void *)cnk
.data
, cnk
.length
);
374 TALLOC_FREE(cnk_to_free
);
377 /* move val to the end of the match */
379 val
.length
-= (p
- val
.data
);
381 TALLOC_FREE(cnk_to_free
);
397 match a simple leaf node
399 static int ldb_match_substring(struct ldb_context
*ldb
,
400 const struct ldb_message
*msg
,
401 const struct ldb_parse_tree
*tree
,
402 enum ldb_scope scope
, bool *matched
)
405 struct ldb_message_element
*el
;
407 el
= ldb_msg_find_element(msg
, tree
->u
.substring
.attr
);
413 for (i
= 0; i
< el
->num_values
; i
++) {
415 ret
= ldb_wildcard_compare(ldb
, tree
, el
->values
[i
], matched
);
416 if (ret
!= LDB_SUCCESS
) return ret
;
417 if (*matched
) return LDB_SUCCESS
;
426 bitwise and/or comparator depending on oid
428 static int ldb_comparator_bitmask(const char *oid
, const struct ldb_val
*v1
, const struct ldb_val
*v2
,
435 if (v1
->length
>= sizeof(ibuf
)-1) {
436 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX
;
438 memcpy(ibuf
, (char *)v1
->data
, v1
->length
);
439 ibuf
[v1
->length
] = 0;
440 i1
= strtoull(ibuf
, &endptr
, 0);
441 if (endptr
!= NULL
) {
442 if (endptr
== ibuf
|| *endptr
!= 0) {
443 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX
;
447 if (v2
->length
>= sizeof(ibuf
)-1) {
448 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX
;
451 memcpy(ibuf
, (char *)v2
->data
, v2
->length
);
452 ibuf
[v2
->length
] = 0;
453 i2
= strtoull(ibuf
, &endptr
, 0);
454 if (endptr
!= NULL
) {
455 if (endptr
== ibuf
|| *endptr
!= 0) {
456 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX
;
459 if (strcmp(LDB_OID_COMPARATOR_AND
, oid
) == 0) {
460 *matched
= ((i1
& i2
) == i2
);
461 } else if (strcmp(LDB_OID_COMPARATOR_OR
, oid
) == 0) {
462 *matched
= ((i1
& i2
) != 0);
464 return LDB_ERR_INAPPROPRIATE_MATCHING
;
469 static int ldb_match_bitmask(struct ldb_context
*ldb
,
471 const struct ldb_message
*msg
,
472 const char *attribute_to_match
,
473 const struct ldb_val
*value_to_match
,
477 struct ldb_message_element
*el
;
479 /* find the message element */
480 el
= ldb_msg_find_element(msg
, attribute_to_match
);
486 for (i
=0;i
<el
->num_values
;i
++) {
488 struct ldb_val
*v
= &el
->values
[i
];
490 ret
= ldb_comparator_bitmask(oid
, v
, value_to_match
, matched
);
491 if (ret
!= LDB_SUCCESS
) {
506 static int ldb_comparator_false(struct ldb_context
*ldb
,
508 const struct ldb_message
*msg
,
509 const char *attribute_to_match
,
510 const struct ldb_val
*value_to_match
,
518 static const struct ldb_extended_match_rule
*ldb_find_extended_match_rule(struct ldb_context
*ldb
,
521 struct ldb_extended_match_entry
*extended_match_rule
;
523 for (extended_match_rule
= ldb
->extended_match_rules
;
525 extended_match_rule
= extended_match_rule
->next
) {
526 if (strcmp(extended_match_rule
->rule
->oid
, oid
) == 0) {
527 return extended_match_rule
->rule
;
536 extended match, handles things like bitops
538 static int ldb_match_extended(struct ldb_context
*ldb
,
539 const struct ldb_message
*msg
,
540 const struct ldb_parse_tree
*tree
,
541 enum ldb_scope scope
, bool *matched
)
543 const struct ldb_extended_match_rule
*rule
;
545 if (tree
->u
.extended
.dnAttributes
) {
546 /* FIXME: We really need to find out what this ":dn" part in
547 * an extended match means and how to handle it. For now print
548 * only a warning to have s3 winbind and other tools working
549 * against us. - Matthias */
550 ldb_debug(ldb
, LDB_DEBUG_WARNING
, "ldb: dnAttributes extended match not supported yet");
552 if (tree
->u
.extended
.rule_id
== NULL
) {
553 ldb_debug(ldb
, LDB_DEBUG_ERROR
, "ldb: no-rule extended matches not supported yet");
554 return LDB_ERR_INAPPROPRIATE_MATCHING
;
556 if (tree
->u
.extended
.attr
== NULL
) {
557 ldb_debug(ldb
, LDB_DEBUG_ERROR
, "ldb: no-attribute extended matches not supported yet");
558 return LDB_ERR_INAPPROPRIATE_MATCHING
;
561 rule
= ldb_find_extended_match_rule(ldb
, tree
->u
.extended
.rule_id
);
564 ldb_debug(ldb
, LDB_DEBUG_ERROR
, "ldb: unknown extended rule_id %s",
565 tree
->u
.extended
.rule_id
);
569 return rule
->callback(ldb
, rule
->oid
, msg
,
570 tree
->u
.extended
.attr
,
571 &tree
->u
.extended
.value
, matched
);
574 static bool ldb_must_suppress_match(const struct ldb_message
*msg
,
575 const struct ldb_parse_tree
*tree
)
577 const char *attr
= NULL
;
578 struct ldb_message_element
*el
= NULL
;
580 attr
= ldb_parse_tree_get_attr(tree
);
585 /* find the message element */
586 el
= ldb_msg_find_element(msg
, attr
);
591 return ldb_msg_element_is_inaccessible(el
);
595 Check if a particular message will match the given filter
597 set *matched to true if it matches, false otherwise
599 returns LDB_SUCCESS or an error
601 this is a recursive function, and does short-circuit evaluation
603 int ldb_match_message(struct ldb_context
*ldb
,
604 const struct ldb_message
*msg
,
605 const struct ldb_parse_tree
*tree
,
606 enum ldb_scope scope
, bool *matched
)
613 if (scope
!= LDB_SCOPE_BASE
&& ldb_dn_is_special(msg
->dn
)) {
614 /* don't match special records except on base searches */
619 * Suppress matches on confidential attributes (handled
620 * manually in extended matches as these can do custom things
621 * like read other parts of the DB or other attributes).
623 if (tree
->operation
!= LDB_OP_EXTENDED
) {
624 if (ldb_must_suppress_match(msg
, tree
)) {
629 switch (tree
->operation
) {
631 for (i
=0;i
<tree
->u
.list
.num_elements
;i
++) {
632 ret
= ldb_match_message(ldb
, msg
, tree
->u
.list
.elements
[i
], scope
, matched
);
633 if (ret
!= LDB_SUCCESS
) return ret
;
634 if (!*matched
) return LDB_SUCCESS
;
640 for (i
=0;i
<tree
->u
.list
.num_elements
;i
++) {
641 ret
= ldb_match_message(ldb
, msg
, tree
->u
.list
.elements
[i
], scope
, matched
);
642 if (ret
!= LDB_SUCCESS
) return ret
;
643 if (*matched
) return LDB_SUCCESS
;
649 ret
= ldb_match_message(ldb
, msg
, tree
->u
.isnot
.child
, scope
, matched
);
650 if (ret
!= LDB_SUCCESS
) return ret
;
651 *matched
= ! *matched
;
654 case LDB_OP_EQUALITY
:
655 return ldb_match_equality(ldb
, msg
, tree
, scope
, matched
);
657 case LDB_OP_SUBSTRING
:
658 return ldb_match_substring(ldb
, msg
, tree
, scope
, matched
);
661 return ldb_match_comparison(ldb
, msg
, tree
, scope
, LDB_OP_GREATER
, matched
);
664 return ldb_match_comparison(ldb
, msg
, tree
, scope
, LDB_OP_LESS
, matched
);
667 return ldb_match_present(ldb
, msg
, tree
, scope
, matched
);
670 return ldb_match_comparison(ldb
, msg
, tree
, scope
, LDB_OP_APPROX
, matched
);
672 case LDB_OP_EXTENDED
:
673 return ldb_match_extended(ldb
, msg
, tree
, scope
, matched
);
676 return LDB_ERR_INAPPROPRIATE_MATCHING
;
680 return 0 if the given parse tree matches the given message. Assumes
681 the message is in sorted order
683 return 1 if it matches, and 0 if it doesn't match
686 int ldb_match_msg(struct ldb_context
*ldb
,
687 const struct ldb_message
*msg
,
688 const struct ldb_parse_tree
*tree
,
690 enum ldb_scope scope
)
695 if ( ! ldb_match_scope(ldb
, base
, msg
->dn
, scope
) ) {
699 ret
= ldb_match_message(ldb
, msg
, tree
, scope
, &matched
);
700 if (ret
!= LDB_SUCCESS
) {
701 /* to match the old API, we need to consider this a
708 int ldb_match_msg_error(struct ldb_context
*ldb
,
709 const struct ldb_message
*msg
,
710 const struct ldb_parse_tree
*tree
,
712 enum ldb_scope scope
,
715 if ( ! ldb_match_scope(ldb
, base
, msg
->dn
, scope
) ) {
720 return ldb_match_message(ldb
, msg
, tree
, scope
, matched
);
723 int ldb_match_msg_objectclass(const struct ldb_message
*msg
,
724 const char *objectclass
)
727 struct ldb_message_element
*el
= ldb_msg_find_element(msg
, "objectClass");
731 for (i
=0; i
< el
->num_values
; i
++) {
732 if (ldb_attr_cmp((const char *)el
->values
[i
].data
, objectclass
) == 0) {
739 _PRIVATE_
int ldb_register_extended_match_rules(struct ldb_context
*ldb
)
741 struct ldb_extended_match_rule
*bitmask_and
;
742 struct ldb_extended_match_rule
*bitmask_or
;
743 struct ldb_extended_match_rule
*always_false
;
746 /* Register bitmask-and match */
747 bitmask_and
= talloc_zero(ldb
, struct ldb_extended_match_rule
);
748 if (bitmask_and
== NULL
) {
749 return LDB_ERR_OPERATIONS_ERROR
;
752 bitmask_and
->oid
= LDB_OID_COMPARATOR_AND
;
753 bitmask_and
->callback
= ldb_match_bitmask
;
755 ret
= ldb_register_extended_match_rule(ldb
, bitmask_and
);
756 if (ret
!= LDB_SUCCESS
) {
760 /* Register bitmask-or match */
761 bitmask_or
= talloc_zero(ldb
, struct ldb_extended_match_rule
);
762 if (bitmask_or
== NULL
) {
763 return LDB_ERR_OPERATIONS_ERROR
;
766 bitmask_or
->oid
= LDB_OID_COMPARATOR_OR
;
767 bitmask_or
->callback
= ldb_match_bitmask
;
769 ret
= ldb_register_extended_match_rule(ldb
, bitmask_or
);
770 if (ret
!= LDB_SUCCESS
) {
774 /* Register always-false match */
775 always_false
= talloc_zero(ldb
, struct ldb_extended_match_rule
);
776 if (always_false
== NULL
) {
777 return LDB_ERR_OPERATIONS_ERROR
;
780 always_false
->oid
= SAMBA_LDAP_MATCH_ALWAYS_FALSE
;
781 always_false
->callback
= ldb_comparator_false
;
783 ret
= ldb_register_extended_match_rule(ldb
, always_false
);
784 if (ret
!= LDB_SUCCESS
) {
792 register a new ldb extended matching rule
794 int ldb_register_extended_match_rule(struct ldb_context
*ldb
,
795 const struct ldb_extended_match_rule
*rule
)
797 const struct ldb_extended_match_rule
*lookup_rule
;
798 struct ldb_extended_match_entry
*entry
;
800 lookup_rule
= ldb_find_extended_match_rule(ldb
, rule
->oid
);
802 return LDB_ERR_ENTRY_ALREADY_EXISTS
;
805 entry
= talloc_zero(ldb
, struct ldb_extended_match_entry
);
807 return LDB_ERR_OPERATIONS_ERROR
;
810 DLIST_ADD_END(ldb
->extended_match_rules
, entry
);
815 int ldb_register_redact_callback(struct ldb_context
*ldb
,
816 ldb_redact_fn redact_fn
,
817 struct ldb_module
*module
)
819 if (ldb
->redact
.callback
!= NULL
) {
820 return LDB_ERR_ENTRY_ALREADY_EXISTS
;
823 ldb
->redact
.callback
= redact_fn
;
824 ldb
->redact
.module
= module
;