added new function "ldb_msg_add_dn"
[Samba/cd1.git] / source4 / lib / ldb / common / attrib_handlers.c
blob1c08741f7d963f4fba06e6b3b3b5d4297528f9e0
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 int 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;
106 canonicalise a ldap Integer
107 rfc2252 specifies it should be in decimal form
109 static int ldb_canonicalise_Integer(struct ldb_context *ldb, void *mem_ctx,
110 const struct ldb_val *in, struct ldb_val *out)
112 char *end;
113 long long i = strtoll((char *)in->data, &end, 0);
114 if (*end != 0) {
115 return -1;
117 out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%lld", i);
118 if (out->data == NULL) {
119 return -1;
121 out->length = strlen((char *)out->data);
122 return 0;
126 compare two Integers
128 static int ldb_comparison_Integer(struct ldb_context *ldb, void *mem_ctx,
129 const struct ldb_val *v1, const struct ldb_val *v2)
131 return strtoll((char *)v1->data, NULL, 0) - strtoll((char *)v2->data, NULL, 0);
135 canonicalise a ldap Boolean
136 rfc2252 specifies it should be either "TRUE" or "FALSE"
138 static int ldb_canonicalise_Boolean(struct ldb_context *ldb, void *mem_ctx,
139 const struct ldb_val *in, struct ldb_val *out)
141 if (strncasecmp((char *)in->data, "TRUE", in->length) == 0) {
142 out->data = (uint8_t *)talloc_strdup(mem_ctx, "TRUE");
143 out->length = 4;
144 } else if (strncasecmp((char *)in->data, "FALSE", in->length) == 0) {
145 out->data = (uint8_t *)talloc_strdup(mem_ctx, "FALSE");
146 out->length = 4;
147 } else {
148 return -1;
150 return 0;
154 compare two Booleans
156 static int ldb_comparison_Boolean(struct ldb_context *ldb, void *mem_ctx,
157 const struct ldb_val *v1, const struct ldb_val *v2)
159 if (v1->length != v2->length) {
160 return v1->length - v2->length;
162 return strncasecmp((char *)v1->data, (char *)v2->data, v1->length);
167 compare two binary blobs
169 int ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx,
170 const struct ldb_val *v1, const struct ldb_val *v2)
172 if (v1->length != v2->length) {
173 return v1->length - v2->length;
175 return memcmp(v1->data, v2->data, v1->length);
179 compare two case insensitive strings, ignoring multiple whitespaces
180 and leading and trailing whitespaces
181 see rfc2252 section 8.1
183 try to optimize for the ascii case,
184 but if we find out an utf8 codepoint revert to slower but correct function
186 int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx,
187 const struct ldb_val *v1, const struct ldb_val *v2)
189 const char *s1=(const char *)v1->data, *s2=(const char *)v2->data;
190 size_t n1 = v1->length, n2 = v2->length;
191 char *b1, *b2;
192 const char *u1, *u2;
193 int ret;
194 while (n1 && *s1 == ' ') { s1++; n1--; };
195 while (n2 && *s2 == ' ') { s2++; n2--; };
197 while (n1 && n2 && *s1 && *s2) {
198 /* the first 127 (0x7F) chars are ascii and utf8 guarantes they
199 * never appear in multibyte sequences */
200 if (((unsigned char)s1[0]) & 0x80) goto utf8str;
201 if (((unsigned char)s2[0]) & 0x80) goto utf8str;
202 if (toupper((unsigned char)*s1) != toupper((unsigned char)*s2))
203 break;
204 if (*s1 == ' ') {
205 while (n1 && s1[0] == s1[1]) { s1++; n1--; }
206 while (n2 && s2[0] == s2[1]) { s2++; n2--; }
208 s1++; s2++;
209 n1--; n2--;
212 /* check for trailing spaces only if the other pointers has
213 * reached the end of the strings otherwise we can
214 * mistakenly match. ex. "domain users" <->
215 * "domainUpdates"
217 if (n1 && *s1 == ' ' && (!n2 || !*s2)) {
218 while (n1 && *s1 == ' ') { s1++; n1--; }
220 if (n2 && *s2 == ' ' && (!n1 || !*s1)) {
221 while (n2 && *s2 == ' ') { s2++; n2--; }
223 if (n1 == 0 && n2 != 0) {
224 return -(int)toupper(*s2);
226 if (n2 == 0 && n1 != 0) {
227 return (int)toupper(*s1);
229 if (n2 == 0 && n2 == 0) {
230 return 0;
232 return (int)toupper(*s1) - (int)toupper(*s2);
234 utf8str:
235 /* no need to recheck from the start, just from the first utf8 char found */
236 b1 = ldb_casefold(ldb, mem_ctx, s1, n1);
237 b2 = ldb_casefold(ldb, mem_ctx, s2, n2);
239 if (!b1 || !b2) {
240 /* One of the strings was not UTF8, so we have no
241 * options but to do a binary compare */
242 talloc_free(b1);
243 talloc_free(b2);
244 if (memcmp(s1, s2, MIN(n1, n2)) == 0) {
245 if (n1 == n2) return 0;
246 if (n1 > n2) {
247 return (int)toupper(s1[n2]);
248 } else {
249 return -(int)toupper(s2[n1]);
254 u1 = b1;
255 u2 = b2;
257 while (*u1 & *u2) {
258 if (*u1 != *u2)
259 break;
260 if (*u1 == ' ') {
261 while (u1[0] == u1[1]) u1++;
262 while (u2[0] == u2[1]) u2++;
264 u1++; u2++;
266 if (! (*u1 && *u2)) {
267 while (*u1 == ' ') u1++;
268 while (*u2 == ' ') u2++;
270 ret = (int)(*u1 - *u2);
272 talloc_free(b1);
273 talloc_free(b2);
275 return ret;
280 canonicalise a attribute in DN format
282 static int ldb_canonicalise_dn(struct ldb_context *ldb, void *mem_ctx,
283 const struct ldb_val *in, struct ldb_val *out)
285 struct ldb_dn *dn;
286 int ret = -1;
288 out->length = 0;
289 out->data = NULL;
291 dn = ldb_dn_from_ldb_val(mem_ctx, ldb, in);
292 if ( ! ldb_dn_validate(dn)) {
293 return LDB_ERR_INVALID_DN_SYNTAX;
296 out->data = (uint8_t *)ldb_dn_alloc_casefold(mem_ctx, dn);
297 if (out->data == NULL) {
298 goto done;
300 out->length = strlen((char *)out->data);
302 ret = 0;
304 done:
305 talloc_free(dn);
307 return ret;
311 compare two dns
313 static int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx,
314 const struct ldb_val *v1, const struct ldb_val *v2)
316 struct ldb_dn *dn1 = NULL, *dn2 = NULL;
317 int ret;
319 dn1 = ldb_dn_from_ldb_val(mem_ctx, ldb, v1);
320 if ( ! ldb_dn_validate(dn1)) return -1;
322 dn2 = ldb_dn_from_ldb_val(mem_ctx, ldb, v2);
323 if ( ! ldb_dn_validate(dn2)) {
324 talloc_free(dn1);
325 return -1;
328 ret = ldb_dn_compare(dn1, dn2);
330 talloc_free(dn1);
331 talloc_free(dn2);
332 return ret;
336 compare two utc time values. 1 second resolution
338 static int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx,
339 const struct ldb_val *v1, const struct ldb_val *v2)
341 time_t t1, t2;
342 t1 = ldb_string_to_time((char *)v1->data);
343 t2 = ldb_string_to_time((char *)v2->data);
344 return (int)t2 - (int)t1;
348 canonicalise a utc time
350 static int ldb_canonicalise_utctime(struct ldb_context *ldb, void *mem_ctx,
351 const struct ldb_val *in, struct ldb_val *out)
353 time_t t = ldb_string_to_time((char *)in->data);
354 out->data = (uint8_t *)ldb_timestring(mem_ctx, t);
355 if (out->data == NULL) {
356 return -1;
358 out->length = strlen((char *)out->data);
359 return 0;
363 table of standard attribute handlers
365 static const struct ldb_schema_syntax ldb_standard_syntaxes[] = {
367 .name = LDB_SYNTAX_INTEGER,
368 .ldif_read_fn = ldb_handler_copy,
369 .ldif_write_fn = ldb_handler_copy,
370 .canonicalise_fn = ldb_canonicalise_Integer,
371 .comparison_fn = ldb_comparison_Integer
374 .name = LDB_SYNTAX_OCTET_STRING,
375 .ldif_read_fn = ldb_handler_copy,
376 .ldif_write_fn = ldb_handler_copy,
377 .canonicalise_fn = ldb_handler_copy,
378 .comparison_fn = ldb_comparison_binary
381 .name = LDB_SYNTAX_DIRECTORY_STRING,
382 .ldif_read_fn = ldb_handler_copy,
383 .ldif_write_fn = ldb_handler_copy,
384 .canonicalise_fn = ldb_handler_fold,
385 .comparison_fn = ldb_comparison_fold
388 .name = LDB_SYNTAX_DN,
389 .ldif_read_fn = ldb_handler_copy,
390 .ldif_write_fn = ldb_handler_copy,
391 .canonicalise_fn = ldb_canonicalise_dn,
392 .comparison_fn = ldb_comparison_dn
395 .name = LDB_SYNTAX_OBJECTCLASS,
396 .ldif_read_fn = ldb_handler_copy,
397 .ldif_write_fn = ldb_handler_copy,
398 .canonicalise_fn = ldb_handler_fold,
399 .comparison_fn = ldb_comparison_fold
402 .name = LDB_SYNTAX_UTC_TIME,
403 .ldif_read_fn = ldb_handler_copy,
404 .ldif_write_fn = ldb_handler_copy,
405 .canonicalise_fn = ldb_canonicalise_utctime,
406 .comparison_fn = ldb_comparison_utctime
409 .name = LDB_SYNTAX_BOOLEAN,
410 .ldif_read_fn = ldb_handler_copy,
411 .ldif_write_fn = ldb_handler_copy,
412 .canonicalise_fn = ldb_canonicalise_Boolean,
413 .comparison_fn = ldb_comparison_Boolean
419 return the attribute handlers for a given syntax name
421 const struct ldb_schema_syntax *ldb_standard_syntax_by_name(struct ldb_context *ldb,
422 const char *syntax)
424 int i;
425 unsigned num_handlers = sizeof(ldb_standard_syntaxes)/sizeof(ldb_standard_syntaxes[0]);
426 /* TODO: should be replaced with a binary search */
427 for (i=0;i<num_handlers;i++) {
428 if (strcmp(ldb_standard_syntaxes[i].name, syntax) == 0) {
429 return &ldb_standard_syntaxes[i];
432 return NULL;
435 int ldb_any_comparison(struct ldb_context *ldb, void *mem_ctx,
436 ldb_attr_handler_t canonicalise_fn,
437 const struct ldb_val *v1,
438 const struct ldb_val *v2)
440 int ret, ret1, ret2;
441 struct ldb_val v1_canon, v2_canon;
442 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
444 /* I could try and bail if tmp_ctx was NULL, but what return
445 * value would I use?
447 * It seems easier to continue on the NULL context
449 ret1 = canonicalise_fn(ldb, tmp_ctx, v1, &v1_canon);
450 ret2 = canonicalise_fn(ldb, tmp_ctx, v2, &v2_canon);
452 if (ret1 == LDB_SUCCESS && ret2 == LDB_SUCCESS) {
453 ret = ldb_comparison_binary(ldb, mem_ctx, &v1_canon, &v2_canon);
454 } else {
455 ret = ldb_comparison_binary(ldb, mem_ctx, v1, v2);
457 talloc_free(tmp_ctx);
458 return ret;