4 Copyright (C) Andrew Tridgell 2004-2005
6 ** NOTE! The following LGPL license applies to the ldb
7 ** library. This does NOT imply that all of Samba is released
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 2 of the License, or (at your option) any later version.
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 * Component: ldb expression matching
30 * Description: ldb expression matching
32 * Author: Andrew Tridgell
36 #include "ldb/include/ldb.h"
37 #include "ldb/include/ldb_private.h"
41 check if the scope matches in a search result
43 static int ldb_match_scope(struct ldb_context
*ldb
,
52 if (base_str
== NULL
) {
56 base
= ldb_dn_explode_casefold(ldb
, base_str
);
57 if (base
== NULL
) return 0;
59 dn
= ldb_dn_explode_casefold(ldb
, dn_str
);
67 if (ldb_dn_compare(ldb
, base
, dn
) == 0) {
72 case LDB_SCOPE_ONELEVEL
:
73 if (dn
->comp_num
!= base
->comp_num
) {
74 if (ldb_dn_compare_base(ldb
, base
, dn
) == 0) {
80 case LDB_SCOPE_SUBTREE
:
82 if (ldb_dn_compare_base(ldb
, base
, dn
) == 0) {
95 match if node is present
97 static int ldb_match_present(struct ldb_context
*ldb
,
98 struct ldb_message
*msg
,
99 struct ldb_parse_tree
*tree
,
101 enum ldb_scope scope
)
104 if (ldb_attr_cmp(tree
->u
.simple
.attr
, "dn") == 0) {
108 if (ldb_msg_find_element(msg
, tree
->u
.simple
.attr
)) {
116 match a simple leaf node
118 static int ldb_match_simple(struct ldb_context
*ldb
,
119 struct ldb_message
*msg
,
120 struct ldb_parse_tree
*tree
,
122 enum ldb_scope scope
)
125 struct ldb_message_element
*el
;
126 const struct ldb_attrib_handler
*h
;
127 struct ldb_dn
*msgdn
, *valuedn
;
130 if (ldb_attr_cmp(tree
->u
.simple
.attr
, "dn") == 0) {
132 msgdn
= ldb_dn_explode_casefold(ldb
, msg
->dn
);
133 if (msgdn
== NULL
) return 0;
135 valuedn
= ldb_dn_explode_casefold(ldb
, tree
->u
.simple
.value
.data
);
136 if (valuedn
== NULL
) {
141 ret
= ldb_dn_compare(ldb
, msgdn
, valuedn
);
144 talloc_free(valuedn
);
146 if (ret
== 0) return 1;
150 el
= ldb_msg_find_element(msg
, tree
->u
.simple
.attr
);
155 h
= ldb_attrib_handler(ldb
, el
->name
);
157 for (i
=0;i
<el
->num_values
;i
++) {
158 if (h
->comparison_fn(ldb
, ldb
, &tree
->u
.simple
.value
,
159 &el
->values
[i
]) == 0) {
167 static int ldb_wildcard_compare(struct ldb_context
*ldb
,
168 struct ldb_parse_tree
*tree
,
169 const struct ldb_val value
)
171 const struct ldb_attrib_handler
*h
;
174 struct ldb_val
*chunk
;
179 h
= ldb_attrib_handler(ldb
, tree
->u
.substring
.attr
);
181 if(h
->canonicalise_fn(ldb
, ldb
, &value
, &val
) != 0)
187 if ( ! tree
->u
.substring
.start_with_wildcard
) {
189 chunk
= tree
->u
.substring
.chunks
[c
];
190 if(h
->canonicalise_fn(ldb
, ldb
, chunk
, &cnk
) != 0) goto failed
;
192 /* FIXME: case of embedded nulls */
193 if (strncmp(val
.data
, cnk
.data
, cnk
.length
) != 0) goto failed
;
194 val
.length
-= cnk
.length
;
195 val
.data
+= cnk
.length
;
197 talloc_free(cnk
.data
);
201 while (tree
->u
.substring
.chunks
[c
]) {
203 chunk
= tree
->u
.substring
.chunks
[c
];
204 if(h
->canonicalise_fn(ldb
, ldb
, chunk
, &cnk
) != 0) goto failed
;
206 /* FIXME: case of embedded nulls */
207 p
= strstr(val
.data
, cnk
.data
);
208 if (p
== NULL
) goto failed
;
209 if ( (! tree
->u
.substring
.chunks
[c
+ 1]) && (! tree
->u
.substring
.end_with_wildcard
) ) {
211 g
= strstr(p
+ cnk
.length
, cnk
.data
);
215 val
.length
= val
.length
- (p
- (char *)(val
.data
)) - cnk
.length
;
216 val
.data
= p
+ cnk
.length
;
218 talloc_free(cnk
.data
);
222 if ( (! tree
->u
.substring
.end_with_wildcard
) && (*(val
.data
) != 0) ) goto failed
; /* last chunk have not reached end of string */
228 talloc_free(cnk
.data
);
233 match a simple leaf node
235 static int ldb_match_substring(struct ldb_context
*ldb
,
236 struct ldb_message
*msg
,
237 struct ldb_parse_tree
*tree
,
239 enum ldb_scope scope
)
242 struct ldb_message_element
*el
;
244 el
= ldb_msg_find_element(msg
, tree
->u
.simple
.attr
);
249 for (i
= 0; i
< el
->num_values
; i
++) {
250 if (ldb_wildcard_compare(ldb
, tree
, el
->values
[i
]) == 1) {
260 bitwise-and comparator
262 static int ldb_comparator_and(struct ldb_val
*v1
, struct ldb_val
*v2
)
265 i1
= strtoull(v1
->data
, NULL
, 0);
266 i2
= strtoull(v2
->data
, NULL
, 0);
267 return ((i1
& i2
) == i2
);
271 bitwise-or comparator
273 static int ldb_comparator_or(struct ldb_val
*v1
, struct ldb_val
*v2
)
276 i1
= strtoull(v1
->data
, NULL
, 0);
277 i2
= strtoull(v2
->data
, NULL
, 0);
278 return ((i1
& i2
) != 0);
283 extended match, handles things like bitops
285 static int ldb_match_extended(struct ldb_context
*ldb
,
286 struct ldb_message
*msg
,
287 struct ldb_parse_tree
*tree
,
289 enum ldb_scope scope
)
294 int (*comparator
)(struct ldb_val
*, struct ldb_val
*);
296 { LDB_OID_COMPARATOR_AND
, ldb_comparator_and
},
297 { LDB_OID_COMPARATOR_OR
, ldb_comparator_or
}
299 int (*comp
)(struct ldb_val
*, struct ldb_val
*) = NULL
;
300 struct ldb_message_element
*el
;
302 if (tree
->u
.extended
.dnAttributes
) {
303 ldb_debug(ldb
, LDB_DEBUG_ERROR
, "ldb: dnAttributes extended match not supported yet");
306 if (tree
->u
.extended
.rule_id
== NULL
) {
307 ldb_debug(ldb
, LDB_DEBUG_ERROR
, "ldb: no-rule extended matches not supported yet");
310 if (tree
->u
.extended
.attr
== NULL
) {
311 ldb_debug(ldb
, LDB_DEBUG_ERROR
, "ldb: no-attribute extended matches not supported yet");
315 for (i
=0;i
<ARRAY_SIZE(rules
);i
++) {
316 if (strcmp(rules
[i
].oid
, tree
->u
.extended
.rule_id
) == 0) {
317 comp
= rules
[i
].comparator
;
322 ldb_debug(ldb
, LDB_DEBUG_ERROR
, "ldb: unknown extended rule_id %s\n",
323 tree
->u
.extended
.rule_id
);
327 /* find the message element */
328 el
= ldb_msg_find_element(msg
, tree
->u
.extended
.attr
);
333 for (i
=0;i
<el
->num_values
;i
++) {
334 int ret
= comp(&el
->values
[i
], &tree
->u
.extended
.value
);
335 if (ret
== -1 || ret
== 1) return ret
;
342 return 0 if the given parse tree matches the given message. Assumes
343 the message is in sorted order
345 return 1 if it matches, and 0 if it doesn't match
347 this is a recursive function, and does short-circuit evaluation
349 static int ldb_match_message(struct ldb_context
*ldb
,
350 struct ldb_message
*msg
,
351 struct ldb_parse_tree
*tree
,
353 enum ldb_scope scope
)
358 switch (tree
->operation
) {
360 return ldb_match_simple(ldb
, msg
, tree
, base
, scope
);
363 return ldb_match_present(ldb
, msg
, tree
, base
, scope
);
365 case LDB_OP_SUBSTRING
:
366 return ldb_match_substring(ldb
, msg
, tree
, base
, scope
);
368 case LDB_OP_EXTENDED
:
369 return ldb_match_extended(ldb
, msg
, tree
, base
, scope
);
372 return ! ldb_match_message(ldb
, msg
, tree
->u
.isnot
.child
, base
, scope
);
375 for (i
=0;i
<tree
->u
.list
.num_elements
;i
++) {
376 v
= ldb_match_message(ldb
, msg
, tree
->u
.list
.elements
[i
],
383 for (i
=0;i
<tree
->u
.list
.num_elements
;i
++) {
384 v
= ldb_match_message(ldb
, msg
, tree
->u
.list
.elements
[i
],
394 int ldb_match_msg(struct ldb_context
*ldb
,
395 struct ldb_message
*msg
,
396 struct ldb_parse_tree
*tree
,
398 enum ldb_scope scope
)
400 if ( ! ldb_match_scope(ldb
, base
, msg
->dn
, scope
) ) {
404 return ldb_match_message(ldb
, msg
, tree
, base
, scope
);