/src/samba/lib/ldb/common/ldb_parse.c
Line | Count | Source |
1 | | /* |
2 | | ldb database library |
3 | | |
4 | | Copyright (C) Andrew Tridgell 2004 |
5 | | |
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 |
9 | | |
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. |
14 | | |
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. |
19 | | |
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/>. |
22 | | */ |
23 | | |
24 | | /* |
25 | | * Name: ldb |
26 | | * |
27 | | * Component: ldb expression parsing |
28 | | * |
29 | | * Description: parse LDAP-like search expressions |
30 | | * |
31 | | * Author: Andrew Tridgell |
32 | | */ |
33 | | |
34 | | /* |
35 | | TODO: |
36 | | - add RFC2254 binary string handling |
37 | | - possibly add ~=, <= and >= handling |
38 | | - expand the test suite |
39 | | - add better parse error handling |
40 | | |
41 | | */ |
42 | | |
43 | | #include "ldb_private.h" |
44 | | #include "system/locale.h" |
45 | | |
46 | | /* |
47 | | * Maximum depth of the filter parse tree, the value chosen is small enough to |
48 | | * avoid triggering ASAN stack overflow checks. But large enough to be useful. |
49 | | * |
50 | | * On Windows clients the maximum number of levels of recursion allowed is 100. |
51 | | * In the LDAP server, Windows restricts clients to 512 nested |
52 | | * (eg) OR statements. |
53 | | */ |
54 | 402 | #define LDB_MAX_PARSE_TREE_DEPTH 128 |
55 | | |
56 | | /* |
57 | | a filter is defined by: |
58 | | <filter> ::= '(' <filtercomp> ')' |
59 | | <filtercomp> ::= <and> | <or> | <not> | <simple> |
60 | | <and> ::= '&' <filterlist> |
61 | | <or> ::= '|' <filterlist> |
62 | | <not> ::= '!' <filter> |
63 | | <filterlist> ::= <filter> | <filter> <filterlist> |
64 | | <simple> ::= <attributetype> <filtertype> <attributevalue> |
65 | | <filtertype> ::= '=' | '~=' | '<=' | '>=' |
66 | | */ |
67 | | |
68 | | /* |
69 | | decode a RFC2254 binary string representation of a buffer. |
70 | | Used in LDAP filters. |
71 | | */ |
72 | | struct ldb_val ldb_binary_decode(TALLOC_CTX *mem_ctx, const char *str) |
73 | 217k | { |
74 | 217k | size_t i, j; |
75 | 217k | struct ldb_val ret; |
76 | 217k | size_t slen = str?strlen(str):0; |
77 | | |
78 | 217k | ret.data = (uint8_t *)talloc_size(mem_ctx, slen+1); |
79 | 217k | ret.length = 0; |
80 | 217k | if (ret.data == NULL) return ret; |
81 | | |
82 | 35.3M | for (i=j=0;i<slen;i++) { |
83 | 35.1M | if (str[i] == '\\') { |
84 | 205k | uint8_t c; |
85 | 205k | bool ok; |
86 | | |
87 | 205k | ok = hex_byte(&str[i+1], &c); |
88 | 205k | if (!ok) { |
89 | 169 | talloc_free(ret.data); |
90 | 169 | return (struct ldb_val){}; |
91 | 169 | } |
92 | 205k | ((uint8_t *)ret.data)[j++] = c; |
93 | 205k | i += 2; |
94 | 34.9M | } else { |
95 | 34.9M | ((uint8_t *)ret.data)[j++] = str[i]; |
96 | 34.9M | } |
97 | 35.1M | } |
98 | 217k | ret.length = j; |
99 | 217k | ((uint8_t *)ret.data)[j] = 0; |
100 | | |
101 | 217k | return ret; |
102 | 217k | } |
103 | | |
104 | | static bool need_encode(unsigned char cval) |
105 | 79.5M | { |
106 | 79.5M | if (cval < 0x20 || cval > 0x7E || strchr(" *()\\&|!\"", cval)) { |
107 | 59.4M | return true; |
108 | 59.4M | } |
109 | 20.0M | return false; |
110 | 79.5M | } |
111 | | |
112 | | /* |
113 | | encode a blob as a RFC2254 binary string, escaping any |
114 | | non-printable or '\' characters |
115 | | */ |
116 | | char *ldb_binary_encode(TALLOC_CTX *mem_ctx, struct ldb_val val) |
117 | 214k | { |
118 | 214k | size_t i; |
119 | 214k | char *ret; |
120 | 214k | size_t len = val.length; |
121 | 214k | unsigned char *buf = val.data; |
122 | | |
123 | 39.9M | for (i=0;i<val.length;i++) { |
124 | 39.7M | if (need_encode(buf[i])) { |
125 | 29.7M | len += 2; |
126 | 29.7M | } |
127 | 39.7M | } |
128 | 214k | ret = talloc_array(mem_ctx, char, len+1); |
129 | 214k | if (ret == NULL) return NULL; |
130 | | |
131 | 214k | len = 0; |
132 | 39.9M | for (i=0;i<val.length;i++) { |
133 | 39.7M | if (need_encode(buf[i])) { |
134 | 29.7M | snprintf(ret+len, 4, "\\%02X", buf[i]); |
135 | 29.7M | len += 3; |
136 | 29.7M | } else { |
137 | 10.0M | ret[len++] = buf[i]; |
138 | 10.0M | } |
139 | 39.7M | } |
140 | | |
141 | 214k | ret[len] = 0; |
142 | | |
143 | 214k | return ret; |
144 | 214k | } |
145 | | |
146 | | /* |
147 | | encode a string as a RFC2254 binary string, escaping any |
148 | | non-printable or '\' characters. This routine is suitable for use |
149 | | in escaping user data in ldap filters. |
150 | | */ |
151 | | char *ldb_binary_encode_string(TALLOC_CTX *mem_ctx, const char *string) |
152 | 208 | { |
153 | 208 | struct ldb_val val; |
154 | 208 | if (string == NULL) { |
155 | 0 | return NULL; |
156 | 0 | } |
157 | 208 | val.data = discard_const_p(uint8_t, string); |
158 | 208 | val.length = strlen(string); |
159 | 208 | return ldb_binary_encode(mem_ctx, val); |
160 | 208 | } |
161 | | |
162 | | /* find the first matching wildcard */ |
163 | | static char *ldb_parse_find_wildcard(char *value) |
164 | 216k | { |
165 | 218k | while (*value) { |
166 | 91.8k | value = strpbrk(value, "\\*"); |
167 | 91.8k | if (value == NULL) return NULL; |
168 | | |
169 | 76.0k | if (value[0] == '\\') { |
170 | 1.70k | if (value[1] == '\0') return NULL; |
171 | 1.69k | value += 2; |
172 | 1.69k | continue; |
173 | 1.70k | } |
174 | | |
175 | 74.3k | if (value[0] == '*') return value; |
176 | 74.3k | } |
177 | | |
178 | 126k | return NULL; |
179 | 216k | } |
180 | | |
181 | | /* return a NULL terminated list of binary strings representing the value |
182 | | chunks separated by wildcards that makes the value portion of the filter |
183 | | */ |
184 | | static struct ldb_val **ldb_wildcard_decode(TALLOC_CTX *mem_ctx, const char *string) |
185 | 1.15k | { |
186 | 1.15k | struct ldb_val **ret = NULL; |
187 | 1.15k | unsigned int val = 0; |
188 | 1.15k | char *wc, *str; |
189 | | |
190 | 1.15k | wc = talloc_strdup(mem_ctx, string); |
191 | 1.15k | if (wc == NULL) return NULL; |
192 | | |
193 | 75.0k | while (wc && *wc) { |
194 | 73.8k | str = wc; |
195 | 73.8k | wc = ldb_parse_find_wildcard(str); |
196 | 73.8k | if (wc && *wc) { |
197 | 73.1k | if (wc == str) { |
198 | 842 | wc++; |
199 | 842 | continue; |
200 | 842 | } |
201 | 72.3k | *wc = 0; |
202 | 72.3k | wc++; |
203 | 72.3k | } |
204 | | |
205 | 73.0k | ret = talloc_realloc(mem_ctx, ret, struct ldb_val *, val + 2); |
206 | 73.0k | if (ret == NULL) return NULL; |
207 | | |
208 | 73.0k | ret[val] = talloc(mem_ctx, struct ldb_val); |
209 | 73.0k | if (ret[val] == NULL) return NULL; |
210 | | |
211 | 73.0k | *(ret[val]) = ldb_binary_decode(mem_ctx, str); |
212 | 73.0k | if ((ret[val])->data == NULL) return NULL; |
213 | | |
214 | 73.0k | val++; |
215 | 73.0k | } |
216 | | |
217 | 1.13k | if (ret != NULL) { |
218 | 1.12k | ret[val] = NULL; |
219 | 1.12k | } |
220 | | |
221 | 1.13k | return ret; |
222 | 1.15k | } |
223 | | |
224 | | static struct ldb_parse_tree *ldb_parse_filter( |
225 | | TALLOC_CTX *mem_ctx, |
226 | | const char **s, |
227 | | unsigned depth, |
228 | | unsigned max_depth); |
229 | | |
230 | | |
231 | | /* |
232 | | parse an extended match |
233 | | |
234 | | possible forms: |
235 | | (attr:oid:=value) |
236 | | (attr:dn:oid:=value) |
237 | | (attr:dn:=value) |
238 | | (:dn:oid:=value) |
239 | | |
240 | | the ':dn' part sets the dnAttributes boolean if present |
241 | | the oid sets the rule_id string |
242 | | |
243 | | */ |
244 | | static struct ldb_parse_tree *ldb_parse_extended(struct ldb_parse_tree *ret, |
245 | | char *attr, char *value) |
246 | 1.11k | { |
247 | 1.11k | char *p1, *p2; |
248 | | |
249 | 1.11k | ret->operation = LDB_OP_EXTENDED; |
250 | 1.11k | ret->u.extended.value = ldb_binary_decode(ret, value); |
251 | 1.11k | if (ret->u.extended.value.data == NULL) goto failed; |
252 | | |
253 | 1.11k | p1 = strchr(attr, ':'); |
254 | 1.11k | if (p1 == NULL) goto failed; |
255 | 1.11k | p2 = strchr(p1+1, ':'); |
256 | | |
257 | 1.11k | *p1 = 0; |
258 | 1.11k | if (p2) *p2 = 0; |
259 | | |
260 | 1.11k | ret->u.extended.attr = attr; |
261 | 1.11k | if (strcmp(p1+1, "dn") == 0) { |
262 | 581 | ret->u.extended.dnAttributes = 1; |
263 | 581 | if (p2) { |
264 | 194 | ret->u.extended.rule_id = talloc_strdup(ret, p2+1); |
265 | 194 | if (ret->u.extended.rule_id == NULL) goto failed; |
266 | 387 | } else { |
267 | 387 | ret->u.extended.rule_id = NULL; |
268 | 387 | } |
269 | 581 | } else { |
270 | 530 | ret->u.extended.dnAttributes = 0; |
271 | 530 | ret->u.extended.rule_id = talloc_strdup(ret, p1+1); |
272 | 530 | if (ret->u.extended.rule_id == NULL) goto failed; |
273 | 530 | } |
274 | | |
275 | 1.11k | return ret; |
276 | | |
277 | 8 | failed: |
278 | 8 | talloc_free(ret); |
279 | 8 | return NULL; |
280 | 1.11k | } |
281 | | |
282 | | static enum ldb_parse_op ldb_parse_filtertype(TALLOC_CTX *mem_ctx, char **type, char **value, const char **s) |
283 | 145k | { |
284 | 145k | enum ldb_parse_op filter = 0; |
285 | 145k | char *name, *val, *k; |
286 | 145k | const char *p = *s; |
287 | 145k | const char *t, *t1; |
288 | | |
289 | | /* retrieve attributetype name */ |
290 | 145k | t = p; |
291 | | |
292 | 145k | if (*p == '@') { /* for internal attributes the first char can be @ */ |
293 | 194 | p++; |
294 | 194 | } |
295 | | |
296 | 147k | while ((isascii(*p) && isalnum((unsigned char)*p)) || (*p == '-') || (*p == '.')) { |
297 | | /* attribute names can only be alphanums */ |
298 | 1.67k | p++; |
299 | 1.67k | } |
300 | | |
301 | 145k | if (*p == ':') { /* but extended searches have : and . chars too */ |
302 | 1.12k | p = strstr(p, ":="); |
303 | 1.12k | if (p == NULL) { /* malformed attribute name */ |
304 | 1 | return 0; |
305 | 1 | } |
306 | 1.12k | } |
307 | | |
308 | 145k | t1 = p; |
309 | | |
310 | 145k | while (isspace((unsigned char)*p)) p++; |
311 | | |
312 | 145k | if (!strchr("=<>~:", *p)) { |
313 | 30 | return 0; |
314 | 30 | } |
315 | | |
316 | | /* save name */ |
317 | 145k | name = (char *)talloc_memdup(mem_ctx, t, t1 - t + 1); |
318 | 145k | if (name == NULL) return 0; |
319 | 145k | name[t1 - t] = '\0'; |
320 | | |
321 | | /* retrieve filtertype */ |
322 | | |
323 | 145k | if (*p == '=') { |
324 | 143k | filter = LDB_OP_EQUALITY; |
325 | 143k | } else if (*p != '\0' && *(p + 1) == '=') { |
326 | 2.31k | switch (*p) { |
327 | 389 | case '<': |
328 | 389 | filter = LDB_OP_LESS; |
329 | 389 | p++; |
330 | 389 | break; |
331 | 419 | case '>': |
332 | 419 | filter = LDB_OP_GREATER; |
333 | 419 | p++; |
334 | 419 | break; |
335 | 390 | case '~': |
336 | 390 | filter = LDB_OP_APPROX; |
337 | 390 | p++; |
338 | 390 | break; |
339 | 1.11k | case ':': |
340 | 1.11k | filter = LDB_OP_EXTENDED; |
341 | 1.11k | p++; |
342 | 1.11k | break; |
343 | 2.31k | } |
344 | 2.31k | } |
345 | 145k | if (!filter) { |
346 | 104 | talloc_free(name); |
347 | 104 | return 0; |
348 | 104 | } |
349 | 145k | p++; |
350 | | |
351 | 145k | while (isspace((unsigned char)*p)) p++; |
352 | | |
353 | | /* retrieve value */ |
354 | 145k | t = p; |
355 | | |
356 | 14.8M | while (*p && ((*p != ')') || ((*p == ')') && (*(p - 1) == '\\')))) p++; |
357 | | |
358 | 145k | val = (char *)talloc_memdup(mem_ctx, t, p - t + 1); |
359 | 145k | if (val == NULL) { |
360 | 0 | talloc_free(name); |
361 | 0 | return 0; |
362 | 0 | } |
363 | 145k | val[p - t] = '\0'; |
364 | | |
365 | 145k | k = &(val[p - t]); |
366 | | |
367 | | /* remove trailing spaces from value */ |
368 | 146k | while ((k > val) && (isspace((unsigned char)*(k - 1)))) k--; |
369 | 145k | *k = '\0'; |
370 | | |
371 | 145k | *type = name; |
372 | 145k | *value = val; |
373 | 145k | *s = p; |
374 | 145k | return filter; |
375 | 145k | } |
376 | | |
377 | | /* |
378 | | <simple> ::= <attributetype> <filtertype> <attributevalue> |
379 | | */ |
380 | | static struct ldb_parse_tree *ldb_parse_simple(TALLOC_CTX *mem_ctx, const char **s) |
381 | 145k | { |
382 | 145k | char *attr, *value; |
383 | 145k | struct ldb_parse_tree *ret; |
384 | 145k | enum ldb_parse_op filtertype; |
385 | | |
386 | 145k | ret = talloc_zero(mem_ctx, struct ldb_parse_tree); |
387 | 145k | if (!ret) { |
388 | 0 | errno = ENOMEM; |
389 | 0 | return NULL; |
390 | 0 | } |
391 | | |
392 | 145k | filtertype = ldb_parse_filtertype(ret, &attr, &value, s); |
393 | 145k | if (!filtertype) { |
394 | 135 | talloc_free(ret); |
395 | 135 | return NULL; |
396 | 135 | } |
397 | | |
398 | 145k | switch (filtertype) { |
399 | | |
400 | 0 | case LDB_OP_PRESENT: |
401 | 0 | ret->operation = LDB_OP_PRESENT; |
402 | 0 | ret->u.present.attr = attr; |
403 | 0 | break; |
404 | | |
405 | 143k | case LDB_OP_EQUALITY: |
406 | | |
407 | 143k | if (strcmp(value, "*") == 0) { |
408 | 564 | ret->operation = LDB_OP_PRESENT; |
409 | 564 | ret->u.present.attr = attr; |
410 | 564 | break; |
411 | 564 | } |
412 | | |
413 | 142k | if (ldb_parse_find_wildcard(value) != NULL) { |
414 | 1.15k | ret->operation = LDB_OP_SUBSTRING; |
415 | 1.15k | ret->u.substring.attr = attr; |
416 | 1.15k | ret->u.substring.start_with_wildcard = 0; |
417 | 1.15k | ret->u.substring.end_with_wildcard = 0; |
418 | 1.15k | ret->u.substring.chunks = ldb_wildcard_decode(ret, value); |
419 | 1.15k | if (ret->u.substring.chunks == NULL){ |
420 | 29 | talloc_free(ret); |
421 | 29 | return NULL; |
422 | 29 | } |
423 | 1.12k | if (value[0] == '*') |
424 | 410 | ret->u.substring.start_with_wildcard = 1; |
425 | 1.12k | if (value[strlen(value) - 1] == '*') |
426 | 422 | ret->u.substring.end_with_wildcard = 1; |
427 | 1.12k | talloc_free(value); |
428 | | |
429 | 1.12k | break; |
430 | 1.15k | } |
431 | | |
432 | 141k | ret->operation = LDB_OP_EQUALITY; |
433 | 141k | ret->u.equality.attr = attr; |
434 | 141k | ret->u.equality.value = ldb_binary_decode(ret, value); |
435 | 141k | if (ret->u.equality.value.data == NULL) { |
436 | 68 | talloc_free(ret); |
437 | 68 | return NULL; |
438 | 68 | } |
439 | 141k | talloc_free(value); |
440 | 141k | break; |
441 | | |
442 | 419 | case LDB_OP_GREATER: |
443 | 419 | ret->operation = LDB_OP_GREATER; |
444 | 419 | ret->u.comparison.attr = attr; |
445 | 419 | ret->u.comparison.value = ldb_binary_decode(ret, value); |
446 | 419 | if (ret->u.comparison.value.data == NULL) { |
447 | 1 | talloc_free(ret); |
448 | 1 | return NULL; |
449 | 1 | } |
450 | 418 | talloc_free(value); |
451 | 418 | break; |
452 | | |
453 | 389 | case LDB_OP_LESS: |
454 | 389 | ret->operation = LDB_OP_LESS; |
455 | 389 | ret->u.comparison.attr = attr; |
456 | 389 | ret->u.comparison.value = ldb_binary_decode(ret, value); |
457 | 389 | if (ret->u.comparison.value.data == NULL) { |
458 | 1 | talloc_free(ret); |
459 | 1 | return NULL; |
460 | 1 | } |
461 | 388 | talloc_free(value); |
462 | 388 | break; |
463 | | |
464 | 390 | case LDB_OP_APPROX: |
465 | 390 | ret->operation = LDB_OP_APPROX; |
466 | 390 | ret->u.comparison.attr = attr; |
467 | 390 | ret->u.comparison.value = ldb_binary_decode(ret, value); |
468 | 390 | if (ret->u.comparison.value.data == NULL) { |
469 | 1 | talloc_free(ret); |
470 | 1 | return NULL; |
471 | 1 | } |
472 | 389 | talloc_free(value); |
473 | 389 | break; |
474 | | |
475 | 1.11k | case LDB_OP_EXTENDED: |
476 | | |
477 | 1.11k | ret = ldb_parse_extended(ret, attr, value); |
478 | 1.11k | break; |
479 | | |
480 | 0 | default: |
481 | 0 | talloc_free(ret); |
482 | 0 | return NULL; |
483 | 145k | } |
484 | | |
485 | 145k | return ret; |
486 | 145k | } |
487 | | |
488 | | |
489 | | /* |
490 | | parse a filterlist |
491 | | <and> ::= '&' <filterlist> |
492 | | <or> ::= '|' <filterlist> |
493 | | <filterlist> ::= <filter> | <filter> <filterlist> |
494 | | */ |
495 | | static struct ldb_parse_tree *ldb_parse_filterlist( |
496 | | TALLOC_CTX *mem_ctx, |
497 | | const char **s, |
498 | | unsigned depth, |
499 | | unsigned max_depth) |
500 | 3.79k | { |
501 | 3.79k | struct ldb_parse_tree *ret, *next; |
502 | 3.79k | enum ldb_parse_op op; |
503 | 3.79k | const char *p = *s; |
504 | | |
505 | 3.79k | switch (*p) { |
506 | 2.22k | case '&': |
507 | 2.22k | op = LDB_OP_AND; |
508 | 2.22k | break; |
509 | 1.56k | case '|': |
510 | 1.56k | op = LDB_OP_OR; |
511 | 1.56k | break; |
512 | 0 | default: |
513 | 0 | return NULL; |
514 | 3.79k | } |
515 | 3.79k | p++; |
516 | | |
517 | 3.79k | while (isspace((unsigned char)*p)) p++; |
518 | | |
519 | 3.79k | ret = talloc(mem_ctx, struct ldb_parse_tree); |
520 | 3.79k | if (!ret) { |
521 | 0 | errno = ENOMEM; |
522 | 0 | return NULL; |
523 | 0 | } |
524 | | |
525 | 3.79k | ret->operation = op; |
526 | 3.79k | ret->u.list.num_elements = 1; |
527 | 3.79k | ret->u.list.elements = talloc(ret, struct ldb_parse_tree *); |
528 | 3.79k | if (!ret->u.list.elements) { |
529 | 0 | errno = ENOMEM; |
530 | 0 | talloc_free(ret); |
531 | 0 | return NULL; |
532 | 0 | } |
533 | | |
534 | 3.79k | ret->u.list.elements[0] = |
535 | 3.79k | ldb_parse_filter(ret->u.list.elements, &p, depth, max_depth); |
536 | 3.79k | if (!ret->u.list.elements[0]) { |
537 | 2.89k | talloc_free(ret); |
538 | 2.89k | return NULL; |
539 | 2.89k | } |
540 | | |
541 | 897 | while (isspace((unsigned char)*p)) p++; |
542 | | |
543 | 145k | while (*p) { |
544 | 145k | struct ldb_parse_tree **e; |
545 | 145k | if (*p == ')') { |
546 | 581 | break; |
547 | 581 | } |
548 | | |
549 | 145k | next = ldb_parse_filter( |
550 | 145k | ret->u.list.elements, &p, depth, max_depth); |
551 | 145k | if (next == NULL) { |
552 | | /* an invalid filter element */ |
553 | 304 | talloc_free(ret); |
554 | 304 | return NULL; |
555 | 304 | } |
556 | 144k | e = talloc_realloc(ret, ret->u.list.elements, |
557 | 144k | struct ldb_parse_tree *, |
558 | 144k | ret->u.list.num_elements + 1); |
559 | 144k | if (!e) { |
560 | 0 | errno = ENOMEM; |
561 | 0 | talloc_free(ret); |
562 | 0 | return NULL; |
563 | 0 | } |
564 | 144k | ret->u.list.elements = e; |
565 | 144k | ret->u.list.elements[ret->u.list.num_elements] = next; |
566 | 144k | ret->u.list.num_elements++; |
567 | 144k | while (isspace((unsigned char)*p)) p++; |
568 | 144k | } |
569 | | |
570 | 593 | *s = p; |
571 | | |
572 | 593 | return ret; |
573 | 897 | } |
574 | | |
575 | | |
576 | | /* |
577 | | <not> ::= '!' <filter> |
578 | | */ |
579 | | static struct ldb_parse_tree *ldb_parse_not( |
580 | | TALLOC_CTX *mem_ctx, |
581 | | const char **s, |
582 | | unsigned depth, |
583 | | unsigned max_depth) |
584 | 783 | { |
585 | 783 | struct ldb_parse_tree *ret; |
586 | 783 | const char *p = *s; |
587 | | |
588 | 783 | if (*p != '!') { |
589 | 0 | return NULL; |
590 | 0 | } |
591 | 783 | p++; |
592 | | |
593 | 783 | ret = talloc(mem_ctx, struct ldb_parse_tree); |
594 | 783 | if (!ret) { |
595 | 0 | errno = ENOMEM; |
596 | 0 | return NULL; |
597 | 0 | } |
598 | | |
599 | 783 | ret->operation = LDB_OP_NOT; |
600 | 783 | ret->u.isnot.child = ldb_parse_filter(ret, &p, depth, max_depth); |
601 | 783 | if (!ret->u.isnot.child) { |
602 | 209 | talloc_free(ret); |
603 | 209 | return NULL; |
604 | 209 | } |
605 | | |
606 | 574 | *s = p; |
607 | | |
608 | 574 | return ret; |
609 | 783 | } |
610 | | |
611 | | /* |
612 | | parse a filtercomp |
613 | | <filtercomp> ::= <and> | <or> | <not> | <simple> |
614 | | */ |
615 | | static struct ldb_parse_tree *ldb_parse_filtercomp( |
616 | | TALLOC_CTX *mem_ctx, |
617 | | const char **s, |
618 | | unsigned depth, |
619 | | unsigned max_depth) |
620 | 149k | { |
621 | 149k | struct ldb_parse_tree *ret; |
622 | 149k | const char *p = *s; |
623 | | |
624 | 149k | while (isspace((unsigned char)*p)) p++; |
625 | | |
626 | 149k | switch (*p) { |
627 | 2.22k | case '&': |
628 | 2.22k | ret = ldb_parse_filterlist(mem_ctx, &p, depth, max_depth); |
629 | 2.22k | break; |
630 | | |
631 | 1.56k | case '|': |
632 | 1.56k | ret = ldb_parse_filterlist(mem_ctx, &p, depth, max_depth); |
633 | 1.56k | break; |
634 | | |
635 | 783 | case '!': |
636 | 783 | ret = ldb_parse_not(mem_ctx, &p, depth, max_depth); |
637 | 783 | break; |
638 | | |
639 | 1 | case '(': |
640 | 10 | case ')': |
641 | 10 | return NULL; |
642 | | |
643 | 145k | default: |
644 | 145k | ret = ldb_parse_simple(mem_ctx, &p); |
645 | | |
646 | 149k | } |
647 | | |
648 | 149k | *s = p; |
649 | 149k | return ret; |
650 | 149k | } |
651 | | |
652 | | /* |
653 | | <filter> ::= '(' <filtercomp> ')' |
654 | | */ |
655 | | static struct ldb_parse_tree *ldb_parse_filter( |
656 | | TALLOC_CTX *mem_ctx, |
657 | | const char **s, |
658 | | unsigned depth, |
659 | | unsigned max_depth) |
660 | 150k | { |
661 | 150k | struct ldb_parse_tree *ret; |
662 | 150k | const char *p = *s; |
663 | | |
664 | | /* |
665 | | * Check the depth of the parse tree, and reject the input if |
666 | | * max_depth exceeded. This avoids stack overflow |
667 | | * issues. |
668 | | */ |
669 | 150k | if (depth > max_depth) { |
670 | 1 | return NULL; |
671 | 1 | } |
672 | 150k | depth++; |
673 | | |
674 | 150k | if (*p != '(') { |
675 | 64 | return NULL; |
676 | 64 | } |
677 | 149k | p++; |
678 | | |
679 | 149k | ret = ldb_parse_filtercomp(mem_ctx, &p, depth, max_depth); |
680 | | |
681 | 149k | if (*p != ')') { |
682 | 3.59k | return NULL; |
683 | 3.59k | } |
684 | 146k | p++; |
685 | | |
686 | 146k | while (isspace((unsigned char)*p)) { |
687 | 194 | p++; |
688 | 194 | } |
689 | | |
690 | 146k | *s = p; |
691 | | |
692 | 146k | return ret; |
693 | 149k | } |
694 | | |
695 | | |
696 | | /* |
697 | | main parser entry point. Takes a search string and returns a parse tree |
698 | | |
699 | | expression ::= <simple> | <filter> |
700 | | */ |
701 | | struct ldb_parse_tree *ldb_parse_tree(TALLOC_CTX *mem_ctx, const char *s) |
702 | 943 | { |
703 | 943 | unsigned depth = 0; |
704 | | |
705 | 1.31k | while (s && isspace((unsigned char)*s)) s++; |
706 | | |
707 | 943 | if (s == NULL || *s == 0) { |
708 | 12 | s = "(|(objectClass=*)(distinguishedName=*))"; |
709 | 12 | } |
710 | | |
711 | 943 | if (*s == '(') { |
712 | 402 | return ldb_parse_filter( |
713 | 402 | mem_ctx, &s, depth, LDB_MAX_PARSE_TREE_DEPTH); |
714 | 402 | } |
715 | | |
716 | 541 | return ldb_parse_simple(mem_ctx, &s); |
717 | 943 | } |
718 | | |
719 | | |
720 | | /* |
721 | | construct a ldap parse filter given a parse tree |
722 | | */ |
723 | | char *ldb_filter_from_tree(TALLOC_CTX *mem_ctx, const struct ldb_parse_tree *tree) |
724 | 144k | { |
725 | 144k | char *s, *s2, *ret; |
726 | 144k | unsigned int i; |
727 | | |
728 | 144k | if (tree == NULL) { |
729 | 438 | return NULL; |
730 | 438 | } |
731 | | |
732 | 143k | switch (tree->operation) { |
733 | 294 | case LDB_OP_AND: |
734 | 501 | case LDB_OP_OR: |
735 | 501 | ret = talloc_asprintf(mem_ctx, "(%c", tree->operation==LDB_OP_AND?'&':'|'); |
736 | 501 | if (ret == NULL) return NULL; |
737 | 143k | for (i=0;i<tree->u.list.num_elements;i++) { |
738 | 142k | s = ldb_filter_from_tree(mem_ctx, tree->u.list.elements[i]); |
739 | 142k | if (s == NULL) { |
740 | 0 | talloc_free(ret); |
741 | 0 | return NULL; |
742 | 0 | } |
743 | 142k | s2 = talloc_asprintf_append(ret, "%s", s); |
744 | 142k | talloc_free(s); |
745 | 142k | if (s2 == NULL) { |
746 | 0 | talloc_free(ret); |
747 | 0 | return NULL; |
748 | 0 | } |
749 | 142k | ret = s2; |
750 | 142k | } |
751 | 501 | s = talloc_asprintf_append(ret, ")"); |
752 | 501 | if (s == NULL) { |
753 | 0 | talloc_free(ret); |
754 | 0 | return NULL; |
755 | 0 | } |
756 | 501 | return s; |
757 | 380 | case LDB_OP_NOT: |
758 | 380 | s = ldb_filter_from_tree(mem_ctx, tree->u.isnot.child); |
759 | 380 | if (s == NULL) return NULL; |
760 | | |
761 | 380 | ret = talloc_asprintf(mem_ctx, "(!%s)", s); |
762 | 380 | talloc_free(s); |
763 | 380 | return ret; |
764 | 140k | case LDB_OP_EQUALITY: |
765 | 140k | s = ldb_binary_encode(mem_ctx, tree->u.equality.value); |
766 | 140k | if (s == NULL) return NULL; |
767 | 140k | ret = talloc_asprintf(mem_ctx, "(%s=%s)", |
768 | 140k | tree->u.equality.attr, s); |
769 | 140k | talloc_free(s); |
770 | 140k | return ret; |
771 | 737 | case LDB_OP_SUBSTRING: |
772 | 737 | ret = talloc_asprintf(mem_ctx, "(%s=%s", tree->u.substring.attr, |
773 | 737 | tree->u.substring.start_with_wildcard?"*":""); |
774 | 737 | if (ret == NULL) return NULL; |
775 | 73.3k | for (i = 0; tree->u.substring.chunks && tree->u.substring.chunks[i]; i++) { |
776 | 72.6k | s2 = ldb_binary_encode(mem_ctx, *(tree->u.substring.chunks[i])); |
777 | 72.6k | if (s2 == NULL) { |
778 | 0 | talloc_free(ret); |
779 | 0 | return NULL; |
780 | 0 | } |
781 | 72.6k | if (tree->u.substring.chunks[i+1] || |
782 | 72.1k | tree->u.substring.end_with_wildcard) { |
783 | 72.1k | s = talloc_asprintf_append(ret, "%s*", s2); |
784 | 72.1k | } else { |
785 | 508 | s = talloc_asprintf_append(ret, "%s", s2); |
786 | 508 | } |
787 | 72.6k | if (s == NULL) { |
788 | 0 | talloc_free(ret); |
789 | 0 | return NULL; |
790 | 0 | } |
791 | 72.6k | ret = s; |
792 | 72.6k | } |
793 | 737 | s = talloc_asprintf_append(ret, ")"); |
794 | 737 | if (s == NULL) { |
795 | 0 | talloc_free(ret); |
796 | 0 | return NULL; |
797 | 0 | } |
798 | 737 | ret = s; |
799 | 737 | return ret; |
800 | 225 | case LDB_OP_GREATER: |
801 | 225 | s = ldb_binary_encode(mem_ctx, tree->u.comparison.value); |
802 | 225 | if (s == NULL) return NULL; |
803 | 225 | ret = talloc_asprintf(mem_ctx, "(%s>=%s)", |
804 | 225 | tree->u.comparison.attr, s); |
805 | 225 | talloc_free(s); |
806 | 225 | return ret; |
807 | 195 | case LDB_OP_LESS: |
808 | 195 | s = ldb_binary_encode(mem_ctx, tree->u.comparison.value); |
809 | 195 | if (s == NULL) return NULL; |
810 | 195 | ret = talloc_asprintf(mem_ctx, "(%s<=%s)", |
811 | 195 | tree->u.comparison.attr, s); |
812 | 195 | talloc_free(s); |
813 | 195 | return ret; |
814 | 372 | case LDB_OP_PRESENT: |
815 | 372 | ret = talloc_asprintf(mem_ctx, "(%s=*)", tree->u.present.attr); |
816 | 372 | return ret; |
817 | 196 | case LDB_OP_APPROX: |
818 | 196 | s = ldb_binary_encode(mem_ctx, tree->u.comparison.value); |
819 | 196 | if (s == NULL) return NULL; |
820 | 196 | ret = talloc_asprintf(mem_ctx, "(%s~=%s)", |
821 | 196 | tree->u.comparison.attr, s); |
822 | 196 | talloc_free(s); |
823 | 196 | return ret; |
824 | 408 | case LDB_OP_EXTENDED: |
825 | 408 | s = ldb_binary_encode(mem_ctx, tree->u.extended.value); |
826 | 408 | if (s == NULL) return NULL; |
827 | 408 | ret = talloc_asprintf(mem_ctx, "(%s%s%s%s:=%s)", |
828 | 408 | tree->u.extended.attr?tree->u.extended.attr:"", |
829 | 408 | tree->u.extended.dnAttributes?":dn":"", |
830 | 408 | tree->u.extended.rule_id?":":"", |
831 | 408 | tree->u.extended.rule_id?tree->u.extended.rule_id:"", |
832 | 408 | s); |
833 | 408 | talloc_free(s); |
834 | 408 | return ret; |
835 | 143k | } |
836 | | |
837 | 0 | return NULL; |
838 | 143k | } |
839 | | |
840 | | |
841 | | /* |
842 | | walk a parse tree, calling the provided callback on each node |
843 | | */ |
844 | | int ldb_parse_tree_walk(struct ldb_parse_tree *tree, |
845 | | int (*callback)(struct ldb_parse_tree *tree, void *), |
846 | | void *private_context) |
847 | 0 | { |
848 | 0 | unsigned int i; |
849 | 0 | int ret; |
850 | |
|
851 | 0 | ret = callback(tree, private_context); |
852 | 0 | if (ret != LDB_SUCCESS) { |
853 | 0 | return ret; |
854 | 0 | } |
855 | | |
856 | 0 | switch (tree->operation) { |
857 | 0 | case LDB_OP_AND: |
858 | 0 | case LDB_OP_OR: |
859 | 0 | for (i=0;i<tree->u.list.num_elements;i++) { |
860 | 0 | ret = ldb_parse_tree_walk(tree->u.list.elements[i], callback, private_context); |
861 | 0 | if (ret != LDB_SUCCESS) { |
862 | 0 | return ret; |
863 | 0 | } |
864 | 0 | } |
865 | 0 | break; |
866 | 0 | case LDB_OP_NOT: |
867 | 0 | ret = ldb_parse_tree_walk(tree->u.isnot.child, callback, private_context); |
868 | 0 | if (ret != LDB_SUCCESS) { |
869 | 0 | return ret; |
870 | 0 | } |
871 | 0 | break; |
872 | 0 | case LDB_OP_EQUALITY: |
873 | 0 | case LDB_OP_GREATER: |
874 | 0 | case LDB_OP_LESS: |
875 | 0 | case LDB_OP_APPROX: |
876 | 0 | case LDB_OP_SUBSTRING: |
877 | 0 | case LDB_OP_PRESENT: |
878 | 0 | case LDB_OP_EXTENDED: |
879 | 0 | break; |
880 | 0 | } |
881 | 0 | return LDB_SUCCESS; |
882 | 0 | } |
883 | | |
884 | | struct parse_tree_attr_replace_ctx { |
885 | | const char *attr; |
886 | | const char *replace; |
887 | | }; |
888 | | |
889 | | /* |
890 | | callback for ldb_parse_tree_attr_replace() |
891 | | */ |
892 | | static int parse_tree_attr_replace(struct ldb_parse_tree *tree, void *private_context) |
893 | 0 | { |
894 | 0 | struct parse_tree_attr_replace_ctx *ctx = private_context; |
895 | 0 | switch (tree->operation) { |
896 | 0 | case LDB_OP_EQUALITY: |
897 | 0 | if (ldb_attr_cmp(tree->u.equality.attr, ctx->attr) == 0) { |
898 | 0 | tree->u.equality.attr = ctx->replace; |
899 | 0 | } |
900 | 0 | break; |
901 | 0 | case LDB_OP_GREATER: |
902 | 0 | case LDB_OP_LESS: |
903 | 0 | case LDB_OP_APPROX: |
904 | 0 | if (ldb_attr_cmp(tree->u.comparison.attr, ctx->attr) == 0) { |
905 | 0 | tree->u.comparison.attr = ctx->replace; |
906 | 0 | } |
907 | 0 | break; |
908 | 0 | case LDB_OP_SUBSTRING: |
909 | 0 | if (ldb_attr_cmp(tree->u.substring.attr, ctx->attr) == 0) { |
910 | 0 | tree->u.substring.attr = ctx->replace; |
911 | 0 | } |
912 | 0 | break; |
913 | 0 | case LDB_OP_PRESENT: |
914 | 0 | if (ldb_attr_cmp(tree->u.present.attr, ctx->attr) == 0) { |
915 | 0 | tree->u.present.attr = ctx->replace; |
916 | 0 | } |
917 | 0 | break; |
918 | 0 | case LDB_OP_EXTENDED: |
919 | 0 | if (tree->u.extended.attr && |
920 | 0 | ldb_attr_cmp(tree->u.extended.attr, ctx->attr) == 0) { |
921 | 0 | tree->u.extended.attr = ctx->replace; |
922 | 0 | } |
923 | 0 | break; |
924 | 0 | default: |
925 | 0 | break; |
926 | 0 | } |
927 | 0 | return LDB_SUCCESS; |
928 | 0 | } |
929 | | |
930 | | /* |
931 | | replace any occurrences of an attribute name in the parse tree with a |
932 | | new name |
933 | | */ |
934 | | void ldb_parse_tree_attr_replace(struct ldb_parse_tree *tree, |
935 | | const char *attr, |
936 | | const char *replace) |
937 | 0 | { |
938 | 0 | struct parse_tree_attr_replace_ctx ctx; |
939 | |
|
940 | 0 | ctx.attr = attr; |
941 | 0 | ctx.replace = replace; |
942 | |
|
943 | 0 | ldb_parse_tree_walk(tree, parse_tree_attr_replace, &ctx); |
944 | 0 | } |
945 | | |
946 | | /* |
947 | | shallow copy a tree - copying only the elements array so that the caller |
948 | | can safely add new elements without changing the message |
949 | | */ |
950 | | struct ldb_parse_tree *ldb_parse_tree_copy_shallow(TALLOC_CTX *mem_ctx, |
951 | | const struct ldb_parse_tree *ot) |
952 | 0 | { |
953 | 0 | unsigned int i; |
954 | 0 | struct ldb_parse_tree *nt; |
955 | |
|
956 | 0 | nt = talloc(mem_ctx, struct ldb_parse_tree); |
957 | 0 | if (!nt) { |
958 | 0 | return NULL; |
959 | 0 | } |
960 | | |
961 | 0 | *nt = *ot; |
962 | |
|
963 | 0 | switch (ot->operation) { |
964 | 0 | case LDB_OP_AND: |
965 | 0 | case LDB_OP_OR: |
966 | 0 | nt->u.list.elements = talloc_array(nt, struct ldb_parse_tree *, |
967 | 0 | ot->u.list.num_elements); |
968 | 0 | if (!nt->u.list.elements) { |
969 | 0 | talloc_free(nt); |
970 | 0 | return NULL; |
971 | 0 | } |
972 | | |
973 | 0 | for (i=0;i<ot->u.list.num_elements;i++) { |
974 | 0 | nt->u.list.elements[i] = |
975 | 0 | ldb_parse_tree_copy_shallow(nt->u.list.elements, |
976 | 0 | ot->u.list.elements[i]); |
977 | 0 | if (!nt->u.list.elements[i]) { |
978 | 0 | talloc_free(nt); |
979 | 0 | return NULL; |
980 | 0 | } |
981 | 0 | } |
982 | 0 | break; |
983 | 0 | case LDB_OP_NOT: |
984 | 0 | nt->u.isnot.child = ldb_parse_tree_copy_shallow(nt, |
985 | 0 | ot->u.isnot.child); |
986 | 0 | if (!nt->u.isnot.child) { |
987 | 0 | talloc_free(nt); |
988 | 0 | return NULL; |
989 | 0 | } |
990 | 0 | break; |
991 | 0 | case LDB_OP_EQUALITY: |
992 | 0 | case LDB_OP_GREATER: |
993 | 0 | case LDB_OP_LESS: |
994 | 0 | case LDB_OP_APPROX: |
995 | 0 | case LDB_OP_SUBSTRING: |
996 | 0 | case LDB_OP_PRESENT: |
997 | 0 | case LDB_OP_EXTENDED: |
998 | 0 | break; |
999 | 0 | } |
1000 | | |
1001 | 0 | return nt; |
1002 | 0 | } |
1003 | | |
1004 | | /* Get the attribute (if any) associated with the top node of a parse tree. */ |
1005 | | const char *ldb_parse_tree_get_attr(const struct ldb_parse_tree *tree) |
1006 | 0 | { |
1007 | 0 | switch (tree->operation) { |
1008 | 0 | case LDB_OP_AND: |
1009 | 0 | case LDB_OP_OR: |
1010 | 0 | case LDB_OP_NOT: |
1011 | 0 | return NULL; |
1012 | 0 | case LDB_OP_EQUALITY: |
1013 | 0 | return tree->u.equality.attr; |
1014 | 0 | case LDB_OP_SUBSTRING: |
1015 | 0 | return tree->u.substring.attr; |
1016 | 0 | case LDB_OP_GREATER: |
1017 | 0 | case LDB_OP_LESS: |
1018 | 0 | case LDB_OP_APPROX: |
1019 | 0 | return tree->u.comparison.attr; |
1020 | 0 | case LDB_OP_PRESENT: |
1021 | 0 | return tree->u.present.attr; |
1022 | 0 | case LDB_OP_EXTENDED: |
1023 | 0 | return tree->u.extended.attr; |
1024 | 0 | } |
1025 | | |
1026 | 0 | return NULL; |
1027 | 0 | } |