Line data Source code
1 : /*
2 : ldb database library
3 :
4 : Copyright (C) Andrew Tridgell 2005
5 : Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006-2009
6 :
7 : ** NOTE! The following LGPL license applies to the ldb
8 : ** library. This does NOT imply that all of Samba is released
9 : ** under the LGPL
10 :
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 3 of the License, or (at your option) any later version.
15 :
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.
20 :
21 : You should have received a copy of the GNU Lesser General Public
22 : License along with this library; if not, see <http://www.gnu.org/licenses/>.
23 : */
24 : /*
25 : attribute handlers for well known attribute types, selected by syntax OID
26 : see rfc2252
27 : */
28 :
29 : #include "ldb_private.h"
30 : #include "system/locale.h"
31 : #include "ldb_handlers.h"
32 :
33 : /*
34 : default handler that just copies a ldb_val.
35 : */
36 67218512 : int ldb_handler_copy(struct ldb_context *ldb, void *mem_ctx,
37 : const struct ldb_val *in, struct ldb_val *out)
38 : {
39 67218512 : *out = ldb_val_dup(mem_ctx, in);
40 67218512 : if (in->length > 0 && out->data == NULL) {
41 0 : ldb_oom(ldb);
42 0 : return -1;
43 : }
44 67218512 : return 0;
45 : }
46 :
47 : /*
48 : a case folding copy handler, removing leading and trailing spaces and
49 : multiple internal spaces
50 :
51 : We exploit the fact that utf8 never uses the space octet except for
52 : the space itself
53 : */
54 543295414 : int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx,
55 : const struct ldb_val *in, struct ldb_val *out)
56 : {
57 : char *s, *t, *start;
58 : bool in_space;
59 :
60 543295414 : if (!in || !out || !(in->data)) {
61 0 : return -1;
62 : }
63 :
64 543295414 : out->data = (uint8_t *)ldb_casefold(ldb, mem_ctx, (const char *)(in->data), in->length);
65 543295414 : if (out->data == NULL) {
66 0 : ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_handler_fold: unable to casefold string [%.*s]", (int)in->length, (const char *)in->data);
67 0 : return -1;
68 : }
69 :
70 543295414 : start = (char *)(out->data);
71 543295414 : in_space = true;
72 543295414 : t = start;
73 7941347796 : for (s = start; *s != '\0'; s++) {
74 7398052382 : if (*s == ' ') {
75 72264692 : if (in_space) {
76 : /*
77 : * We already have one (or this is the start)
78 : * and we don't want to add more
79 : */
80 2229 : continue;
81 : }
82 72262463 : in_space = true;
83 : } else {
84 7325787690 : in_space = false;
85 : }
86 7398050153 : *t = *s;
87 7398050153 : t++;
88 : }
89 :
90 543295414 : if (in_space && t != start) {
91 : /* the loop will have left a single trailing space */
92 13 : t--;
93 : }
94 543295414 : *t = '\0';
95 :
96 543295414 : out->length = t - start;
97 543295414 : return 0;
98 : }
99 :
100 : /* length limited conversion of a ldb_val to an int64_t */
101 22935974 : static int val_to_int64(const struct ldb_val *in, int64_t *v)
102 : {
103 : char *end;
104 : char buf[64];
105 :
106 : /* make sure we don't read past the end of the data */
107 22935974 : if (in->length > sizeof(buf)-1) {
108 0 : return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
109 : }
110 22935974 : strncpy(buf, (char *)in->data, in->length);
111 22935974 : buf[in->length] = 0;
112 :
113 22935974 : *v = (int64_t) strtoll(buf, &end, 0);
114 22935974 : if (*end != 0) {
115 13 : return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
116 : }
117 22935961 : return LDB_SUCCESS;
118 : }
119 :
120 :
121 : /*
122 : canonicalise a ldap Integer
123 : rfc2252 specifies it should be in decimal form
124 : */
125 178404 : static int ldb_canonicalise_Integer(struct ldb_context *ldb, void *mem_ctx,
126 : const struct ldb_val *in, struct ldb_val *out)
127 : {
128 : int64_t i;
129 : int ret;
130 :
131 178404 : ret = val_to_int64(in, &i);
132 178404 : if (ret != LDB_SUCCESS) {
133 1 : return ret;
134 : }
135 178403 : out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%lld", (long long)i);
136 178403 : if (out->data == NULL) {
137 0 : ldb_oom(ldb);
138 0 : return LDB_ERR_OPERATIONS_ERROR;
139 : }
140 178403 : out->length = strlen((char *)out->data);
141 178403 : return 0;
142 : }
143 :
144 : /*
145 : * Lexicographically ordered format for a ldap Integer
146 : *
147 : * [ INT64_MIN ... -3, -2, -1 | 0 | +1, +2, +3 ... INT64_MAX ]
148 : * n o p
149 : *
150 : * For human readability sake, we continue to format the key as a string
151 : * (like the canonicalize) rather than store as a fixed binary representation.
152 : *
153 : * In order to sort the integers in the correct string order, there are three
154 : * techniques we use:
155 : *
156 : * 1. Zero padding
157 : * 2. Negative integer inversion
158 : * 3. 1-byte prefixes: 'n' < 'o' < 'p'
159 : *
160 : * 1. To have a fixed-width representation so that 10 sorts after 2 rather than
161 : * after 1, we zero pad, like this 4-byte width example:
162 : *
163 : * 0001, 0002, 0010
164 : *
165 : * INT64_MAX = 2^63 - 1 = 9223372036854775807 (19 characters long)
166 : *
167 : * Meaning we need to pad to 19 characters.
168 : *
169 : * 2. This works for positive integers, but negative integers will still be
170 : * sorted backwards, for example:
171 : *
172 : * -9223372036854775808 ..., -0000000000000000002, -0000000000000000001
173 : * INT64_MIN -2 -1
174 : *
175 : * gets sorted based on string as:
176 : *
177 : * -0000000000000000001, -0000000000000000002, ... -9223372036854775808
178 : *
179 : * In order to fix this, we invert the negative integer range, so that they
180 : * get sorted the same way as positive numbers. INT64_MIN becomes the lowest
181 : * possible non-negative number (zero), and -1 becomes the highest (INT64_MAX).
182 : *
183 : * The actual conversion applied to negative number 'x' is:
184 : * INT64_MAX - abs(x) + 1
185 : * (The +1 is needed because abs(INT64_MIN) is one greater than INT64_MAX)
186 : *
187 : * 3. Finally, we now have two different numbers that map to the same key, e.g.
188 : * INT64_MIN maps to -0000000000000000000 and zero maps to 0000000000000000000.
189 : * In order to avoid confusion, we give every number a prefix representing its
190 : * sign: 'n' for negative numbers, 'o' for zero, and 'p' for positive. (Note
191 : * that '+' and '-' weren't used because they sort the wrong way).
192 : *
193 : * The result is a range of key values that look like this:
194 : *
195 : * n0000000000000000000, ... n9223372036854775807,
196 : * INT64_MIN -1
197 : *
198 : * o0000000000000000000,
199 : * ZERO
200 : *
201 : * p0000000000000000001, ... p9223372036854775807
202 : * +1 INT64_MAX
203 : */
204 4240628 : static int ldb_index_format_Integer(struct ldb_context *ldb,
205 : void *mem_ctx,
206 : const struct ldb_val *in,
207 : struct ldb_val *out)
208 : {
209 : int64_t i;
210 : int ret;
211 : char prefix;
212 : size_t len;
213 :
214 4240628 : ret = val_to_int64(in, &i);
215 4240628 : if (ret != LDB_SUCCESS) {
216 0 : return ret;
217 : }
218 :
219 4240628 : if (i < 0) {
220 : /*
221 : * i is negative, so this is subtraction rather than
222 : * wrap-around.
223 : */
224 46 : prefix = 'n';
225 46 : i = INT64_MAX + i + 1;
226 4240582 : } else if (i > 0) {
227 4240576 : prefix = 'p';
228 : } else {
229 6 : prefix = 'o';
230 : }
231 :
232 4240628 : out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%c%019lld", prefix, (long long)i);
233 4240628 : if (out->data == NULL) {
234 0 : ldb_oom(ldb);
235 0 : return LDB_ERR_OPERATIONS_ERROR;
236 : }
237 :
238 4240628 : len = talloc_array_length(out->data) - 1;
239 4240628 : if (len != 20) {
240 0 : ldb_debug(ldb, LDB_DEBUG_ERROR,
241 : __location__ ": expected index format str %s to"
242 : " have length 20 but got %zu",
243 0 : (char*)out->data, len);
244 0 : return LDB_ERR_OPERATIONS_ERROR;
245 : }
246 :
247 4240628 : out->length = 20;
248 4240628 : return 0;
249 : }
250 :
251 : /*
252 : compare two Integers
253 : */
254 9258471 : static int ldb_comparison_Integer(struct ldb_context *ldb, void *mem_ctx,
255 : const struct ldb_val *v1, const struct ldb_val *v2)
256 : {
257 9258471 : int64_t i1=0, i2=0;
258 9258471 : val_to_int64(v1, &i1);
259 9258471 : val_to_int64(v2, &i2);
260 9258471 : if (i1 == i2) return 0;
261 9111047 : return i1 > i2? 1 : -1;
262 : }
263 :
264 : /*
265 : canonicalise a ldap Boolean
266 : rfc2252 specifies it should be either "TRUE" or "FALSE"
267 : */
268 2000645 : static int ldb_canonicalise_Boolean(struct ldb_context *ldb, void *mem_ctx,
269 : const struct ldb_val *in, struct ldb_val *out)
270 : {
271 2000645 : if (in->length >= 4 && strncasecmp((char *)in->data, "TRUE", in->length) == 0) {
272 1828531 : out->data = (uint8_t *)talloc_strdup(mem_ctx, "TRUE");
273 1828531 : out->length = 4;
274 172114 : } else if (in->length >= 5 && strncasecmp((char *)in->data, "FALSE", in->length) == 0) {
275 172114 : out->data = (uint8_t *)talloc_strdup(mem_ctx, "FALSE");
276 172114 : out->length = 5;
277 : } else {
278 0 : return -1;
279 : }
280 2000645 : return 0;
281 : }
282 :
283 : /*
284 : compare two Booleans
285 : */
286 4524106 : static int ldb_comparison_Boolean(struct ldb_context *ldb, void *mem_ctx,
287 : const struct ldb_val *v1, const struct ldb_val *v2)
288 : {
289 4524106 : if (v1->length != v2->length) {
290 47 : return v1->length - v2->length;
291 : }
292 4524059 : return strncasecmp((char *)v1->data, (char *)v2->data, v1->length);
293 : }
294 :
295 :
296 : /*
297 : compare two binary blobs
298 : */
299 18766277 : int ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx,
300 : const struct ldb_val *v1, const struct ldb_val *v2)
301 : {
302 18766277 : if (v1->length != v2->length) {
303 25417 : return v1->length - v2->length;
304 : }
305 18740860 : return memcmp(v1->data, v2->data, v1->length);
306 : }
307 :
308 : /*
309 : compare two case insensitive strings, ignoring multiple whitespaces
310 : and leading and trailing whitespaces
311 : see rfc2252 section 8.1
312 :
313 : try to optimize for the ascii case,
314 : but if we find out an utf8 codepoint revert to slower but correct function
315 : */
316 158140966 : int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx,
317 : const struct ldb_val *v1, const struct ldb_val *v2)
318 : {
319 158140966 : const char *s1=(const char *)v1->data, *s2=(const char *)v2->data;
320 158140966 : size_t n1 = v1->length, n2 = v2->length;
321 : char *b1, *b2;
322 : const char *u1, *u2;
323 : int ret;
324 158140966 : while (n1 && *s1 == ' ') { s1++; n1--; };
325 158140966 : while (n2 && *s2 == ' ') { s2++; n2--; };
326 :
327 1255451648 : while (n1 && n2 && *s1 && *s2) {
328 : /* the first 127 (0x7F) chars are ascii and utf8 guarantes they
329 : * never appear in multibyte sequences */
330 1073133627 : if (((unsigned char)s1[0]) & 0x80) goto utf8str;
331 1073082328 : if (((unsigned char)s2[0]) & 0x80) goto utf8str;
332 1073080870 : if (toupper((unsigned char)*s1) != toupper((unsigned char)*s2))
333 92628652 : break;
334 980452218 : if (*s1 == ' ') {
335 6797 : while (n1 > 1 && s1[0] == s1[1]) { s1++; n1--; }
336 6797 : while (n2 > 1 && s2[0] == s2[1]) { s2++; n2--; }
337 : }
338 980452218 : s1++; s2++;
339 980452218 : n1--; n2--;
340 : }
341 :
342 : /* check for trailing spaces only if the other pointers has
343 : * reached the end of the strings otherwise we can
344 : * mistakenly match. ex. "domain users" <->
345 : * "domainUpdates"
346 : */
347 158088209 : if (n1 && *s1 == ' ' && (!n2 || !*s2)) {
348 245 : while (n1 && *s1 == ' ') { s1++; n1--; }
349 : }
350 158088209 : if (n2 && *s2 == ' ' && (!n1 || !*s1)) {
351 9 : while (n2 && *s2 == ' ') { s2++; n2--; }
352 : }
353 158088209 : if (n1 == 0 && n2 != 0) {
354 41765 : return -(int)toupper(*s2);
355 : }
356 158046444 : if (n2 == 0 && n1 != 0) {
357 20879 : return (int)toupper(*s1);
358 : }
359 158025565 : if (n1 == 0 && n2 == 0) {
360 65396911 : return 0;
361 : }
362 92628654 : return (int)toupper(*s1) - (int)toupper(*s2);
363 :
364 52757 : utf8str:
365 : /* no need to recheck from the start, just from the first utf8 char found */
366 52757 : b1 = ldb_casefold(ldb, mem_ctx, s1, n1);
367 52757 : b2 = ldb_casefold(ldb, mem_ctx, s2, n2);
368 :
369 52757 : if (!b1 || !b2) {
370 : /* One of the strings was not UTF8, so we have no
371 : * options but to do a binary compare */
372 0 : talloc_free(b1);
373 0 : talloc_free(b2);
374 0 : ret = memcmp(s1, s2, MIN(n1, n2));
375 0 : if (ret == 0) {
376 0 : if (n1 == n2) return 0;
377 0 : if (n1 > n2) {
378 0 : return (int)toupper(s1[n2]);
379 : } else {
380 0 : return -(int)toupper(s2[n1]);
381 : }
382 : }
383 0 : return ret;
384 : }
385 :
386 52757 : u1 = b1;
387 52757 : u2 = b2;
388 :
389 534913 : while (*u1 & *u2) {
390 433786 : if (*u1 != *u2)
391 4387 : break;
392 429399 : if (*u1 == ' ') {
393 1 : while (u1[0] == u1[1]) u1++;
394 1 : while (u2[0] == u2[1]) u2++;
395 : }
396 429399 : u1++; u2++;
397 : }
398 52757 : if (! (*u1 && *u2)) {
399 47688 : while (*u1 == ' ') u1++;
400 47688 : while (*u2 == ' ') u2++;
401 : }
402 52757 : ret = (int)(*u1 - *u2);
403 :
404 52757 : talloc_free(b1);
405 52757 : talloc_free(b2);
406 :
407 52757 : return ret;
408 : }
409 :
410 :
411 : /*
412 : canonicalise a attribute in DN format
413 : */
414 0 : static int ldb_canonicalise_dn(struct ldb_context *ldb, void *mem_ctx,
415 : const struct ldb_val *in, struct ldb_val *out)
416 : {
417 : struct ldb_dn *dn;
418 0 : int ret = -1;
419 :
420 0 : out->length = 0;
421 0 : out->data = NULL;
422 :
423 0 : dn = ldb_dn_from_ldb_val(mem_ctx, ldb, in);
424 0 : if ( ! ldb_dn_validate(dn)) {
425 0 : return LDB_ERR_INVALID_DN_SYNTAX;
426 : }
427 :
428 0 : out->data = (uint8_t *)ldb_dn_alloc_casefold(mem_ctx, dn);
429 0 : if (out->data == NULL) {
430 0 : goto done;
431 : }
432 0 : out->length = strlen((char *)out->data);
433 :
434 0 : ret = 0;
435 :
436 0 : done:
437 0 : talloc_free(dn);
438 :
439 0 : return ret;
440 : }
441 :
442 : /*
443 : compare two dns
444 : */
445 0 : static int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx,
446 : const struct ldb_val *v1, const struct ldb_val *v2)
447 : {
448 0 : struct ldb_dn *dn1 = NULL, *dn2 = NULL;
449 : int ret;
450 :
451 0 : dn1 = ldb_dn_from_ldb_val(mem_ctx, ldb, v1);
452 0 : if ( ! ldb_dn_validate(dn1)) return -1;
453 :
454 0 : dn2 = ldb_dn_from_ldb_val(mem_ctx, ldb, v2);
455 0 : if ( ! ldb_dn_validate(dn2)) {
456 0 : talloc_free(dn1);
457 0 : return -1;
458 : }
459 :
460 0 : ret = ldb_dn_compare(dn1, dn2);
461 :
462 0 : talloc_free(dn1);
463 0 : talloc_free(dn2);
464 0 : return ret;
465 : }
466 :
467 : /*
468 : compare two utc time values. 1 second resolution
469 : */
470 571422 : static int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx,
471 : const struct ldb_val *v1, const struct ldb_val *v2)
472 : {
473 571422 : time_t t1=0, t2=0;
474 571422 : ldb_val_to_time(v1, &t1);
475 571422 : ldb_val_to_time(v2, &t2);
476 571422 : if (t1 == t2) return 0;
477 278577 : return t1 > t2? 1 : -1;
478 : }
479 :
480 : /*
481 : canonicalise a utc time
482 : */
483 0 : static int ldb_canonicalise_utctime(struct ldb_context *ldb, void *mem_ctx,
484 : const struct ldb_val *in, struct ldb_val *out)
485 : {
486 : time_t t;
487 : int ret;
488 0 : ret = ldb_val_to_time(in, &t);
489 0 : if (ret != LDB_SUCCESS) {
490 0 : return ret;
491 : }
492 0 : out->data = (uint8_t *)ldb_timestring_utc(mem_ctx, t);
493 0 : if (out->data == NULL) {
494 0 : ldb_oom(ldb);
495 0 : return LDB_ERR_OPERATIONS_ERROR;
496 : }
497 0 : out->length = strlen((char *)out->data);
498 0 : return 0;
499 : }
500 :
501 : /*
502 : canonicalise a generalized time
503 : */
504 10713 : static int ldb_canonicalise_generalizedtime(struct ldb_context *ldb, void *mem_ctx,
505 : const struct ldb_val *in, struct ldb_val *out)
506 : {
507 : time_t t;
508 : int ret;
509 10713 : ret = ldb_val_to_time(in, &t);
510 10713 : if (ret != LDB_SUCCESS) {
511 0 : return ret;
512 : }
513 10713 : out->data = (uint8_t *)ldb_timestring(mem_ctx, t);
514 10713 : if (out->data == NULL) {
515 0 : ldb_oom(ldb);
516 0 : return LDB_ERR_OPERATIONS_ERROR;
517 : }
518 10713 : out->length = strlen((char *)out->data);
519 10713 : return 0;
520 : }
521 :
522 : /*
523 : table of standard attribute handlers
524 : */
525 : static const struct ldb_schema_syntax ldb_standard_syntaxes[] = {
526 : {
527 : .name = LDB_SYNTAX_INTEGER,
528 : .ldif_read_fn = ldb_handler_copy,
529 : .ldif_write_fn = ldb_handler_copy,
530 : .canonicalise_fn = ldb_canonicalise_Integer,
531 : .comparison_fn = ldb_comparison_Integer
532 : },
533 : {
534 : .name = LDB_SYNTAX_ORDERED_INTEGER,
535 : .ldif_read_fn = ldb_handler_copy,
536 : .ldif_write_fn = ldb_handler_copy,
537 : .canonicalise_fn = ldb_canonicalise_Integer,
538 : .index_format_fn = ldb_index_format_Integer,
539 : .comparison_fn = ldb_comparison_Integer
540 : },
541 : {
542 : .name = LDB_SYNTAX_OCTET_STRING,
543 : .ldif_read_fn = ldb_handler_copy,
544 : .ldif_write_fn = ldb_handler_copy,
545 : .canonicalise_fn = ldb_handler_copy,
546 : .comparison_fn = ldb_comparison_binary
547 : },
548 : {
549 : .name = LDB_SYNTAX_DIRECTORY_STRING,
550 : .ldif_read_fn = ldb_handler_copy,
551 : .ldif_write_fn = ldb_handler_copy,
552 : .canonicalise_fn = ldb_handler_fold,
553 : .comparison_fn = ldb_comparison_fold
554 : },
555 : {
556 : .name = LDB_SYNTAX_DN,
557 : .ldif_read_fn = ldb_handler_copy,
558 : .ldif_write_fn = ldb_handler_copy,
559 : .canonicalise_fn = ldb_canonicalise_dn,
560 : .comparison_fn = ldb_comparison_dn
561 : },
562 : {
563 : .name = LDB_SYNTAX_OBJECTCLASS,
564 : .ldif_read_fn = ldb_handler_copy,
565 : .ldif_write_fn = ldb_handler_copy,
566 : .canonicalise_fn = ldb_handler_fold,
567 : .comparison_fn = ldb_comparison_fold
568 : },
569 : {
570 : .name = LDB_SYNTAX_UTC_TIME,
571 : .ldif_read_fn = ldb_handler_copy,
572 : .ldif_write_fn = ldb_handler_copy,
573 : .canonicalise_fn = ldb_canonicalise_utctime,
574 : .comparison_fn = ldb_comparison_utctime
575 : },
576 : {
577 : .name = LDB_SYNTAX_GENERALIZED_TIME,
578 : .ldif_read_fn = ldb_handler_copy,
579 : .ldif_write_fn = ldb_handler_copy,
580 : .canonicalise_fn = ldb_canonicalise_generalizedtime,
581 : .comparison_fn = ldb_comparison_utctime
582 : },
583 : {
584 : .name = LDB_SYNTAX_BOOLEAN,
585 : .ldif_read_fn = ldb_handler_copy,
586 : .ldif_write_fn = ldb_handler_copy,
587 : .canonicalise_fn = ldb_canonicalise_Boolean,
588 : .comparison_fn = ldb_comparison_Boolean
589 : },
590 : };
591 :
592 :
593 : /*
594 : return the attribute handlers for a given syntax name
595 : */
596 102775628 : const struct ldb_schema_syntax *ldb_standard_syntax_by_name(struct ldb_context *ldb,
597 : const char *syntax)
598 : {
599 : unsigned int i;
600 102775628 : unsigned num_handlers = sizeof(ldb_standard_syntaxes)/sizeof(ldb_standard_syntaxes[0]);
601 : /* TODO: should be replaced with a binary search */
602 403194218 : for (i=0;i<num_handlers;i++) {
603 403194218 : if (strcmp(ldb_standard_syntaxes[i].name, syntax) == 0) {
604 102775628 : return &ldb_standard_syntaxes[i];
605 : }
606 : }
607 0 : return NULL;
608 : }
609 :
610 69787 : int ldb_any_comparison(struct ldb_context *ldb, void *mem_ctx,
611 : ldb_attr_handler_t canonicalise_fn,
612 : const struct ldb_val *v1,
613 : const struct ldb_val *v2)
614 : {
615 : int ret, ret1, ret2;
616 : struct ldb_val v1_canon, v2_canon;
617 69787 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
618 :
619 : /* I could try and bail if tmp_ctx was NULL, but what return
620 : * value would I use?
621 : *
622 : * It seems easier to continue on the NULL context
623 : */
624 69787 : ret1 = canonicalise_fn(ldb, tmp_ctx, v1, &v1_canon);
625 69787 : ret2 = canonicalise_fn(ldb, tmp_ctx, v2, &v2_canon);
626 :
627 69787 : if (ret1 == LDB_SUCCESS && ret2 == LDB_SUCCESS) {
628 69765 : ret = ldb_comparison_binary(ldb, mem_ctx, &v1_canon, &v2_canon);
629 : } else {
630 22 : ret = ldb_comparison_binary(ldb, mem_ctx, v1, v2);
631 : }
632 69787 : talloc_free(tmp_ctx);
633 69787 : return ret;
634 : }
|