s3: Fix a typo
[Samba/gebeck_regimport.git] / lib / ldb / common / attrib_handlers.c
blobdaeb422aca3c6c54a43dfb6367fb106048724b87
1 /*
2 ldb database library
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
9 ** under the LGPL
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
26 see rfc2252
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) {
41 ldb_oom(ldb);
42 return -1;
44 return 0;
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
52 the space itself
54 int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx,
55 const struct ldb_val *in, struct ldb_val *out)
57 char *s, *t;
58 size_t l;
60 if (!in || !out || !(in->data)) {
61 return -1;
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);
67 return -1;
70 s = (char *)(out->data);
72 /* remove trailing spaces if any */
73 l = strlen(s);
74 while (l > 0 && s[l - 1] == ' ') l--;
75 s[l] = '\0';
77 /* remove leading spaces if any */
78 if (*s == ' ') {
79 for (t = s; *s == ' '; s++) ;
81 /* remove leading spaces by moving down the string */
82 memmove(t, s, l);
84 s = t;
87 /* check middle spaces */
88 while ((t = strchr(s, ' ')) != NULL) {
89 for (s = t; *s == ' '; s++) ;
91 if ((s - t) > 1) {
92 l = strlen(s);
94 /* remove all spaces but one by moving down the string */
95 memmove(t + 1, s, l);
99 out->length = strlen((char *)out->data);
100 return 0;
103 /* length limited conversion of a ldb_val to a int32_t */
104 static int val_to_int64(const struct ldb_val *in, int64_t *v)
106 char *end;
107 char buf[64];
109 /* make sure we don't read past the end of the data */
110 if (in->length > sizeof(buf)-1) {
111 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
113 strncpy(buf, (char *)in->data, in->length);
114 buf[in->length] = 0;
116 /* We've to use "strtoll" here to have the intended overflows.
117 * Otherwise we may get "LONG_MAX" and the conversion is wrong. */
118 *v = (int64_t) strtoll(buf, &end, 0);
119 if (*end != 0) {
120 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
122 return LDB_SUCCESS;
127 canonicalise a ldap Integer
128 rfc2252 specifies it should be in decimal form
130 static int ldb_canonicalise_Integer(struct ldb_context *ldb, void *mem_ctx,
131 const struct ldb_val *in, struct ldb_val *out)
133 int64_t i;
134 int ret;
136 ret = val_to_int64(in, &i);
137 if (ret != LDB_SUCCESS) {
138 return ret;
140 out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%lld", (long long)i);
141 if (out->data == NULL) {
142 ldb_oom(ldb);
143 return LDB_ERR_OPERATIONS_ERROR;
145 out->length = strlen((char *)out->data);
146 return 0;
150 compare two Integers
152 static int ldb_comparison_Integer(struct ldb_context *ldb, void *mem_ctx,
153 const struct ldb_val *v1, const struct ldb_val *v2)
155 int64_t i1=0, i2=0;
156 val_to_int64(v1, &i1);
157 val_to_int64(v2, &i2);
158 if (i1 == i2) return 0;
159 return i1 > i2? 1 : -1;
163 canonicalise a ldap Boolean
164 rfc2252 specifies it should be either "TRUE" or "FALSE"
166 static int ldb_canonicalise_Boolean(struct ldb_context *ldb, void *mem_ctx,
167 const struct ldb_val *in, struct ldb_val *out)
169 if (in->length >= 4 && strncasecmp((char *)in->data, "TRUE", in->length) == 0) {
170 out->data = (uint8_t *)talloc_strdup(mem_ctx, "TRUE");
171 out->length = 4;
172 } else if (in->length >= 5 && strncasecmp((char *)in->data, "FALSE", in->length) == 0) {
173 out->data = (uint8_t *)talloc_strdup(mem_ctx, "FALSE");
174 out->length = 5;
175 } else {
176 return -1;
178 return 0;
182 compare two Booleans
184 static int ldb_comparison_Boolean(struct ldb_context *ldb, void *mem_ctx,
185 const struct ldb_val *v1, const struct ldb_val *v2)
187 if (v1->length != v2->length) {
188 return v1->length - v2->length;
190 return strncasecmp((char *)v1->data, (char *)v2->data, v1->length);
195 compare two binary blobs
197 int ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx,
198 const struct ldb_val *v1, const struct ldb_val *v2)
200 if (v1->length != v2->length) {
201 return v1->length - v2->length;
203 return memcmp(v1->data, v2->data, v1->length);
207 compare two case insensitive strings, ignoring multiple whitespaces
208 and leading and trailing whitespaces
209 see rfc2252 section 8.1
211 try to optimize for the ascii case,
212 but if we find out an utf8 codepoint revert to slower but correct function
214 int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx,
215 const struct ldb_val *v1, const struct ldb_val *v2)
217 const char *s1=(const char *)v1->data, *s2=(const char *)v2->data;
218 size_t n1 = v1->length, n2 = v2->length;
219 char *b1, *b2;
220 const char *u1, *u2;
221 int ret;
222 while (n1 && *s1 == ' ') { s1++; n1--; };
223 while (n2 && *s2 == ' ') { s2++; n2--; };
225 while (n1 && n2 && *s1 && *s2) {
226 /* the first 127 (0x7F) chars are ascii and utf8 guarantes they
227 * never appear in multibyte sequences */
228 if (((unsigned char)s1[0]) & 0x80) goto utf8str;
229 if (((unsigned char)s2[0]) & 0x80) goto utf8str;
230 if (toupper((unsigned char)*s1) != toupper((unsigned char)*s2))
231 break;
232 if (*s1 == ' ') {
233 while (n1 && s1[0] == s1[1]) { s1++; n1--; }
234 while (n2 && s2[0] == s2[1]) { s2++; n2--; }
236 s1++; s2++;
237 n1--; n2--;
240 /* check for trailing spaces only if the other pointers has
241 * reached the end of the strings otherwise we can
242 * mistakenly match. ex. "domain users" <->
243 * "domainUpdates"
245 if (n1 && *s1 == ' ' && (!n2 || !*s2)) {
246 while (n1 && *s1 == ' ') { s1++; n1--; }
248 if (n2 && *s2 == ' ' && (!n1 || !*s1)) {
249 while (n2 && *s2 == ' ') { s2++; n2--; }
251 if (n1 == 0 && n2 != 0) {
252 return -(int)toupper(*s2);
254 if (n2 == 0 && n1 != 0) {
255 return (int)toupper(*s1);
257 if (n2 == 0 && n2 == 0) {
258 return 0;
260 return (int)toupper(*s1) - (int)toupper(*s2);
262 utf8str:
263 /* no need to recheck from the start, just from the first utf8 char found */
264 b1 = ldb_casefold(ldb, mem_ctx, s1, n1);
265 b2 = ldb_casefold(ldb, mem_ctx, s2, n2);
267 if (!b1 || !b2) {
268 /* One of the strings was not UTF8, so we have no
269 * options but to do a binary compare */
270 talloc_free(b1);
271 talloc_free(b2);
272 ret = memcmp(s1, s2, MIN(n1, n2));
273 if (ret == 0) {
274 if (n1 == n2) return 0;
275 if (n1 > n2) {
276 return (int)toupper(s1[n2]);
277 } else {
278 return -(int)toupper(s2[n1]);
281 return ret;
284 u1 = b1;
285 u2 = b2;
287 while (*u1 & *u2) {
288 if (*u1 != *u2)
289 break;
290 if (*u1 == ' ') {
291 while (u1[0] == u1[1]) u1++;
292 while (u2[0] == u2[1]) u2++;
294 u1++; u2++;
296 if (! (*u1 && *u2)) {
297 while (*u1 == ' ') u1++;
298 while (*u2 == ' ') u2++;
300 ret = (int)(*u1 - *u2);
302 talloc_free(b1);
303 talloc_free(b2);
305 return ret;
310 canonicalise a attribute in DN format
312 static int ldb_canonicalise_dn(struct ldb_context *ldb, void *mem_ctx,
313 const struct ldb_val *in, struct ldb_val *out)
315 struct ldb_dn *dn;
316 int ret = -1;
318 out->length = 0;
319 out->data = NULL;
321 dn = ldb_dn_from_ldb_val(mem_ctx, ldb, in);
322 if ( ! ldb_dn_validate(dn)) {
323 return LDB_ERR_INVALID_DN_SYNTAX;
326 out->data = (uint8_t *)ldb_dn_alloc_casefold(mem_ctx, dn);
327 if (out->data == NULL) {
328 goto done;
330 out->length = strlen((char *)out->data);
332 ret = 0;
334 done:
335 talloc_free(dn);
337 return ret;
341 compare two dns
343 static int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx,
344 const struct ldb_val *v1, const struct ldb_val *v2)
346 struct ldb_dn *dn1 = NULL, *dn2 = NULL;
347 int ret;
349 dn1 = ldb_dn_from_ldb_val(mem_ctx, ldb, v1);
350 if ( ! ldb_dn_validate(dn1)) return -1;
352 dn2 = ldb_dn_from_ldb_val(mem_ctx, ldb, v2);
353 if ( ! ldb_dn_validate(dn2)) {
354 talloc_free(dn1);
355 return -1;
358 ret = ldb_dn_compare(dn1, dn2);
360 talloc_free(dn1);
361 talloc_free(dn2);
362 return ret;
366 compare two utc time values. 1 second resolution
368 static int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx,
369 const struct ldb_val *v1, const struct ldb_val *v2)
371 time_t t1=0, t2=0;
372 ldb_val_to_time(v1, &t1);
373 ldb_val_to_time(v2, &t2);
374 if (t1 == t2) return 0;
375 return t1 > t2? 1 : -1;
379 canonicalise a utc time
381 static int ldb_canonicalise_utctime(struct ldb_context *ldb, void *mem_ctx,
382 const struct ldb_val *in, struct ldb_val *out)
384 time_t t;
385 int ret;
386 ret = ldb_val_to_time(in, &t);
387 if (ret != LDB_SUCCESS) {
388 return ret;
390 out->data = (uint8_t *)ldb_timestring_utc(mem_ctx, t);
391 if (out->data == NULL) {
392 ldb_oom(ldb);
393 return LDB_ERR_OPERATIONS_ERROR;
395 out->length = strlen((char *)out->data);
396 return 0;
400 canonicalise a generalized time
402 static int ldb_canonicalise_generalizedtime(struct ldb_context *ldb, void *mem_ctx,
403 const struct ldb_val *in, struct ldb_val *out)
405 time_t t;
406 int ret;
407 ret = ldb_val_to_time(in, &t);
408 if (ret != LDB_SUCCESS) {
409 return ret;
411 out->data = (uint8_t *)ldb_timestring(mem_ctx, t);
412 if (out->data == NULL) {
413 ldb_oom(ldb);
414 return LDB_ERR_OPERATIONS_ERROR;
416 out->length = strlen((char *)out->data);
417 return 0;
421 table of standard attribute handlers
423 static const struct ldb_schema_syntax ldb_standard_syntaxes[] = {
425 .name = LDB_SYNTAX_INTEGER,
426 .ldif_read_fn = ldb_handler_copy,
427 .ldif_write_fn = ldb_handler_copy,
428 .canonicalise_fn = ldb_canonicalise_Integer,
429 .comparison_fn = ldb_comparison_Integer
432 .name = LDB_SYNTAX_OCTET_STRING,
433 .ldif_read_fn = ldb_handler_copy,
434 .ldif_write_fn = ldb_handler_copy,
435 .canonicalise_fn = ldb_handler_copy,
436 .comparison_fn = ldb_comparison_binary
439 .name = LDB_SYNTAX_DIRECTORY_STRING,
440 .ldif_read_fn = ldb_handler_copy,
441 .ldif_write_fn = ldb_handler_copy,
442 .canonicalise_fn = ldb_handler_fold,
443 .comparison_fn = ldb_comparison_fold
446 .name = LDB_SYNTAX_DN,
447 .ldif_read_fn = ldb_handler_copy,
448 .ldif_write_fn = ldb_handler_copy,
449 .canonicalise_fn = ldb_canonicalise_dn,
450 .comparison_fn = ldb_comparison_dn
453 .name = LDB_SYNTAX_OBJECTCLASS,
454 .ldif_read_fn = ldb_handler_copy,
455 .ldif_write_fn = ldb_handler_copy,
456 .canonicalise_fn = ldb_handler_fold,
457 .comparison_fn = ldb_comparison_fold
460 .name = LDB_SYNTAX_UTC_TIME,
461 .ldif_read_fn = ldb_handler_copy,
462 .ldif_write_fn = ldb_handler_copy,
463 .canonicalise_fn = ldb_canonicalise_utctime,
464 .comparison_fn = ldb_comparison_utctime
467 .name = LDB_SYNTAX_GENERALIZED_TIME,
468 .ldif_read_fn = ldb_handler_copy,
469 .ldif_write_fn = ldb_handler_copy,
470 .canonicalise_fn = ldb_canonicalise_generalizedtime,
471 .comparison_fn = ldb_comparison_utctime
474 .name = LDB_SYNTAX_BOOLEAN,
475 .ldif_read_fn = ldb_handler_copy,
476 .ldif_write_fn = ldb_handler_copy,
477 .canonicalise_fn = ldb_canonicalise_Boolean,
478 .comparison_fn = ldb_comparison_Boolean
484 return the attribute handlers for a given syntax name
486 const struct ldb_schema_syntax *ldb_standard_syntax_by_name(struct ldb_context *ldb,
487 const char *syntax)
489 unsigned int i;
490 unsigned num_handlers = sizeof(ldb_standard_syntaxes)/sizeof(ldb_standard_syntaxes[0]);
491 /* TODO: should be replaced with a binary search */
492 for (i=0;i<num_handlers;i++) {
493 if (strcmp(ldb_standard_syntaxes[i].name, syntax) == 0) {
494 return &ldb_standard_syntaxes[i];
497 return NULL;
500 int ldb_any_comparison(struct ldb_context *ldb, void *mem_ctx,
501 ldb_attr_handler_t canonicalise_fn,
502 const struct ldb_val *v1,
503 const struct ldb_val *v2)
505 int ret, ret1, ret2;
506 struct ldb_val v1_canon, v2_canon;
507 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
509 /* I could try and bail if tmp_ctx was NULL, but what return
510 * value would I use?
512 * It seems easier to continue on the NULL context
514 ret1 = canonicalise_fn(ldb, tmp_ctx, v1, &v1_canon);
515 ret2 = canonicalise_fn(ldb, tmp_ctx, v2, &v2_canon);
517 if (ret1 == LDB_SUCCESS && ret2 == LDB_SUCCESS) {
518 ret = ldb_comparison_binary(ldb, mem_ctx, &v1_canon, &v2_canon);
519 } else {
520 ret = ldb_comparison_binary(ldb, mem_ctx, v1, v2);
522 talloc_free(tmp_ctx);
523 return ret;