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"
38 check if the scope matches in a search result
40 static int ldb_match_scope(struct ldb_context
*ldb
,
47 if (base
== NULL
|| dn
== NULL
) {
53 if (ldb_dn_compare(base
, dn
) == 0) {
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) {
66 case LDB_SCOPE_SUBTREE
:
68 if (ldb_dn_compare_base(base
, dn
) == 0) {
79 match if node is present
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
)
86 const struct ldb_schema_attribute
*a
;
87 struct ldb_message_element
*el
;
89 if (ldb_attr_dn(tree
->u
.present
.attr
) == 0) {
94 el
= ldb_msg_find_element(msg
, tree
->u
.present
.attr
);
100 a
= ldb_schema_attribute_by_name(ldb
, el
->name
);
102 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX
;
105 if (a
->syntax
->operator_fn
) {
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
;
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
)
127 struct ldb_message_element
*el
;
128 const struct ldb_schema_attribute
*a
;
130 /* FIXME: APPROX comparison not handled yet */
131 if (comp_op
== LDB_OP_APPROX
) {
132 return LDB_ERR_INAPPROPRIATE_MATCHING
;
135 el
= ldb_msg_find_element(msg
, tree
->u
.comparison
.attr
);
141 a
= ldb_schema_attribute_by_name(ldb
, el
->name
);
143 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX
;
146 for (i
= 0; i
< el
->num_values
; i
++) {
147 if (a
->syntax
->operator_fn
) {
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
;
153 int ret
= a
->syntax
->comparison_fn(ldb
, ldb
, &el
->values
[i
], &tree
->u
.comparison
.value
);
159 if (ret
> 0 && comp_op
== LDB_OP_GREATER
) {
163 if (ret
< 0 && comp_op
== LDB_OP_LESS
) {
175 match a simple leaf node
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
,
184 struct ldb_message_element
*el
;
185 const struct ldb_schema_attribute
*a
;
186 struct ldb_dn
*valuedn
;
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
;
195 ret
= ldb_dn_compare(msg
->dn
, valuedn
);
197 talloc_free(valuedn
);
199 *matched
= (ret
== 0);
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
);
211 a
= ldb_schema_attribute_by_name(ldb
, el
->name
);
213 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX
;
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
;
223 if (a
->syntax
->comparison_fn(ldb
, ldb
, &tree
->u
.equality
.value
,
224 &el
->values
[i
]) == 0) {
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
)
239 const struct ldb_schema_attribute
*a
;
242 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
) {
273 if (memcmp((char *)val
.data
, (char *)cnk
.data
, cnk
.length
) != 0) goto mismatch
;
274 val
.length
-= cnk
.length
;
275 val
.data
+= cnk
.length
;
277 talloc_free(cnk
.data
);
281 while (tree
->u
.substring
.chunks
[c
]) {
283 chunk
= tree
->u
.substring
.chunks
[c
];
284 if(a
->syntax
->canonicalise_fn(ldb
, ldb
, chunk
, &cnk
) != 0) goto mismatch
;
286 /* FIXME: case of embedded nulls */
287 p
= strstr((char *)val
.data
, (char *)cnk
.data
);
288 if (p
== NULL
) goto mismatch
;
289 if ( (! tree
->u
.substring
.chunks
[c
+ 1]) && (! tree
->u
.substring
.end_with_wildcard
) ) {
291 g
= strstr((char *)p
+ cnk
.length
, (char *)cnk
.data
);
295 val
.length
= val
.length
- (p
- (char *)(val
.data
)) - cnk
.length
;
296 val
.data
= (uint8_t *)(p
+ cnk
.length
);
298 talloc_free(cnk
.data
);
302 /* last chunk may not have reached end of string */
303 if ( (! tree
->u
.substring
.end_with_wildcard
) && (*(val
.data
) != 0) ) goto mismatch
;
311 talloc_free(cnk
.data
);
316 match a simple leaf node
318 static int ldb_match_substring(struct ldb_context
*ldb
,
319 const struct ldb_message
*msg
,
320 const struct ldb_parse_tree
*tree
,
321 enum ldb_scope scope
, bool *matched
)
324 struct ldb_message_element
*el
;
326 el
= ldb_msg_find_element(msg
, tree
->u
.substring
.attr
);
332 for (i
= 0; i
< el
->num_values
; i
++) {
334 ret
= ldb_wildcard_compare(ldb
, tree
, el
->values
[i
], matched
);
335 if (ret
!= LDB_SUCCESS
) return ret
;
336 if (*matched
) return LDB_SUCCESS
;
345 bitwise-and comparator
347 static int ldb_comparator_bitmask(const char *oid
, const struct ldb_val
*v1
, const struct ldb_val
*v2
,
354 if (v1
->length
>= sizeof(ibuf
)-1) {
355 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX
;
357 memcpy(ibuf
, (char *)v1
->data
, v1
->length
);
358 ibuf
[v1
->length
] = 0;
359 i1
= strtoull(ibuf
, &endptr
, 0);
360 if (endptr
!= NULL
) {
361 if (endptr
== ibuf
|| *endptr
!= 0) {
362 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX
;
366 if (v2
->length
>= sizeof(ibuf
)-1) {
367 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX
;
370 memcpy(ibuf
, (char *)v2
->data
, v2
->length
);
371 ibuf
[v2
->length
] = 0;
372 i2
= strtoull(ibuf
, &endptr
, 0);
373 if (endptr
!= NULL
) {
374 if (endptr
== ibuf
|| *endptr
!= 0) {
375 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX
;
378 if (strcmp(LDB_OID_COMPARATOR_AND
, oid
) == 0) {
379 *matched
= ((i1
& i2
) == i2
);
380 } else if (strcmp(LDB_OID_COMPARATOR_OR
, oid
) == 0) {
381 *matched
= ((i1
& i2
) != 0);
383 return LDB_ERR_INAPPROPRIATE_MATCHING
;
391 static int ldb_comparator_false(const char *oid
, const struct ldb_val
*v1
, const struct ldb_val
*v2
,
400 extended match, handles things like bitops
402 static int ldb_match_extended(struct ldb_context
*ldb
,
403 const struct ldb_message
*msg
,
404 const struct ldb_parse_tree
*tree
,
405 enum ldb_scope scope
, bool *matched
)
410 int (*comparator
)(const char *, const struct ldb_val
*, const struct ldb_val
*, bool *);
412 { LDB_OID_COMPARATOR_AND
, ldb_comparator_bitmask
},
413 { LDB_OID_COMPARATOR_OR
, ldb_comparator_bitmask
},
414 { SAMBA_LDAP_MATCH_ALWAYS_FALSE
, ldb_comparator_false
}
416 int (*comp
)(const char *,const struct ldb_val
*, const struct ldb_val
*, bool *) = NULL
;
417 struct ldb_message_element
*el
;
419 if (tree
->u
.extended
.dnAttributes
) {
420 /* FIXME: We really need to find out what this ":dn" part in
421 * an extended match means and how to handle it. For now print
422 * only a warning to have s3 winbind and other tools working
423 * against us. - Matthias */
424 ldb_debug(ldb
, LDB_DEBUG_WARNING
, "ldb: dnAttributes extended match not supported yet");
426 if (tree
->u
.extended
.rule_id
== NULL
) {
427 ldb_debug(ldb
, LDB_DEBUG_ERROR
, "ldb: no-rule extended matches not supported yet");
428 return LDB_ERR_INAPPROPRIATE_MATCHING
;
430 if (tree
->u
.extended
.attr
== NULL
) {
431 ldb_debug(ldb
, LDB_DEBUG_ERROR
, "ldb: no-attribute extended matches not supported yet");
432 return LDB_ERR_INAPPROPRIATE_MATCHING
;
435 for (i
=0;i
<ARRAY_SIZE(rules
);i
++) {
436 if (strcmp(rules
[i
].oid
, tree
->u
.extended
.rule_id
) == 0) {
437 comp
= rules
[i
].comparator
;
442 ldb_debug(ldb
, LDB_DEBUG_ERROR
, "ldb: unknown extended rule_id %s",
443 tree
->u
.extended
.rule_id
);
444 return LDB_ERR_INAPPROPRIATE_MATCHING
;
447 /* find the message element */
448 el
= ldb_msg_find_element(msg
, tree
->u
.extended
.attr
);
454 for (i
=0;i
<el
->num_values
;i
++) {
455 int ret
= comp(tree
->u
.extended
.rule_id
, &el
->values
[i
], &tree
->u
.extended
.value
, matched
);
456 if (ret
!= LDB_SUCCESS
) return ret
;
457 if (*matched
) return LDB_SUCCESS
;
465 return 0 if the given parse tree matches the given message. Assumes
466 the message is in sorted order
468 return 1 if it matches, and 0 if it doesn't match
470 this is a recursive function, and does short-circuit evaluation
472 static int ldb_match_message(struct ldb_context
*ldb
,
473 const struct ldb_message
*msg
,
474 const struct ldb_parse_tree
*tree
,
475 enum ldb_scope scope
, bool *matched
)
482 if (scope
!= LDB_SCOPE_BASE
&& ldb_dn_is_special(msg
->dn
)) {
483 /* don't match special records except on base searches */
487 switch (tree
->operation
) {
489 for (i
=0;i
<tree
->u
.list
.num_elements
;i
++) {
490 ret
= ldb_match_message(ldb
, msg
, tree
->u
.list
.elements
[i
], scope
, matched
);
491 if (ret
!= LDB_SUCCESS
) return ret
;
492 if (!*matched
) return LDB_SUCCESS
;
498 for (i
=0;i
<tree
->u
.list
.num_elements
;i
++) {
499 ret
= ldb_match_message(ldb
, msg
, tree
->u
.list
.elements
[i
], scope
, matched
);
500 if (ret
!= LDB_SUCCESS
) return ret
;
501 if (*matched
) return LDB_SUCCESS
;
507 ret
= ldb_match_message(ldb
, msg
, tree
->u
.isnot
.child
, scope
, matched
);
508 if (ret
!= LDB_SUCCESS
) return ret
;
509 *matched
= ! *matched
;
512 case LDB_OP_EQUALITY
:
513 return ldb_match_equality(ldb
, msg
, tree
, scope
, matched
);
515 case LDB_OP_SUBSTRING
:
516 return ldb_match_substring(ldb
, msg
, tree
, scope
, matched
);
519 return ldb_match_comparison(ldb
, msg
, tree
, scope
, LDB_OP_GREATER
, matched
);
522 return ldb_match_comparison(ldb
, msg
, tree
, scope
, LDB_OP_LESS
, matched
);
525 return ldb_match_present(ldb
, msg
, tree
, scope
, matched
);
528 return ldb_match_comparison(ldb
, msg
, tree
, scope
, LDB_OP_APPROX
, matched
);
530 case LDB_OP_EXTENDED
:
531 return ldb_match_extended(ldb
, msg
, tree
, scope
, matched
);
534 return LDB_ERR_INAPPROPRIATE_MATCHING
;
537 int ldb_match_msg(struct ldb_context
*ldb
,
538 const struct ldb_message
*msg
,
539 const struct ldb_parse_tree
*tree
,
541 enum ldb_scope scope
)
546 if ( ! ldb_match_scope(ldb
, base
, msg
->dn
, scope
) ) {
550 ret
= ldb_match_message(ldb
, msg
, tree
, scope
, &matched
);
551 if (ret
!= LDB_SUCCESS
) {
552 /* to match the old API, we need to consider this a
559 int ldb_match_msg_error(struct ldb_context
*ldb
,
560 const struct ldb_message
*msg
,
561 const struct ldb_parse_tree
*tree
,
563 enum ldb_scope scope
,
566 if ( ! ldb_match_scope(ldb
, base
, msg
->dn
, scope
) ) {
571 return ldb_match_message(ldb
, msg
, tree
, scope
, matched
);
574 int ldb_match_msg_objectclass(const struct ldb_message
*msg
,
575 const char *objectclass
)
578 struct ldb_message_element
*el
= ldb_msg_find_element(msg
, "objectClass");
582 for (i
=0; i
< el
->num_values
; i
++) {
583 if (ldb_attr_cmp((const char *)el
->values
[i
].data
, objectclass
) == 0) {