4 Copyright (C) Andrew Tridgell 2005
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006-2009
7 ** NOTE! The following LGPL license applies to the ldb
8 ** library. This does NOT imply that all of Samba is released
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.
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.
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/>.
25 attribute handlers for well known attribute types, selected by syntax OID
29 #include "ldb_private.h"
30 #include "system/locale.h"
31 #include "ldb_handlers.h"
34 default handler that just copies a ldb_val.
36 int ldb_handler_copy(struct ldb_context *ldb, void *mem_ctx,
37 const struct ldb_val *in, struct ldb_val *out)
39 *out = ldb_val_dup(mem_ctx, in);
40 if (in->length > 0 && out->data == NULL) {
48 a case folding copy handler, removing leading and trailing spaces and
49 multiple internal spaces
51 We exploit the fact that utf8 never uses the space octet except for
54 int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx,
55 const struct ldb_val *in, struct ldb_val *out)
60 if (!in || !out || !(in->data)) {
64 out->data = (uint8_t *)ldb_casefold(ldb, mem_ctx, (const char *)(in->data), in->length);
65 if (out->data == NULL) {
66 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_handler_fold: unable to casefold string [%.*s]", (int)in->length, (const char *)in->data);
70 start = (char *)(out->data);
73 for (s = start; *s != '\0'; s++) {
77 * We already have one (or this is the start)
78 * and we don't want to add more
90 if (in_space && t != start) {
91 /* the loop will have left a single trailing space */
96 out->length = t - start;
100 /* length limited conversion of a ldb_val to an int64_t */
101 static int val_to_int64(const struct ldb_val *in, int64_t *v)
106 /* make sure we don't read past the end of the data */
107 if (in->length > sizeof(buf)-1) {
108 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
110 strncpy(buf, (char *)in->data, in->length);
113 *v = (int64_t) strtoll(buf, &end, 0);
115 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
122 canonicalise a ldap Integer
123 rfc2252 specifies it should be in decimal form
125 static int ldb_canonicalise_Integer(struct ldb_context *ldb, void *mem_ctx,
126 const struct ldb_val *in, struct ldb_val *out)
131 ret = val_to_int64(in, &i);
132 if (ret != LDB_SUCCESS) {
135 out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%lld", (long long)i);
136 if (out->data == NULL) {
138 return LDB_ERR_OPERATIONS_ERROR;
140 out->length = strlen((char *)out->data);
145 * Lexicographically ordered format for a ldap Integer
147 * [ INT64_MIN ... -3, -2, -1 | 0 | +1, +2, +3 ... INT64_MAX ]
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.
153 * In order to sort the integers in the correct string order, there are three
157 * 2. Negative integer inversion
158 * 3. 1-byte prefixes: 'n' < 'o' < 'p'
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:
165 * INT64_MAX = 2^63 - 1 = 9223372036854775807 (19 characters long)
167 * Meaning we need to pad to 19 characters.
169 * 2. This works for positive integers, but negative integers will still be
170 * sorted backwards, for example:
172 * -9223372036854775808 ..., -0000000000000000002, -0000000000000000001
175 * gets sorted based on string as:
177 * -0000000000000000001, -0000000000000000002, ... -9223372036854775808
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).
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)
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).
193 * The result is a range of key values that look like this:
195 * n0000000000000000000, ... n9223372036854775807,
198 * o0000000000000000000,
201 * p0000000000000000001, ... p9223372036854775807
204 static int ldb_index_format_Integer(struct ldb_context *ldb,
206 const struct ldb_val *in,
214 ret = val_to_int64(in, &i);
215 if (ret != LDB_SUCCESS) {
221 * i is negative, so this is subtraction rather than
225 i = INT64_MAX + i + 1;
232 out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%c%019lld", prefix, (long long)i);
233 if (out->data == NULL) {
235 return LDB_ERR_OPERATIONS_ERROR;
238 len = talloc_array_length(out->data) - 1;
240 ldb_debug(ldb, LDB_DEBUG_ERROR,
241 __location__ ": expected index format str %s to"
242 " have length 20 but got %zu",
243 (char*)out->data, len);
244 return LDB_ERR_OPERATIONS_ERROR;
254 static int ldb_comparison_Integer(struct ldb_context *ldb, void *mem_ctx,
255 const struct ldb_val *v1, const struct ldb_val *v2)
258 val_to_int64(v1, &i1);
259 val_to_int64(v2, &i2);
260 if (i1 == i2) return 0;
261 return i1 > i2? 1 : -1;
265 canonicalise a ldap Boolean
266 rfc2252 specifies it should be either "TRUE" or "FALSE"
268 static int ldb_canonicalise_Boolean(struct ldb_context *ldb, void *mem_ctx,
269 const struct ldb_val *in, struct ldb_val *out)
271 if (in->length >= 4 && strncasecmp((char *)in->data, "TRUE", in->length) == 0) {
272 out->data = (uint8_t *)talloc_strdup(mem_ctx, "TRUE");
274 } else if (in->length >= 5 && strncasecmp((char *)in->data, "FALSE", in->length) == 0) {
275 out->data = (uint8_t *)talloc_strdup(mem_ctx, "FALSE");
286 static int ldb_comparison_Boolean(struct ldb_context *ldb, void *mem_ctx,
287 const struct ldb_val *v1, const struct ldb_val *v2)
289 if (v1->length != v2->length) {
290 return NUMERIC_CMP(v1->length, v2->length);
292 return strncasecmp((char *)v1->data, (char *)v2->data, v1->length);
297 compare two binary blobs
299 int ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx,
300 const struct ldb_val *v1, const struct ldb_val *v2)
302 if (v1->length != v2->length) {
303 return v1->length - v2->length;
305 return memcmp(v1->data, v2->data, v1->length);
309 compare two case insensitive strings, ignoring multiple whitespaces
310 and leading and trailing whitespaces
311 see rfc2252 section 8.1
313 try to optimize for the ascii case,
314 but if we find out an utf8 codepoint revert to slower but correct function
316 int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx,
317 const struct ldb_val *v1, const struct ldb_val *v2)
319 const char *s1=(const char *)v1->data, *s2=(const char *)v2->data;
320 size_t n1 = v1->length, n2 = v2->length;
325 while (n1 && *s1 == ' ') { s1++; n1--; };
326 while (n2 && *s2 == ' ') { s2++; n2--; };
328 while (n1 && n2 && *s1 && *s2) {
329 /* the first 127 (0x7F) chars are ascii and utf8 guarantees they
330 * never appear in multibyte sequences */
331 if (((unsigned char)s1[0]) & 0x80) goto utf8str;
332 if (((unsigned char)s2[0]) & 0x80) goto utf8str;
333 if (toupper((unsigned char)*s1) != toupper((unsigned char)*s2))
336 while (n1 > 1 && s1[0] == s1[1]) { s1++; n1--; }
337 while (n2 > 1 && s2[0] == s2[1]) { s2++; n2--; }
343 /* check for trailing spaces only if the other pointers has
344 * reached the end of the strings otherwise we can
345 * mistakenly match. ex. "domain users" <->
348 if (n1 && *s1 == ' ' && (!n2 || !*s2)) {
349 while (n1 && *s1 == ' ') { s1++; n1--; }
351 if (n2 && *s2 == ' ' && (!n1 || !*s1)) {
352 while (n2 && *s2 == ' ') { s2++; n2--; }
354 if (n1 == 0 && n2 != 0) {
355 return -(int)ldb_ascii_toupper(*s2);
357 if (n2 == 0 && n1 != 0) {
358 return (int)ldb_ascii_toupper(*s1);
360 if (n1 == 0 && n2 == 0) {
363 return (int)ldb_ascii_toupper(*s1) - (int)ldb_ascii_toupper(*s2);
367 * No need to recheck from the start, just from the first utf8 charu
368 * found. Note that the callback of ldb_casefold() needs to be ascii
371 b1 = ldb_casefold(ldb, mem_ctx, s1, n1);
372 b2 = ldb_casefold(ldb, mem_ctx, s2, n2);
375 /* One of the strings was not UTF8, so we have no
376 * options but to do a binary compare */
379 ret = memcmp(s1, s2, MIN(n1, n2));
381 if (n1 == n2) return 0;
383 return (int)ldb_ascii_toupper(s1[n2]);
385 return -(int)ldb_ascii_toupper(s2[n1]);
398 while (u1[0] == u1[1]) u1++;
399 while (u2[0] == u2[1]) u2++;
403 if (! (*u1 && *u2)) {
404 while (*u1 == ' ') u1++;
405 while (*u2 == ' ') u2++;
407 ret = (int)(*u1 - *u2);
417 canonicalise a attribute in DN format
419 static int ldb_canonicalise_dn(struct ldb_context *ldb, void *mem_ctx,
420 const struct ldb_val *in, struct ldb_val *out)
428 dn = ldb_dn_from_ldb_val(mem_ctx, ldb, in);
429 if ( ! ldb_dn_validate(dn)) {
430 return LDB_ERR_INVALID_DN_SYNTAX;
433 out->data = (uint8_t *)ldb_dn_alloc_casefold(mem_ctx, dn);
434 if (out->data == NULL) {
437 out->length = strlen((char *)out->data);
450 static int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx,
451 const struct ldb_val *v1, const struct ldb_val *v2)
453 struct ldb_dn *dn1 = NULL, *dn2 = NULL;
456 dn1 = ldb_dn_from_ldb_val(mem_ctx, ldb, v1);
457 if ( ! ldb_dn_validate(dn1)) return -1;
459 dn2 = ldb_dn_from_ldb_val(mem_ctx, ldb, v2);
460 if ( ! ldb_dn_validate(dn2)) {
465 ret = ldb_dn_compare(dn1, dn2);
473 compare two utc time values. 1 second resolution
475 static int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx,
476 const struct ldb_val *v1, const struct ldb_val *v2)
479 ldb_val_to_time(v1, &t1);
480 ldb_val_to_time(v2, &t2);
481 if (t1 == t2) return 0;
482 return t1 > t2? 1 : -1;
486 canonicalise a utc time
488 static int ldb_canonicalise_utctime(struct ldb_context *ldb, void *mem_ctx,
489 const struct ldb_val *in, struct ldb_val *out)
493 ret = ldb_val_to_time(in, &t);
494 if (ret != LDB_SUCCESS) {
497 out->data = (uint8_t *)ldb_timestring_utc(mem_ctx, t);
498 if (out->data == NULL) {
500 return LDB_ERR_OPERATIONS_ERROR;
502 out->length = strlen((char *)out->data);
507 canonicalise a generalized time
509 static int ldb_canonicalise_generalizedtime(struct ldb_context *ldb, void *mem_ctx,
510 const struct ldb_val *in, struct ldb_val *out)
514 ret = ldb_val_to_time(in, &t);
515 if (ret != LDB_SUCCESS) {
518 out->data = (uint8_t *)ldb_timestring(mem_ctx, t);
519 if (out->data == NULL) {
521 return LDB_ERR_OPERATIONS_ERROR;
523 out->length = strlen((char *)out->data);
528 table of standard attribute handlers
530 static const struct ldb_schema_syntax ldb_standard_syntaxes[] = {
532 .name = LDB_SYNTAX_INTEGER,
533 .ldif_read_fn = ldb_handler_copy,
534 .ldif_write_fn = ldb_handler_copy,
535 .canonicalise_fn = ldb_canonicalise_Integer,
536 .comparison_fn = ldb_comparison_Integer
539 .name = LDB_SYNTAX_ORDERED_INTEGER,
540 .ldif_read_fn = ldb_handler_copy,
541 .ldif_write_fn = ldb_handler_copy,
542 .canonicalise_fn = ldb_canonicalise_Integer,
543 .index_format_fn = ldb_index_format_Integer,
544 .comparison_fn = ldb_comparison_Integer
547 .name = LDB_SYNTAX_OCTET_STRING,
548 .ldif_read_fn = ldb_handler_copy,
549 .ldif_write_fn = ldb_handler_copy,
550 .canonicalise_fn = ldb_handler_copy,
551 .comparison_fn = ldb_comparison_binary
554 .name = LDB_SYNTAX_DIRECTORY_STRING,
555 .ldif_read_fn = ldb_handler_copy,
556 .ldif_write_fn = ldb_handler_copy,
557 .canonicalise_fn = ldb_handler_fold,
558 .comparison_fn = ldb_comparison_fold
561 .name = LDB_SYNTAX_DN,
562 .ldif_read_fn = ldb_handler_copy,
563 .ldif_write_fn = ldb_handler_copy,
564 .canonicalise_fn = ldb_canonicalise_dn,
565 .comparison_fn = ldb_comparison_dn
568 .name = LDB_SYNTAX_OBJECTCLASS,
569 .ldif_read_fn = ldb_handler_copy,
570 .ldif_write_fn = ldb_handler_copy,
571 .canonicalise_fn = ldb_handler_fold,
572 .comparison_fn = ldb_comparison_fold
575 .name = LDB_SYNTAX_UTC_TIME,
576 .ldif_read_fn = ldb_handler_copy,
577 .ldif_write_fn = ldb_handler_copy,
578 .canonicalise_fn = ldb_canonicalise_utctime,
579 .comparison_fn = ldb_comparison_utctime
582 .name = LDB_SYNTAX_GENERALIZED_TIME,
583 .ldif_read_fn = ldb_handler_copy,
584 .ldif_write_fn = ldb_handler_copy,
585 .canonicalise_fn = ldb_canonicalise_generalizedtime,
586 .comparison_fn = ldb_comparison_utctime
589 .name = LDB_SYNTAX_BOOLEAN,
590 .ldif_read_fn = ldb_handler_copy,
591 .ldif_write_fn = ldb_handler_copy,
592 .canonicalise_fn = ldb_canonicalise_Boolean,
593 .comparison_fn = ldb_comparison_Boolean
599 return the attribute handlers for a given syntax name
601 const struct ldb_schema_syntax *ldb_standard_syntax_by_name(struct ldb_context *ldb,
605 unsigned num_handlers = sizeof(ldb_standard_syntaxes)/sizeof(ldb_standard_syntaxes[0]);
606 /* TODO: should be replaced with a binary search */
607 for (i=0;i<num_handlers;i++) {
608 if (strcmp(ldb_standard_syntaxes[i].name, syntax) == 0) {
609 return &ldb_standard_syntaxes[i];
615 int ldb_any_comparison(struct ldb_context *ldb, void *mem_ctx,
616 ldb_attr_handler_t canonicalise_fn,
617 const struct ldb_val *v1,
618 const struct ldb_val *v2)
621 struct ldb_val v1_canon, v2_canon;
622 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
624 /* I could try and bail if tmp_ctx was NULL, but what return
627 * It seems easier to continue on the NULL context
629 ret1 = canonicalise_fn(ldb, tmp_ctx, v1, &v1_canon);
630 ret2 = canonicalise_fn(ldb, tmp_ctx, v2, &v2_canon);
632 if (ret1 == LDB_SUCCESS && ret2 == LDB_SUCCESS) {
633 ret = ldb_comparison_binary(ldb, mem_ctx, &v1_canon, &v2_canon);
635 ret = ldb_comparison_binary(ldb, mem_ctx, v1, v2);
637 talloc_free(tmp_ctx);