docs-xml: fix typos and format in smb.conf server max protocol man
[Samba/gebeck_regimport.git] / lib / ldb / common / ldb_parse.c
blob47145a23011699e6bc0b47373e0c8d4991cba222
1 /*
2 ldb database library
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
8 ** under the LGPL
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 3 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, see <http://www.gnu.org/licenses/>.
25 * Name: ldb
27 * Component: ldb expression parsing
29 * Description: parse LDAP-like search expressions
31 * Author: Andrew Tridgell
35 TODO:
36 - add RFC2254 binary string handling
37 - possibly add ~=, <= and >= handling
38 - expand the test suite
39 - add better parse error handling
43 #include "ldb_private.h"
44 #include "system/locale.h"
46 static int ldb_parse_hex2char(const char *x)
48 if (isxdigit(x[0]) && isxdigit(x[1])) {
49 const char h1 = x[0], h2 = x[1];
50 int c = 0;
52 if (h1 >= 'a') c = h1 - (int)'a' + 10;
53 else if (h1 >= 'A') c = h1 - (int)'A' + 10;
54 else if (h1 >= '0') c = h1 - (int)'0';
55 c = c << 4;
56 if (h2 >= 'a') c += h2 - (int)'a' + 10;
57 else if (h2 >= 'A') c += h2 - (int)'A' + 10;
58 else if (h2 >= '0') c += h2 - (int)'0';
60 return c;
63 return -1;
67 a filter is defined by:
68 <filter> ::= '(' <filtercomp> ')'
69 <filtercomp> ::= <and> | <or> | <not> | <simple>
70 <and> ::= '&' <filterlist>
71 <or> ::= '|' <filterlist>
72 <not> ::= '!' <filter>
73 <filterlist> ::= <filter> | <filter> <filterlist>
74 <simple> ::= <attributetype> <filtertype> <attributevalue>
75 <filtertype> ::= '=' | '~=' | '<=' | '>='
79 decode a RFC2254 binary string representation of a buffer.
80 Used in LDAP filters.
82 struct ldb_val ldb_binary_decode(TALLOC_CTX *mem_ctx, const char *str)
84 size_t i, j;
85 struct ldb_val ret;
86 size_t slen = str?strlen(str):0;
88 ret.data = (uint8_t *)talloc_size(mem_ctx, slen+1);
89 ret.length = 0;
90 if (ret.data == NULL) return ret;
92 for (i=j=0;i<slen;i++) {
93 if (str[i] == '\\') {
94 int c;
96 c = ldb_parse_hex2char(&str[i+1]);
97 if (c == -1) {
98 talloc_free(ret.data);
99 memset(&ret, 0, sizeof(ret));
100 return ret;
102 ((uint8_t *)ret.data)[j++] = c;
103 i += 2;
104 } else {
105 ((uint8_t *)ret.data)[j++] = str[i];
108 ret.length = j;
109 ((uint8_t *)ret.data)[j] = 0;
111 return ret;
116 encode a blob as a RFC2254 binary string, escaping any
117 non-printable or '\' characters
119 char *ldb_binary_encode(TALLOC_CTX *mem_ctx, struct ldb_val val)
121 size_t i;
122 char *ret;
123 size_t len = val.length;
124 unsigned char *buf = val.data;
126 for (i=0;i<val.length;i++) {
127 if (!isprint(buf[i]) || strchr(" *()\\&|!\"", buf[i])) {
128 len += 2;
131 ret = talloc_array(mem_ctx, char, len+1);
132 if (ret == NULL) return NULL;
134 len = 0;
135 for (i=0;i<val.length;i++) {
136 if (!isprint(buf[i]) || strchr(" *()\\&|!\"", buf[i])) {
137 snprintf(ret+len, 4, "\\%02X", buf[i]);
138 len += 3;
139 } else {
140 ret[len++] = buf[i];
144 ret[len] = 0;
146 return ret;
150 encode a string as a RFC2254 binary string, escaping any
151 non-printable or '\' characters. This routine is suitable for use
152 in escaping user data in ldap filters.
154 char *ldb_binary_encode_string(TALLOC_CTX *mem_ctx, const char *string)
156 struct ldb_val val;
157 if (string == NULL) {
158 return NULL;
160 val.data = discard_const_p(uint8_t, string);
161 val.length = strlen(string);
162 return ldb_binary_encode(mem_ctx, val);
165 /* find the first matching wildcard */
166 static char *ldb_parse_find_wildcard(char *value)
168 while (*value) {
169 value = strpbrk(value, "\\*");
170 if (value == NULL) return NULL;
172 if (value[0] == '\\') {
173 if (value[1] == '\0') return NULL;
174 value += 2;
175 continue;
178 if (value[0] == '*') return value;
181 return NULL;
184 /* return a NULL terminated list of binary strings representing the value
185 chunks separated by wildcards that makes the value portion of the filter
187 static struct ldb_val **ldb_wildcard_decode(TALLOC_CTX *mem_ctx, const char *string)
189 struct ldb_val **ret = NULL;
190 unsigned int val = 0;
191 char *wc, *str;
193 wc = talloc_strdup(mem_ctx, string);
194 if (wc == NULL) return NULL;
196 while (wc && *wc) {
197 str = wc;
198 wc = ldb_parse_find_wildcard(str);
199 if (wc && *wc) {
200 if (wc == str) {
201 wc++;
202 continue;
204 *wc = 0;
205 wc++;
208 ret = talloc_realloc(mem_ctx, ret, struct ldb_val *, val + 2);
209 if (ret == NULL) return NULL;
211 ret[val] = talloc(mem_ctx, struct ldb_val);
212 if (ret[val] == NULL) return NULL;
214 *(ret[val]) = ldb_binary_decode(mem_ctx, str);
215 if ((ret[val])->data == NULL) return NULL;
217 val++;
220 if (ret != NULL) {
221 ret[val] = NULL;
224 return ret;
227 static struct ldb_parse_tree *ldb_parse_filter(TALLOC_CTX *mem_ctx, const char **s);
231 parse an extended match
233 possible forms:
234 (attr:oid:=value)
235 (attr:dn:oid:=value)
236 (attr:dn:=value)
237 (:dn:oid:=value)
239 the ':dn' part sets the dnAttributes boolean if present
240 the oid sets the rule_id string
243 static struct ldb_parse_tree *ldb_parse_extended(struct ldb_parse_tree *ret,
244 char *attr, char *value)
246 char *p1, *p2;
248 ret->operation = LDB_OP_EXTENDED;
249 ret->u.extended.value = ldb_binary_decode(ret, value);
250 if (ret->u.extended.value.data == NULL) goto failed;
252 p1 = strchr(attr, ':');
253 if (p1 == NULL) goto failed;
254 p2 = strchr(p1+1, ':');
256 *p1 = 0;
257 if (p2) *p2 = 0;
259 ret->u.extended.attr = attr;
260 if (strcmp(p1+1, "dn") == 0) {
261 ret->u.extended.dnAttributes = 1;
262 if (p2) {
263 ret->u.extended.rule_id = talloc_strdup(ret, p2+1);
264 if (ret->u.extended.rule_id == NULL) goto failed;
265 } else {
266 ret->u.extended.rule_id = NULL;
268 } else {
269 ret->u.extended.dnAttributes = 0;
270 ret->u.extended.rule_id = talloc_strdup(ret, p1+1);
271 if (ret->u.extended.rule_id == NULL) goto failed;
274 return ret;
276 failed:
277 talloc_free(ret);
278 return NULL;
281 static enum ldb_parse_op ldb_parse_filtertype(TALLOC_CTX *mem_ctx, char **type, char **value, const char **s)
283 enum ldb_parse_op filter = 0;
284 char *name, *val, *k;
285 const char *p = *s;
286 const char *t, *t1;
288 /* retrieve attributetype name */
289 t = p;
291 if (*p == '@') { /* for internal attributes the first char can be @ */
292 p++;
295 while ((isascii(*p) && isalnum((unsigned char)*p)) || (*p == '-') || (*p == '.')) {
296 /* attribute names can only be alphanums */
297 p++;
300 if (*p == ':') { /* but extended searches have : and . chars too */
301 p = strstr(p, ":=");
302 if (p == NULL) { /* malformed attribute name */
303 return 0;
307 t1 = p;
309 while (isspace((unsigned char)*p)) p++;
311 if (!strchr("=<>~:", *p)) {
312 return 0;
315 /* save name */
316 name = (char *)talloc_memdup(mem_ctx, t, t1 - t + 1);
317 if (name == NULL) return 0;
318 name[t1 - t] = '\0';
320 /* retrieve filtertype */
322 if (*p == '=') {
323 filter = LDB_OP_EQUALITY;
324 } else if (*(p + 1) == '=') {
325 switch (*p) {
326 case '<':
327 filter = LDB_OP_LESS;
328 p++;
329 break;
330 case '>':
331 filter = LDB_OP_GREATER;
332 p++;
333 break;
334 case '~':
335 filter = LDB_OP_APPROX;
336 p++;
337 break;
338 case ':':
339 filter = LDB_OP_EXTENDED;
340 p++;
341 break;
344 if (!filter) {
345 talloc_free(name);
346 return filter;
348 p++;
350 while (isspace((unsigned char)*p)) p++;
352 /* retrieve value */
353 t = p;
355 while (*p && ((*p != ')') || ((*p == ')') && (*(p - 1) == '\\')))) p++;
357 val = (char *)talloc_memdup(mem_ctx, t, p - t + 1);
358 if (val == NULL) {
359 talloc_free(name);
360 return 0;
362 val[p - t] = '\0';
364 k = &(val[p - t]);
366 /* remove trailing spaces from value */
367 while ((k > val) && (isspace((unsigned char)*(k - 1)))) k--;
368 *k = '\0';
370 *type = name;
371 *value = val;
372 *s = p;
373 return filter;
377 <simple> ::= <attributetype> <filtertype> <attributevalue>
379 static struct ldb_parse_tree *ldb_parse_simple(TALLOC_CTX *mem_ctx, const char **s)
381 char *attr, *value;
382 struct ldb_parse_tree *ret;
383 enum ldb_parse_op filtertype;
385 ret = talloc(mem_ctx, struct ldb_parse_tree);
386 if (!ret) {
387 errno = ENOMEM;
388 return NULL;
391 filtertype = ldb_parse_filtertype(ret, &attr, &value, s);
392 if (!filtertype) {
393 talloc_free(ret);
394 return NULL;
397 switch (filtertype) {
399 case LDB_OP_PRESENT:
400 ret->operation = LDB_OP_PRESENT;
401 ret->u.present.attr = attr;
402 break;
404 case LDB_OP_EQUALITY:
406 if (strcmp(value, "*") == 0) {
407 ret->operation = LDB_OP_PRESENT;
408 ret->u.present.attr = attr;
409 break;
412 if (ldb_parse_find_wildcard(value) != NULL) {
413 ret->operation = LDB_OP_SUBSTRING;
414 ret->u.substring.attr = attr;
415 ret->u.substring.start_with_wildcard = 0;
416 ret->u.substring.end_with_wildcard = 0;
417 ret->u.substring.chunks = ldb_wildcard_decode(ret, value);
418 if (ret->u.substring.chunks == NULL){
419 talloc_free(ret);
420 return NULL;
422 if (value[0] == '*')
423 ret->u.substring.start_with_wildcard = 1;
424 if (value[strlen(value) - 1] == '*')
425 ret->u.substring.end_with_wildcard = 1;
426 talloc_free(value);
428 break;
431 ret->operation = LDB_OP_EQUALITY;
432 ret->u.equality.attr = attr;
433 ret->u.equality.value = ldb_binary_decode(ret, value);
434 if (ret->u.equality.value.data == NULL) {
435 talloc_free(ret);
436 return NULL;
438 talloc_free(value);
439 break;
441 case LDB_OP_GREATER:
442 ret->operation = LDB_OP_GREATER;
443 ret->u.comparison.attr = attr;
444 ret->u.comparison.value = ldb_binary_decode(ret, value);
445 if (ret->u.comparison.value.data == NULL) {
446 talloc_free(ret);
447 return NULL;
449 talloc_free(value);
450 break;
452 case LDB_OP_LESS:
453 ret->operation = LDB_OP_LESS;
454 ret->u.comparison.attr = attr;
455 ret->u.comparison.value = ldb_binary_decode(ret, value);
456 if (ret->u.comparison.value.data == NULL) {
457 talloc_free(ret);
458 return NULL;
460 talloc_free(value);
461 break;
463 case LDB_OP_APPROX:
464 ret->operation = LDB_OP_APPROX;
465 ret->u.comparison.attr = attr;
466 ret->u.comparison.value = ldb_binary_decode(ret, value);
467 if (ret->u.comparison.value.data == NULL) {
468 talloc_free(ret);
469 return NULL;
471 talloc_free(value);
472 break;
474 case LDB_OP_EXTENDED:
476 ret = ldb_parse_extended(ret, attr, value);
477 break;
479 default:
480 talloc_free(ret);
481 return NULL;
484 return ret;
489 parse a filterlist
490 <and> ::= '&' <filterlist>
491 <or> ::= '|' <filterlist>
492 <filterlist> ::= <filter> | <filter> <filterlist>
494 static struct ldb_parse_tree *ldb_parse_filterlist(TALLOC_CTX *mem_ctx, const char **s)
496 struct ldb_parse_tree *ret, *next;
497 enum ldb_parse_op op;
498 const char *p = *s;
500 switch (*p) {
501 case '&':
502 op = LDB_OP_AND;
503 break;
504 case '|':
505 op = LDB_OP_OR;
506 break;
507 default:
508 return NULL;
510 p++;
512 while (isspace((unsigned char)*p)) p++;
514 ret = talloc(mem_ctx, struct ldb_parse_tree);
515 if (!ret) {
516 errno = ENOMEM;
517 return NULL;
520 ret->operation = op;
521 ret->u.list.num_elements = 1;
522 ret->u.list.elements = talloc(ret, struct ldb_parse_tree *);
523 if (!ret->u.list.elements) {
524 errno = ENOMEM;
525 talloc_free(ret);
526 return NULL;
529 ret->u.list.elements[0] = ldb_parse_filter(ret->u.list.elements, &p);
530 if (!ret->u.list.elements[0]) {
531 talloc_free(ret);
532 return NULL;
535 while (isspace((unsigned char)*p)) p++;
537 while (*p) {
538 struct ldb_parse_tree **e;
539 if (*p == ')') {
540 break;
543 next = ldb_parse_filter(ret->u.list.elements, &p);
544 if (next == NULL) {
545 /* an invalid filter element */
546 talloc_free(ret);
547 return NULL;
549 e = talloc_realloc(ret, ret->u.list.elements,
550 struct ldb_parse_tree *,
551 ret->u.list.num_elements + 1);
552 if (!e) {
553 errno = ENOMEM;
554 talloc_free(ret);
555 return NULL;
557 ret->u.list.elements = e;
558 ret->u.list.elements[ret->u.list.num_elements] = next;
559 ret->u.list.num_elements++;
560 while (isspace((unsigned char)*p)) p++;
563 *s = p;
565 return ret;
570 <not> ::= '!' <filter>
572 static struct ldb_parse_tree *ldb_parse_not(TALLOC_CTX *mem_ctx, const char **s)
574 struct ldb_parse_tree *ret;
575 const char *p = *s;
577 if (*p != '!') {
578 return NULL;
580 p++;
582 ret = talloc(mem_ctx, struct ldb_parse_tree);
583 if (!ret) {
584 errno = ENOMEM;
585 return NULL;
588 ret->operation = LDB_OP_NOT;
589 ret->u.isnot.child = ldb_parse_filter(ret, &p);
590 if (!ret->u.isnot.child) {
591 talloc_free(ret);
592 return NULL;
595 *s = p;
597 return ret;
601 parse a filtercomp
602 <filtercomp> ::= <and> | <or> | <not> | <simple>
604 static struct ldb_parse_tree *ldb_parse_filtercomp(TALLOC_CTX *mem_ctx, const char **s)
606 struct ldb_parse_tree *ret;
607 const char *p = *s;
609 while (isspace((unsigned char)*p)) p++;
611 switch (*p) {
612 case '&':
613 ret = ldb_parse_filterlist(mem_ctx, &p);
614 break;
616 case '|':
617 ret = ldb_parse_filterlist(mem_ctx, &p);
618 break;
620 case '!':
621 ret = ldb_parse_not(mem_ctx, &p);
622 break;
624 case '(':
625 case ')':
626 return NULL;
628 default:
629 ret = ldb_parse_simple(mem_ctx, &p);
633 *s = p;
634 return ret;
639 <filter> ::= '(' <filtercomp> ')'
641 static struct ldb_parse_tree *ldb_parse_filter(TALLOC_CTX *mem_ctx, const char **s)
643 struct ldb_parse_tree *ret;
644 const char *p = *s;
646 if (*p != '(') {
647 return NULL;
649 p++;
651 ret = ldb_parse_filtercomp(mem_ctx, &p);
653 if (*p != ')') {
654 return NULL;
656 p++;
658 while (isspace((unsigned char)*p)) {
659 p++;
662 *s = p;
664 return ret;
669 main parser entry point. Takes a search string and returns a parse tree
671 expression ::= <simple> | <filter>
673 struct ldb_parse_tree *ldb_parse_tree(TALLOC_CTX *mem_ctx, const char *s)
675 if (s == NULL || *s == 0) {
676 s = "(|(objectClass=*)(distinguishedName=*))";
679 while (isspace((unsigned char)*s)) s++;
681 if (*s == '(') {
682 return ldb_parse_filter(mem_ctx, &s);
685 return ldb_parse_simple(mem_ctx, &s);
690 construct a ldap parse filter given a parse tree
692 char *ldb_filter_from_tree(TALLOC_CTX *mem_ctx, const struct ldb_parse_tree *tree)
694 char *s, *s2, *ret;
695 unsigned int i;
697 if (tree == NULL) {
698 return NULL;
701 switch (tree->operation) {
702 case LDB_OP_AND:
703 case LDB_OP_OR:
704 ret = talloc_asprintf(mem_ctx, "(%c", tree->operation==LDB_OP_AND?'&':'|');
705 if (ret == NULL) return NULL;
706 for (i=0;i<tree->u.list.num_elements;i++) {
707 s = ldb_filter_from_tree(mem_ctx, tree->u.list.elements[i]);
708 if (s == NULL) {
709 talloc_free(ret);
710 return NULL;
712 s2 = talloc_asprintf_append(ret, "%s", s);
713 talloc_free(s);
714 if (s2 == NULL) {
715 talloc_free(ret);
716 return NULL;
718 ret = s2;
720 s = talloc_asprintf_append(ret, ")");
721 if (s == NULL) {
722 talloc_free(ret);
723 return NULL;
725 return s;
726 case LDB_OP_NOT:
727 s = ldb_filter_from_tree(mem_ctx, tree->u.isnot.child);
728 if (s == NULL) return NULL;
730 ret = talloc_asprintf(mem_ctx, "(!%s)", s);
731 talloc_free(s);
732 return ret;
733 case LDB_OP_EQUALITY:
734 s = ldb_binary_encode(mem_ctx, tree->u.equality.value);
735 if (s == NULL) return NULL;
736 ret = talloc_asprintf(mem_ctx, "(%s=%s)",
737 tree->u.equality.attr, s);
738 talloc_free(s);
739 return ret;
740 case LDB_OP_SUBSTRING:
741 ret = talloc_asprintf(mem_ctx, "(%s=%s", tree->u.substring.attr,
742 tree->u.substring.start_with_wildcard?"*":"");
743 if (ret == NULL) return NULL;
744 for (i = 0; tree->u.substring.chunks[i]; i++) {
745 s2 = ldb_binary_encode(mem_ctx, *(tree->u.substring.chunks[i]));
746 if (s2 == NULL) {
747 talloc_free(ret);
748 return NULL;
750 if (tree->u.substring.chunks[i+1] ||
751 tree->u.substring.end_with_wildcard) {
752 s = talloc_asprintf_append(ret, "%s*", s2);
753 } else {
754 s = talloc_asprintf_append(ret, "%s", s2);
756 if (s == NULL) {
757 talloc_free(ret);
758 return NULL;
760 ret = s;
762 s = talloc_asprintf_append(ret, ")");
763 if (s == NULL) {
764 talloc_free(ret);
765 return NULL;
767 ret = s;
768 return ret;
769 case LDB_OP_GREATER:
770 s = ldb_binary_encode(mem_ctx, tree->u.equality.value);
771 if (s == NULL) return NULL;
772 ret = talloc_asprintf(mem_ctx, "(%s>=%s)",
773 tree->u.equality.attr, s);
774 talloc_free(s);
775 return ret;
776 case LDB_OP_LESS:
777 s = ldb_binary_encode(mem_ctx, tree->u.equality.value);
778 if (s == NULL) return NULL;
779 ret = talloc_asprintf(mem_ctx, "(%s<=%s)",
780 tree->u.equality.attr, s);
781 talloc_free(s);
782 return ret;
783 case LDB_OP_PRESENT:
784 ret = talloc_asprintf(mem_ctx, "(%s=*)", tree->u.present.attr);
785 return ret;
786 case LDB_OP_APPROX:
787 s = ldb_binary_encode(mem_ctx, tree->u.equality.value);
788 if (s == NULL) return NULL;
789 ret = talloc_asprintf(mem_ctx, "(%s~=%s)",
790 tree->u.equality.attr, s);
791 talloc_free(s);
792 return ret;
793 case LDB_OP_EXTENDED:
794 s = ldb_binary_encode(mem_ctx, tree->u.extended.value);
795 if (s == NULL) return NULL;
796 ret = talloc_asprintf(mem_ctx, "(%s%s%s%s:=%s)",
797 tree->u.extended.attr?tree->u.extended.attr:"",
798 tree->u.extended.dnAttributes?":dn":"",
799 tree->u.extended.rule_id?":":"",
800 tree->u.extended.rule_id?tree->u.extended.rule_id:"",
802 talloc_free(s);
803 return ret;
806 return NULL;
811 walk a parse tree, calling the provided callback on each node
813 int ldb_parse_tree_walk(struct ldb_parse_tree *tree,
814 int (*callback)(struct ldb_parse_tree *tree, void *),
815 void *private_context)
817 unsigned int i;
818 int ret;
820 ret = callback(tree, private_context);
821 if (ret != LDB_SUCCESS) {
822 return ret;
825 switch (tree->operation) {
826 case LDB_OP_AND:
827 case LDB_OP_OR:
828 for (i=0;i<tree->u.list.num_elements;i++) {
829 ret = ldb_parse_tree_walk(tree->u.list.elements[i], callback, private_context);
830 if (ret != LDB_SUCCESS) {
831 return ret;
834 break;
835 case LDB_OP_NOT:
836 ret = ldb_parse_tree_walk(tree->u.isnot.child, callback, private_context);
837 if (ret != LDB_SUCCESS) {
838 return ret;
840 break;
841 case LDB_OP_EQUALITY:
842 case LDB_OP_GREATER:
843 case LDB_OP_LESS:
844 case LDB_OP_APPROX:
845 case LDB_OP_SUBSTRING:
846 case LDB_OP_PRESENT:
847 case LDB_OP_EXTENDED:
848 break;
850 return LDB_SUCCESS;
853 struct parse_tree_attr_replace_ctx {
854 const char *attr;
855 const char *replace;
859 callback for ldb_parse_tree_attr_replace()
861 static int parse_tree_attr_replace(struct ldb_parse_tree *tree, void *private_context)
863 struct parse_tree_attr_replace_ctx *ctx = private_context;
864 switch (tree->operation) {
865 case LDB_OP_EQUALITY:
866 case LDB_OP_GREATER:
867 case LDB_OP_LESS:
868 case LDB_OP_APPROX:
869 if (ldb_attr_cmp(tree->u.equality.attr, ctx->attr) == 0) {
870 tree->u.equality.attr = ctx->replace;
872 break;
873 case LDB_OP_SUBSTRING:
874 if (ldb_attr_cmp(tree->u.substring.attr, ctx->attr) == 0) {
875 tree->u.substring.attr = ctx->replace;
877 break;
878 case LDB_OP_PRESENT:
879 if (ldb_attr_cmp(tree->u.present.attr, ctx->attr) == 0) {
880 tree->u.present.attr = ctx->replace;
882 break;
883 case LDB_OP_EXTENDED:
884 if (tree->u.extended.attr &&
885 ldb_attr_cmp(tree->u.extended.attr, ctx->attr) == 0) {
886 tree->u.extended.attr = ctx->replace;
888 break;
889 default:
890 break;
892 return LDB_SUCCESS;
896 replace any occurrences of an attribute name in the parse tree with a
897 new name
899 void ldb_parse_tree_attr_replace(struct ldb_parse_tree *tree,
900 const char *attr,
901 const char *replace)
903 struct parse_tree_attr_replace_ctx ctx;
905 ctx.attr = attr;
906 ctx.replace = replace;
908 ldb_parse_tree_walk(tree, parse_tree_attr_replace, &ctx);
912 shallow copy a tree - copying only the elements array so that the caller
913 can safely add new elements without changing the message
915 struct ldb_parse_tree *ldb_parse_tree_copy_shallow(TALLOC_CTX *mem_ctx,
916 const struct ldb_parse_tree *ot)
918 unsigned int i;
919 struct ldb_parse_tree *nt;
921 nt = talloc(mem_ctx, struct ldb_parse_tree);
922 if (!nt) {
923 return NULL;
926 *nt = *ot;
928 switch (ot->operation) {
929 case LDB_OP_AND:
930 case LDB_OP_OR:
931 nt->u.list.elements = talloc_array(nt, struct ldb_parse_tree *,
932 ot->u.list.num_elements);
933 if (!nt->u.list.elements) {
934 talloc_free(nt);
935 return NULL;
938 for (i=0;i<ot->u.list.num_elements;i++) {
939 nt->u.list.elements[i] =
940 ldb_parse_tree_copy_shallow(nt->u.list.elements,
941 ot->u.list.elements[i]);
942 if (!nt->u.list.elements[i]) {
943 talloc_free(nt);
944 return NULL;
947 break;
948 case LDB_OP_NOT:
949 nt->u.isnot.child = ldb_parse_tree_copy_shallow(nt,
950 ot->u.isnot.child);
951 if (!nt->u.isnot.child) {
952 talloc_free(nt);
953 return NULL;
955 break;
956 case LDB_OP_EQUALITY:
957 case LDB_OP_GREATER:
958 case LDB_OP_LESS:
959 case LDB_OP_APPROX:
960 case LDB_OP_SUBSTRING:
961 case LDB_OP_PRESENT:
962 case LDB_OP_EXTENDED:
963 break;
966 return nt;