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
36 #include "ldb/include/includes.h"
39 check if the scope matches in a search result
41 static int ldb_match_scope(struct ldb_context *ldb,
42 const struct ldb_dn *base,
43 const struct ldb_dn *dn,
48 if (base == NULL || dn == NULL) {
54 if (ldb_dn_compare(ldb, 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(ldb, base, dn) == 0) {
67 case LDB_SCOPE_SUBTREE:
69 if (ldb_dn_compare_base(ldb, 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,
87 if (ldb_attr_dn(tree->u.present.attr) == 0) {
91 if (ldb_msg_find_element(msg, tree->u.present.attr)) {
98 static int ldb_match_comparison(struct ldb_context *ldb,
99 const struct ldb_message *msg,
100 const struct ldb_parse_tree *tree,
101 enum ldb_scope scope,
102 enum ldb_parse_op comp_op)
105 struct ldb_message_element *el;
106 const struct ldb_attrib_handler *h;
109 /* FIXME: APPROX comparison not handled yet */
110 if (comp_op == LDB_OP_APPROX) return 0;
112 el = ldb_msg_find_element(msg, tree->u.comparison.attr);
117 h = ldb_attrib_handler(ldb, el->name);
119 for (i = 0; i < el->num_values; i++) {
120 ret = h->comparison_fn(ldb, ldb, &el->values[i], &tree->u.comparison.value);
125 if (ret > 0 && comp_op == LDB_OP_GREATER) {
128 if (ret < 0 && comp_op == LDB_OP_LESS) {
137 match a simple leaf node
139 static int ldb_match_equality(struct ldb_context *ldb,
140 const struct ldb_message *msg,
141 const struct ldb_parse_tree *tree,
142 enum ldb_scope scope)
145 struct ldb_message_element *el;
146 const struct ldb_attrib_handler *h;
147 struct ldb_dn *valuedn;
150 if (ldb_attr_dn(tree->u.equality.attr) == 0) {
151 valuedn = ldb_dn_explode_casefold(ldb, ldb,
152 (char *)tree->u.equality.value.data);
153 if (valuedn == NULL) {
157 ret = ldb_dn_compare(ldb, msg->dn, valuedn);
159 talloc_free(valuedn);
161 if (ret == 0) return 1;
165 /* TODO: handle the "*" case derived from an extended search
166 operation without the attibute type defined */
167 el = ldb_msg_find_element(msg, tree->u.equality.attr);
172 h = ldb_attrib_handler(ldb, el->name);
174 for (i=0;i<el->num_values;i++) {
175 if (h->comparison_fn(ldb, ldb, &tree->u.equality.value,
176 &el->values[i]) == 0) {
184 static int ldb_wildcard_compare(struct ldb_context *ldb,
185 const struct ldb_parse_tree *tree,
186 const struct ldb_val value)
188 const struct ldb_attrib_handler *h;
191 struct ldb_val *chunk;
193 uint8_t *save_p = NULL;
196 h = ldb_attrib_handler(ldb, tree->u.substring.attr);
198 if(h->canonicalise_fn(ldb, ldb, &value, &val) != 0)
204 if ( ! tree->u.substring.start_with_wildcard ) {
206 chunk = tree->u.substring.chunks[c];
207 if(h->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto failed;
209 /* This deals with wildcard prefix searches on binary attributes (eg objectGUID) */
210 if (cnk.length > val.length) {
213 if (memcmp((char *)val.data, (char *)cnk.data, cnk.length) != 0) goto failed;
214 val.length -= cnk.length;
215 val.data += cnk.length;
217 talloc_free(cnk.data);
221 while (tree->u.substring.chunks[c]) {
223 chunk = tree->u.substring.chunks[c];
224 if(h->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto failed;
226 /* FIXME: case of embedded nulls */
227 p = strstr((char *)val.data, (char *)cnk.data);
228 if (p == NULL) goto failed;
229 if ( (! tree->u.substring.chunks[c + 1]) && (! tree->u.substring.end_with_wildcard) ) {
231 g = strstr((char *)p + cnk.length, (char *)cnk.data);
235 val.length = val.length - (p - (char *)(val.data)) - cnk.length;
236 val.data = (uint8_t *)(p + cnk.length);
238 talloc_free(cnk.data);
242 if ( (! tree->u.substring.end_with_wildcard) && (*(val.data) != 0) ) goto failed; /* last chunk have not reached end of string */
248 talloc_free(cnk.data);
253 match a simple leaf node
255 static int ldb_match_substring(struct ldb_context *ldb,
256 const struct ldb_message *msg,
257 const struct ldb_parse_tree *tree,
258 enum ldb_scope scope)
261 struct ldb_message_element *el;
263 el = ldb_msg_find_element(msg, tree->u.substring.attr);
268 for (i = 0; i < el->num_values; i++) {
269 if (ldb_wildcard_compare(ldb, tree, el->values[i]) == 1) {
279 bitwise-and comparator
281 static int ldb_comparator_and(const struct ldb_val *v1, const struct ldb_val *v2)
284 i1 = strtoull((char *)v1->data, NULL, 0);
285 i2 = strtoull((char *)v2->data, NULL, 0);
286 return ((i1 & i2) == i2);
290 bitwise-or comparator
292 static int ldb_comparator_or(const struct ldb_val *v1, const struct ldb_val *v2)
295 i1 = strtoull((char *)v1->data, NULL, 0);
296 i2 = strtoull((char *)v2->data, NULL, 0);
297 return ((i1 & i2) != 0);
302 extended match, handles things like bitops
304 static int ldb_match_extended(struct ldb_context *ldb,
305 const struct ldb_message *msg,
306 const struct ldb_parse_tree *tree,
307 enum ldb_scope scope)
312 int (*comparator)(const struct ldb_val *, const struct ldb_val *);
314 { LDB_OID_COMPARATOR_AND, ldb_comparator_and},
315 { LDB_OID_COMPARATOR_OR, ldb_comparator_or}
317 int (*comp)(const struct ldb_val *, const struct ldb_val *) = NULL;
318 struct ldb_message_element *el;
320 if (tree->u.extended.dnAttributes) {
321 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: dnAttributes extended match not supported yet");
324 if (tree->u.extended.rule_id == NULL) {
325 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-rule extended matches not supported yet");
328 if (tree->u.extended.attr == NULL) {
329 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-attribute extended matches not supported yet");
333 for (i=0;i<ARRAY_SIZE(rules);i++) {
334 if (strcmp(rules[i].oid, tree->u.extended.rule_id) == 0) {
335 comp = rules[i].comparator;
340 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: unknown extended rule_id %s\n",
341 tree->u.extended.rule_id);
345 /* find the message element */
346 el = ldb_msg_find_element(msg, tree->u.extended.attr);
351 for (i=0;i<el->num_values;i++) {
352 int ret = comp(&el->values[i], &tree->u.extended.value);
353 if (ret == -1 || ret == 1) return ret;
360 return 0 if the given parse tree matches the given message. Assumes
361 the message is in sorted order
363 return 1 if it matches, and 0 if it doesn't match
365 this is a recursive function, and does short-circuit evaluation
367 static int ldb_match_message(struct ldb_context *ldb,
368 const struct ldb_message *msg,
369 const struct ldb_parse_tree *tree,
370 enum ldb_scope scope)
375 switch (tree->operation) {
377 for (i=0;i<tree->u.list.num_elements;i++) {
378 v = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope);
384 for (i=0;i<tree->u.list.num_elements;i++) {
385 v = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope);
391 return ! ldb_match_message(ldb, msg, tree->u.isnot.child, scope);
393 case LDB_OP_EQUALITY:
394 return ldb_match_equality(ldb, msg, tree, scope);
396 case LDB_OP_SUBSTRING:
397 return ldb_match_substring(ldb, msg, tree, scope);
400 return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_GREATER);
403 return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_LESS);
406 return ldb_match_present(ldb, msg, tree, scope);
409 return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_APPROX);
411 case LDB_OP_EXTENDED:
412 return ldb_match_extended(ldb, msg, tree, scope);
419 int ldb_match_msg(struct ldb_context *ldb,
420 const struct ldb_message *msg,
421 const struct ldb_parse_tree *tree,
422 const struct ldb_dn *base,
423 enum ldb_scope scope)
425 if ( ! ldb_match_scope(ldb, base, msg->dn, scope) ) {
429 return ldb_match_message(ldb, msg, tree, scope);