4 Copyright (C) Andrew Tridgell 2004
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 parsing
30 * Description: parse LDAP-like search expressions
32 * Author: Andrew Tridgell
37 - add RFC2254 binary string handling
38 - possibly add ~=, <= and >= handling
39 - expand the test suite
40 - add better parse error handling
45 #include "ldb/include/ldb.h"
50 a filter is defined by:
51 <filter> ::= '(' <filtercomp> ')'
52 <filtercomp> ::= <and> | <or> | <not> | <simple>
53 <and> ::= '&' <filterlist>
54 <or> ::= '|' <filterlist>
55 <not> ::= '!' <filter>
56 <filterlist> ::= <filter> | <filter> <filterlist>
57 <simple> ::= <attributetype> <filtertype> <attributevalue>
58 <filtertype> ::= '=' | '~=' | '<=' | '>='
61 #define LDB_ALL_SEP "()&|=!"
64 return next token element. Caller frees
66 static char *ldb_parse_lex(void *ctx, const char **s, const char *sep)
71 while (isspace((unsigned char)*p)) {
80 if (strchr(sep, *p)) {
82 ret = talloc_strndup(ctx, p, 1);
89 while (*p && (isalnum((unsigned char)*p) || !strchr(sep, *p))) {
97 ret = talloc_strndup(ctx, *s, p - *s);
108 find a matching close brace in a string
110 static const char *match_brace(const char *s)
112 unsigned int count = 0;
113 while (*s && (count != 0 || *s != ')')) {
129 decode a RFC2254 binary string representation of a buffer.
130 Used in LDAP filters.
132 struct ldb_val ldb_binary_decode(void *mem_ctx, const char *str)
136 int slen = str?strlen(str):0;
138 ret.data = talloc_size(mem_ctx, slen+1);
140 if (ret.data == NULL) return ret;
142 for (i=j=0;i<slen;i++) {
143 if (str[i] == '\\') {
145 if (sscanf(&str[i+1], "%02X", &c) != 1) {
146 talloc_free(ret.data);
147 memset(&ret, 0, sizeof(ret));
150 ((uint8_t *)ret.data)[j++] = c;
153 ((uint8_t *)ret.data)[j++] = str[i];
157 ((uint8_t *)ret.data)[j] = 0;
164 encode a blob as a RFC2254 binary string, escaping any
165 non-printable or '\' characters
167 char *ldb_binary_encode(void *mem_ctx, struct ldb_val val)
171 int len = val.length;
172 unsigned char *buf = val.data;
174 for (i=0;i<val.length;i++) {
175 if (!isprint(buf[i]) || strchr(" *()\\&|!\"", buf[i])) {
179 ret = talloc_array(mem_ctx, char, len+1);
180 if (ret == NULL) return NULL;
183 for (i=0;i<val.length;i++) {
184 if (!isprint(buf[i]) || strchr(" *()\\&|!\"", buf[i])) {
185 snprintf(ret+len, 4, "\\%02X", buf[i]);
197 /* find the first matching wildcard */
198 static char *ldb_parse_find_wildcard(char *value)
201 value = strpbrk(value, "\\*");
202 if (value == NULL) return NULL;
204 if (value[0] == '\\') {
205 if (value[1] == '\0') return NULL;
210 if (value[0] == '*') return value;
216 /* return a NULL terminated list of binary strings representing the value
217 chunks separated by wildcards that makes the value portion of the filter
219 static struct ldb_val **ldb_wildcard_decode(void *mem_ctx, const char *string)
221 struct ldb_val **ret = NULL;
225 wc = talloc_strdup(mem_ctx, string);
226 if (wc == NULL) return NULL;
230 wc = ldb_parse_find_wildcard(str);
240 ret = talloc_realloc(mem_ctx, ret, struct ldb_val *, val + 2);
241 if (ret == NULL) return NULL;
243 ret[val] = talloc(mem_ctx, struct ldb_val);
244 if (ret[val] == NULL) return NULL;
246 *(ret[val]) = ldb_binary_decode(mem_ctx, str);
247 if ((ret[val])->data == NULL) return NULL;
257 static struct ldb_parse_tree *ldb_parse_filter(void *mem_ctx, const char **s);
261 parse an extended match
269 the ':dn' part sets the dnAttributes boolean if present
270 the oid sets the rule_id string
273 static struct ldb_parse_tree *ldb_parse_extended(struct ldb_parse_tree *ret,
274 char *attr, char *value)
278 ret->operation = LDB_OP_EXTENDED;
279 ret->u.extended.value = ldb_binary_decode(ret, value);
280 if (ret->u.extended.value.data == NULL) goto failed;
282 p1 = strchr(attr, ':');
283 if (p1 == NULL) goto failed;
284 p2 = strchr(p1+1, ':');
285 if (p2 == NULL) goto failed;
286 p3 = strchr(p2+1, ':');
292 ret->u.extended.attr = talloc_strdup(ret, attr);
293 if (ret->u.extended.attr == NULL) goto failed;
294 if (strcmp(p1+1, "dn") == 0) {
295 ret->u.extended.dnAttributes = 1;
297 ret->u.extended.rule_id = talloc_strdup(ret, p2+1);
298 if (ret->u.extended.rule_id == NULL) goto failed;
300 ret->u.extended.rule_id = NULL;
303 ret->u.extended.dnAttributes = 0;
304 ret->u.extended.rule_id = talloc_strdup(ret, p1+1);
305 if (ret->u.extended.rule_id == NULL) goto failed;
317 <simple> ::= <attributetype> <filtertype> <attributevalue>
319 static struct ldb_parse_tree *ldb_parse_simple(void *mem_ctx, const char *s)
322 struct ldb_parse_tree *ret;
324 ret = talloc(mem_ctx, struct ldb_parse_tree);
330 l = ldb_parse_lex(ret, &s, LDB_ALL_SEP);
336 if (strchr("()&|=", *l)) {
341 eq = ldb_parse_lex(ret, &s, LDB_ALL_SEP);
342 if (!eq || strcmp(eq, "=") != 0) {
348 val = ldb_parse_lex(ret, &s, ")");
349 if (val && strchr("()&|", *val)) {
354 if (l[strlen(l)-1] == ':') {
355 /* its an extended match */
356 return ldb_parse_extended(ret, l, val);
359 if (val && strcmp(val, "*") == 0) {
360 ret->operation = LDB_OP_PRESENT;
361 ret->u.present.attr = l;
366 if (val && ldb_parse_find_wildcard(val) != NULL) {
367 ret->operation = LDB_OP_SUBSTRING;
368 ret->u.substring.attr = l;
369 ret->u.substring.start_with_wildcard = 0;
370 ret->u.substring.end_with_wildcard = 0;
371 ret->u.substring.chunks = ldb_wildcard_decode(ret, val);
372 if (ret->u.substring.chunks == NULL){
376 if (val[0] == '*') ret->u.substring.start_with_wildcard = 1;
377 if (val[strlen(val) - 1] == '*') ret->u.substring.end_with_wildcard = 1;
382 ret->operation = LDB_OP_SIMPLE;
383 ret->u.simple.attr = l;
384 ret->u.simple.value = ldb_binary_decode(ret, val);
385 if (ret->u.simple.value.data == NULL) {
396 <and> ::= '&' <filterlist>
397 <or> ::= '|' <filterlist>
398 <filterlist> ::= <filter> | <filter> <filterlist>
400 static struct ldb_parse_tree *ldb_parse_filterlist(void *mem_ctx,
401 enum ldb_parse_op op, const char *s)
403 struct ldb_parse_tree *ret, *next;
405 ret = talloc(mem_ctx, struct ldb_parse_tree);
412 ret->u.list.num_elements = 1;
413 ret->u.list.elements = talloc(ret, struct ldb_parse_tree *);
414 if (!ret->u.list.elements) {
420 ret->u.list.elements[0] = ldb_parse_filter(ret->u.list.elements, &s);
421 if (!ret->u.list.elements[0]) {
426 while (isspace((unsigned char)*s)) s++;
428 while (*s && (next = ldb_parse_filter(ret->u.list.elements, &s))) {
429 struct ldb_parse_tree **e;
430 e = talloc_realloc(ret, ret->u.list.elements,
431 struct ldb_parse_tree *,
432 ret->u.list.num_elements+1);
438 ret->u.list.elements = e;
439 ret->u.list.elements[ret->u.list.num_elements] = next;
440 ret->u.list.num_elements++;
441 while (isspace((unsigned char)*s)) s++;
449 <not> ::= '!' <filter>
451 static struct ldb_parse_tree *ldb_parse_not(void *mem_ctx, const char *s)
453 struct ldb_parse_tree *ret;
455 ret = talloc(mem_ctx, struct ldb_parse_tree);
461 ret->operation = LDB_OP_NOT;
462 ret->u.not.child = ldb_parse_filter(ret, &s);
463 if (!ret->u.not.child) {
473 <filtercomp> ::= <and> | <or> | <not> | <simple>
475 static struct ldb_parse_tree *ldb_parse_filtercomp(void *mem_ctx, const char *s)
477 while (isspace((unsigned char)*s)) s++;
481 return ldb_parse_filterlist(mem_ctx, LDB_OP_AND, s+1);
484 return ldb_parse_filterlist(mem_ctx, LDB_OP_OR, s+1);
487 return ldb_parse_not(mem_ctx, s+1);
494 return ldb_parse_simple(mem_ctx, s);
499 <filter> ::= '(' <filtercomp> ')'
501 static struct ldb_parse_tree *ldb_parse_filter(void *mem_ctx, const char **s)
505 struct ldb_parse_tree *ret;
507 l = ldb_parse_lex(mem_ctx, s, LDB_ALL_SEP);
512 if (strcmp(l, "(") != 0) {
524 s2 = talloc_strndup(mem_ctx, *s, p - *s);
530 ret = ldb_parse_filtercomp(mem_ctx, s2);
540 main parser entry point. Takes a search string and returns a parse tree
542 expression ::= <simple> | <filter>
544 struct ldb_parse_tree *ldb_parse_tree(void *mem_ctx, const char *s)
546 while (isspace((unsigned char)*s)) s++;
549 return ldb_parse_filter(mem_ctx, &s);
552 return ldb_parse_simple(mem_ctx, s);
557 construct a ldap parse filter given a parse tree
559 char *ldb_filter_from_tree(void *mem_ctx, struct ldb_parse_tree *tree)
564 switch (tree->operation) {
566 s = ldb_binary_encode(mem_ctx, tree->u.simple.value);
567 if (s == NULL) return NULL;
568 ret = talloc_asprintf(mem_ctx, "(%s=%s)",
569 tree->u.simple.attr, s);
572 case LDB_OP_EXTENDED:
573 s = ldb_binary_encode(mem_ctx, tree->u.extended.value);
574 if (s == NULL) return NULL;
575 ret = talloc_asprintf(mem_ctx, "(%s%s%s%s:=%s)",
576 tree->u.extended.attr?tree->u.extended.attr:"",
577 tree->u.extended.dnAttributes?":dn":"",
578 tree->u.extended.rule_id?":":"",
579 tree->u.extended.rule_id?tree->u.extended.rule_id:"",
583 case LDB_OP_SUBSTRING:
584 ret = talloc_strdup(mem_ctx, (tree->u.substring.start_with_wildcard)?"*":"");
585 if (ret == NULL) return NULL;
586 for (i = 0; tree->u.substring.chunks[i]; i++) {
587 s2 = ldb_binary_encode(mem_ctx, *(tree->u.substring.chunks[i]));
592 s = talloc_asprintf_append(ret, "%s*", s2);
599 if ( ! tree->u.substring.end_with_wildcard ) {
600 ret[strlen(ret) - 1] = '\0'; /* remove last wildcard */
604 ret = talloc_strdup(mem_ctx, "*");
605 if (ret == NULL) return NULL;
609 ret = talloc_asprintf(mem_ctx, "(%c", (char)tree->operation);
610 if (ret == NULL) return NULL;
611 for (i=0;i<tree->u.list.num_elements;i++) {
612 s = ldb_filter_from_tree(mem_ctx, tree->u.list.elements[i]);
617 s2 = talloc_asprintf_append(ret, "%s", s);
625 s = talloc_asprintf_append(ret, ")");
632 s = ldb_filter_from_tree(mem_ctx, tree->u.not.child);
633 if (s == NULL) return NULL;
635 ret = talloc_asprintf(mem_ctx, "(!%s)", s);