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 2 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, write to the Free Software
23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 * Component: ldb expression matching
31 * Description: ldb expression matching
33 * Author: Andrew Tridgell
37 #include "ldb/include/ldb.h"
38 #include "ldb/include/ldb_private.h"
42 check if the scope matches in a search result
44 static int ldb_match_scope(struct ldb_context *ldb,
53 if (base_str == NULL) {
57 base = ldb_dn_explode_casefold(ldb, base_str);
58 if (base == NULL) return 0;
60 dn = ldb_dn_explode_casefold(ldb, dn_str);
68 if (ldb_dn_compare(ldb, base, dn) == 0) {
73 case LDB_SCOPE_ONELEVEL:
74 if (dn->comp_num == (base->comp_num + 1)) {
75 if (ldb_dn_compare_base(ldb, base, dn) == 0) {
81 case LDB_SCOPE_SUBTREE:
83 if (ldb_dn_compare_base(ldb, base, dn) == 0) {
96 match if node is present
98 static int ldb_match_present(struct ldb_context *ldb,
99 struct ldb_message *msg,
100 struct ldb_parse_tree *tree,
102 enum ldb_scope scope)
105 if (ldb_attr_cmp(tree->u.present.attr, "dn") == 0) {
109 if (ldb_msg_find_element(msg, tree->u.present.attr)) {
116 static int ldb_match_comparison(struct ldb_context *ldb,
117 struct ldb_message *msg,
118 struct ldb_parse_tree *tree,
120 enum ldb_scope scope,
121 enum ldb_parse_op comp_op)
124 struct ldb_message_element *el;
125 const struct ldb_attrib_handler *h;
128 /* FIXME: APPROX comparison not handled yet */
129 if (comp_op == LDB_OP_APPROX) return 0;
131 el = ldb_msg_find_element(msg, tree->u.comparison.attr);
136 h = ldb_attrib_handler(ldb, el->name);
138 for (i = 0; i < el->num_values; i++) {
139 ret = h->comparison_fn(ldb, ldb, &el->values[i], &tree->u.comparison.value);
144 if (ret > 0 && comp_op == LDB_OP_GREATER) {
147 if (ret < 0 && comp_op == LDB_OP_LESS) {
156 match a simple leaf node
158 static int ldb_match_equality(struct ldb_context *ldb,
159 struct ldb_message *msg,
160 struct ldb_parse_tree *tree,
162 enum ldb_scope scope)
165 struct ldb_message_element *el;
166 const struct ldb_attrib_handler *h;
167 struct ldb_dn *msgdn, *valuedn;
170 if (ldb_attr_cmp(tree->u.equality.attr, "dn") == 0) {
172 msgdn = ldb_dn_explode_casefold(ldb, msg->dn);
173 if (msgdn == NULL) return 0;
175 valuedn = ldb_dn_explode_casefold(ldb, tree->u.equality.value.data);
176 if (valuedn == NULL) {
181 ret = ldb_dn_compare(ldb, msgdn, valuedn);
184 talloc_free(valuedn);
186 if (ret == 0) return 1;
190 /* TODO: handle the "*" case derived from an extended search
191 operation without the attibute type defined */
192 el = ldb_msg_find_element(msg, tree->u.equality.attr);
197 h = ldb_attrib_handler(ldb, el->name);
199 for (i=0;i<el->num_values;i++) {
200 if (h->comparison_fn(ldb, ldb, &tree->u.equality.value,
201 &el->values[i]) == 0) {
209 static int ldb_wildcard_compare(struct ldb_context *ldb,
210 struct ldb_parse_tree *tree,
211 const struct ldb_val value)
213 const struct ldb_attrib_handler *h;
216 struct ldb_val *chunk;
221 h = ldb_attrib_handler(ldb, tree->u.substring.attr);
223 if(h->canonicalise_fn(ldb, ldb, &value, &val) != 0)
229 if ( ! tree->u.substring.start_with_wildcard ) {
231 chunk = tree->u.substring.chunks[c];
232 if(h->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto failed;
234 /* FIXME: case of embedded nulls */
235 if (strncmp(val.data, cnk.data, cnk.length) != 0) goto failed;
236 val.length -= cnk.length;
237 val.data += cnk.length;
239 talloc_free(cnk.data);
243 while (tree->u.substring.chunks[c]) {
245 chunk = tree->u.substring.chunks[c];
246 if(h->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto failed;
248 /* FIXME: case of embedded nulls */
249 p = strstr(val.data, cnk.data);
250 if (p == NULL) goto failed;
251 if ( (! tree->u.substring.chunks[c + 1]) && (! tree->u.substring.end_with_wildcard) ) {
253 g = strstr(p + cnk.length, cnk.data);
257 val.length = val.length - (p - (char *)(val.data)) - cnk.length;
258 val.data = p + cnk.length;
260 talloc_free(cnk.data);
264 if ( (! tree->u.substring.end_with_wildcard) && (*(val.data) != 0) ) goto failed; /* last chunk have not reached end of string */
270 talloc_free(cnk.data);
275 match a simple leaf node
277 static int ldb_match_substring(struct ldb_context *ldb,
278 struct ldb_message *msg,
279 struct ldb_parse_tree *tree,
281 enum ldb_scope scope)
284 struct ldb_message_element *el;
286 el = ldb_msg_find_element(msg, tree->u.substring.attr);
291 for (i = 0; i < el->num_values; i++) {
292 if (ldb_wildcard_compare(ldb, tree, el->values[i]) == 1) {
302 bitwise-and comparator
304 static int ldb_comparator_and(struct ldb_val *v1, struct ldb_val *v2)
307 i1 = strtoull(v1->data, NULL, 0);
308 i2 = strtoull(v2->data, NULL, 0);
309 return ((i1 & i2) == i2);
313 bitwise-or comparator
315 static int ldb_comparator_or(struct ldb_val *v1, struct ldb_val *v2)
318 i1 = strtoull(v1->data, NULL, 0);
319 i2 = strtoull(v2->data, NULL, 0);
320 return ((i1 & i2) != 0);
325 extended match, handles things like bitops
327 static int ldb_match_extended(struct ldb_context *ldb,
328 struct ldb_message *msg,
329 struct ldb_parse_tree *tree,
331 enum ldb_scope scope)
336 int (*comparator)(struct ldb_val *, struct ldb_val *);
338 { LDB_OID_COMPARATOR_AND, ldb_comparator_and},
339 { LDB_OID_COMPARATOR_OR, ldb_comparator_or}
341 int (*comp)(struct ldb_val *, struct ldb_val *) = NULL;
342 struct ldb_message_element *el;
344 if (tree->u.extended.dnAttributes) {
345 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: dnAttributes extended match not supported yet");
348 if (tree->u.extended.rule_id == NULL) {
349 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-rule extended matches not supported yet");
352 if (tree->u.extended.attr == NULL) {
353 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-attribute extended matches not supported yet");
357 for (i=0;i<ARRAY_SIZE(rules);i++) {
358 if (strcmp(rules[i].oid, tree->u.extended.rule_id) == 0) {
359 comp = rules[i].comparator;
364 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: unknown extended rule_id %s\n",
365 tree->u.extended.rule_id);
369 /* find the message element */
370 el = ldb_msg_find_element(msg, tree->u.extended.attr);
375 for (i=0;i<el->num_values;i++) {
376 int ret = comp(&el->values[i], &tree->u.extended.value);
377 if (ret == -1 || ret == 1) return ret;
384 return 0 if the given parse tree matches the given message. Assumes
385 the message is in sorted order
387 return 1 if it matches, and 0 if it doesn't match
389 this is a recursive function, and does short-circuit evaluation
391 static int ldb_match_message(struct ldb_context *ldb,
392 struct ldb_message *msg,
393 struct ldb_parse_tree *tree,
395 enum ldb_scope scope)
400 switch (tree->operation) {
402 for (i=0;i<tree->u.list.num_elements;i++) {
403 v = ldb_match_message(ldb, msg, tree->u.list.elements[i],
410 for (i=0;i<tree->u.list.num_elements;i++) {
411 v = ldb_match_message(ldb, msg, tree->u.list.elements[i],
418 return ! ldb_match_message(ldb, msg, tree->u.isnot.child, base, scope);
420 case LDB_OP_EQUALITY:
421 return ldb_match_equality(ldb, msg, tree, base, scope);
423 case LDB_OP_SUBSTRING:
424 return ldb_match_substring(ldb, msg, tree, base, scope);
427 return ldb_match_comparison(ldb, msg, tree, base, scope, LDB_OP_GREATER);
430 return ldb_match_comparison(ldb, msg, tree, base, scope, LDB_OP_LESS);
433 return ldb_match_present(ldb, msg, tree, base, scope);
436 return ldb_match_comparison(ldb, msg, tree, base, scope, LDB_OP_APPROX);
438 case LDB_OP_EXTENDED:
439 return ldb_match_extended(ldb, msg, tree, base, scope);
446 int ldb_match_msg(struct ldb_context *ldb,
447 struct ldb_message *msg,
448 struct ldb_parse_tree *tree,
450 enum ldb_scope scope)
452 if ( ! ldb_match_scope(ldb, base, msg->dn, scope) ) {
456 return ldb_match_message(ldb, msg, tree, base, scope);