4 Copyright (C) Andrew Tridgell 2005
6 ** NOTE! The following LGPL license applies to the ldb
7 ** library. This does NOT imply that all of Samba is released
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.
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.
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/>.
24 attribute handlers for well known attribute types, selected by syntax OID
28 #include "ldb_private.h"
29 #include "system/locale.h"
30 #include "ldb_handlers.h"
33 default handler that just copies a ldb_val.
35 int ldb_handler_copy(struct ldb_context *ldb, void *mem_ctx,
36 const struct ldb_val *in, struct ldb_val *out)
38 *out = ldb_val_dup(mem_ctx, in);
39 if (in->length > 0 && out->data == NULL) {
47 a case folding copy handler, removing leading and trailing spaces and
48 multiple internal spaces
50 We exploit the fact that utf8 never uses the space octet except for
53 int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx,
54 const struct ldb_val *in, struct ldb_val *out)
59 if (!in || !out || !(in->data)) {
63 out->data = (uint8_t *)ldb_casefold(ldb, mem_ctx, (const char *)(in->data), in->length);
64 if (out->data == NULL) {
65 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_handler_fold: unable to casefold string [%s]", in->data);
69 s = (char *)(out->data);
71 /* remove trailing spaces if any */
73 while (l > 0 && s[l - 1] == ' ') l--;
76 /* remove leading spaces if any */
78 for (t = s; *s == ' '; s++) ;
80 /* remove leading spaces by moving down the string */
86 /* check middle spaces */
87 while ((t = strchr(s, ' ')) != NULL) {
88 for (s = t; *s == ' '; s++) ;
93 /* remove all spaces but one by moving down the string */
98 out->length = strlen((char *)out->data);
105 canonicalise a ldap Integer
106 rfc2252 specifies it should be in decimal form
108 static int ldb_canonicalise_Integer(struct ldb_context *ldb, void *mem_ctx,
109 const struct ldb_val *in, struct ldb_val *out)
112 long long i = strtoll((char *)in->data, &end, 0);
116 out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%lld", i);
117 if (out->data == NULL) {
120 out->length = strlen((char *)out->data);
127 static int ldb_comparison_Integer(struct ldb_context *ldb, void *mem_ctx,
128 const struct ldb_val *v1, const struct ldb_val *v2)
130 return strtoll((char *)v1->data, NULL, 0) - strtoll((char *)v2->data, NULL, 0);
134 canonicalise a ldap Boolean
135 rfc2252 specifies it should be either "TRUE" or "FALSE"
137 static int ldb_canonicalise_Boolean(struct ldb_context *ldb, void *mem_ctx,
138 const struct ldb_val *in, struct ldb_val *out)
140 if (strncasecmp((char *)in->data, "TRUE", in->length) == 0) {
141 out->data = (uint8_t *)talloc_strdup(mem_ctx, "TRUE");
143 } else if (strncasecmp((char *)in->data, "FALSE", in->length) == 0) {
144 out->data = (uint8_t *)talloc_strdup(mem_ctx, "FALSE");
155 static int ldb_comparison_Boolean(struct ldb_context *ldb, void *mem_ctx,
156 const struct ldb_val *v1, const struct ldb_val *v2)
158 if (v1->length != v2->length) {
159 return v1->length - v2->length;
161 return strncasecmp((char *)v1->data, (char *)v2->data, v1->length);
166 compare two binary blobs
168 int ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx,
169 const struct ldb_val *v1, const struct ldb_val *v2)
171 if (v1->length != v2->length) {
172 return v1->length - v2->length;
174 return memcmp(v1->data, v2->data, v1->length);
178 compare two case insensitive strings, ignoring multiple whitespaces
179 and leading and trailing whitespaces
180 see rfc2252 section 8.1
182 try to optimize for the ascii case,
183 but if we find out an utf8 codepoint revert to slower but correct function
185 int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx,
186 const struct ldb_val *v1, const struct ldb_val *v2)
188 const char *s1=(const char *)v1->data, *s2=(const char *)v2->data;
189 size_t n1 = v1->length, n2 = v2->length;
193 while (n1 && *s1 == ' ') { s1++; n1--; };
194 while (n2 && *s2 == ' ') { s2++; n2--; };
196 while (n1 && n2 && *s1 && *s2) {
197 /* the first 127 (0x7F) chars are ascii and utf8 guarantes they
198 * never appear in multibyte sequences */
199 if (((unsigned char)s1[0]) & 0x80) goto utf8str;
200 if (((unsigned char)s2[0]) & 0x80) goto utf8str;
201 if (toupper((unsigned char)*s1) != toupper((unsigned char)*s2))
204 while (n1 && s1[0] == s1[1]) { s1++; n1--; }
205 while (n2 && s2[0] == s2[1]) { s2++; n2--; }
211 /* check for trailing spaces only if the other pointers has
212 * reached the end of the strings otherwise we can
213 * mistakenly match. ex. "domain users" <->
216 if (n1 && *s1 == ' ' && (!n2 || !*s2)) {
217 while (n1 && *s1 == ' ') { s1++; n1--; }
219 if (n2 && *s2 == ' ' && (!n1 || !*s1)) {
220 while (n2 && *s2 == ' ') { s2++; n2--; }
222 if (n1 == 0 && n2 != 0) {
223 return -(int)toupper(*s2);
225 if (n2 == 0 && n1 != 0) {
226 return (int)toupper(*s1);
228 if (n2 == 0 && n2 == 0) {
231 return (int)toupper(*s1) - (int)toupper(*s2);
234 /* no need to recheck from the start, just from the first utf8 char found */
235 b1 = ldb_casefold(ldb, mem_ctx, s1, n1);
236 b2 = ldb_casefold(ldb, mem_ctx, s2, n2);
239 /* One of the strings was not UTF8, so we have no
240 * options but to do a binary compare */
243 if (memcmp(s1, s2, MIN(n1, n2)) == 0) {
244 if (n1 == n2) return 0;
246 return (int)toupper(s1[n2]);
248 return -(int)toupper(s2[n1]);
260 while (u1[0] == u1[1]) u1++;
261 while (u2[0] == u2[1]) u2++;
265 if (! (*u1 && *u2)) {
266 while (*u1 == ' ') u1++;
267 while (*u2 == ' ') u2++;
269 ret = (int)(*u1 - *u2);
279 canonicalise a attribute in DN format
281 static int ldb_canonicalise_dn(struct ldb_context *ldb, void *mem_ctx,
282 const struct ldb_val *in, struct ldb_val *out)
290 dn = ldb_dn_from_ldb_val(ldb, mem_ctx, in);
291 if ( ! ldb_dn_validate(dn)) {
292 return LDB_ERR_INVALID_DN_SYNTAX;
295 out->data = (uint8_t *)ldb_dn_alloc_casefold(mem_ctx, dn);
296 if (out->data == NULL) {
299 out->length = strlen((char *)out->data);
312 static int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx,
313 const struct ldb_val *v1, const struct ldb_val *v2)
315 struct ldb_dn *dn1 = NULL, *dn2 = NULL;
318 dn1 = ldb_dn_from_ldb_val(ldb, mem_ctx, v1);
319 if ( ! ldb_dn_validate(dn1)) return -1;
321 dn2 = ldb_dn_from_ldb_val(ldb, mem_ctx, v2);
322 if ( ! ldb_dn_validate(dn2)) {
327 ret = ldb_dn_compare(dn1, dn2);
335 compare two utc time values. 1 second resolution
337 static int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx,
338 const struct ldb_val *v1, const struct ldb_val *v2)
341 t1 = ldb_string_to_time((char *)v1->data);
342 t2 = ldb_string_to_time((char *)v2->data);
343 return (int)t2 - (int)t1;
347 canonicalise a utc time
349 static int ldb_canonicalise_utctime(struct ldb_context *ldb, void *mem_ctx,
350 const struct ldb_val *in, struct ldb_val *out)
352 time_t t = ldb_string_to_time((char *)in->data);
353 out->data = (uint8_t *)ldb_timestring(mem_ctx, t);
354 if (out->data == NULL) {
357 out->length = strlen((char *)out->data);
362 table of standard attribute handlers
364 static const struct ldb_schema_syntax ldb_standard_syntaxes[] = {
366 .name = LDB_SYNTAX_INTEGER,
367 .ldif_read_fn = ldb_handler_copy,
368 .ldif_write_fn = ldb_handler_copy,
369 .canonicalise_fn = ldb_canonicalise_Integer,
370 .comparison_fn = ldb_comparison_Integer
373 .name = LDB_SYNTAX_OCTET_STRING,
374 .ldif_read_fn = ldb_handler_copy,
375 .ldif_write_fn = ldb_handler_copy,
376 .canonicalise_fn = ldb_handler_copy,
377 .comparison_fn = ldb_comparison_binary
380 .name = LDB_SYNTAX_DIRECTORY_STRING,
381 .ldif_read_fn = ldb_handler_copy,
382 .ldif_write_fn = ldb_handler_copy,
383 .canonicalise_fn = ldb_handler_fold,
384 .comparison_fn = ldb_comparison_fold
387 .name = LDB_SYNTAX_DN,
388 .ldif_read_fn = ldb_handler_copy,
389 .ldif_write_fn = ldb_handler_copy,
390 .canonicalise_fn = ldb_canonicalise_dn,
391 .comparison_fn = ldb_comparison_dn
394 .name = LDB_SYNTAX_OBJECTCLASS,
395 .ldif_read_fn = ldb_handler_copy,
396 .ldif_write_fn = ldb_handler_copy,
397 .canonicalise_fn = ldb_handler_fold,
398 .comparison_fn = ldb_comparison_fold
401 .name = LDB_SYNTAX_UTC_TIME,
402 .ldif_read_fn = ldb_handler_copy,
403 .ldif_write_fn = ldb_handler_copy,
404 .canonicalise_fn = ldb_canonicalise_utctime,
405 .comparison_fn = ldb_comparison_utctime
408 .name = LDB_SYNTAX_BOOLEAN,
409 .ldif_read_fn = ldb_handler_copy,
410 .ldif_write_fn = ldb_handler_copy,
411 .canonicalise_fn = ldb_canonicalise_Boolean,
412 .comparison_fn = ldb_comparison_Boolean
418 return the attribute handlers for a given syntax name
420 const struct ldb_schema_syntax *ldb_standard_syntax_by_name(struct ldb_context *ldb,
424 unsigned num_handlers = sizeof(ldb_standard_syntaxes)/sizeof(ldb_standard_syntaxes[0]);
425 /* TODO: should be replaced with a binary search */
426 for (i=0;i<num_handlers;i++) {
427 if (strcmp(ldb_standard_syntaxes[i].name, syntax) == 0) {
428 return &ldb_standard_syntaxes[i];