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 (*s1 == ' ' && n1) { s1++; n1--; };
194 while (*s2 == ' ' && n2) { s2++; n2--; };
195 /* TODO: make utf8 safe, possibly with helper function from application */
196 while (*s1 && *s2 && n1 && n2) {
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 (s1[0] == s1[1] && n1) { s1++; n1--; }
205 while (s2[0] == s2[1] && n2) { s2++; n2--; }
210 if (! (*s1 && *s2)) {
211 /* check for trailing spaces only if one of the pointers
212 * has reached the end of the strings otherwise we
213 * can mistakenly match.
214 * ex. "domain users" <-> "domainUpdates"
216 while (*s1 == ' ') { s1++; n1--; }
217 while (*s2 == ' ') { s2++; n2--; }
222 return (int)(toupper(*s1)) - (int)(toupper(*s2));
225 /* no need to recheck from the start, just from the first utf8 char found */
226 b1 = ldb_casefold(ldb, mem_ctx, s1, n1);
227 b2 = ldb_casefold(ldb, mem_ctx, s2, n2);
230 /* Both strings converted correctly */
235 /* One of the strings was not UTF8, so we have no options but to do a binary compare */
245 while (u1[0] == u1[1]) u1++;
246 while (u2[0] == u2[1]) u2++;
250 if (! (*u1 && *u2)) {
251 while (*u1 == ' ') u1++;
252 while (*u2 == ' ') u2++;
254 ret = (int)(*u1 - *u2);
264 canonicalise a attribute in DN format
266 static int ldb_canonicalise_dn(struct ldb_context *ldb, void *mem_ctx,
267 const struct ldb_val *in, struct ldb_val *out)
275 dn = ldb_dn_from_ldb_val(ldb, mem_ctx, in);
276 if ( ! ldb_dn_validate(dn)) {
277 return LDB_ERR_INVALID_DN_SYNTAX;
280 out->data = (uint8_t *)ldb_dn_alloc_casefold(mem_ctx, dn);
281 if (out->data == NULL) {
284 out->length = strlen((char *)out->data);
297 static int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx,
298 const struct ldb_val *v1, const struct ldb_val *v2)
300 struct ldb_dn *dn1 = NULL, *dn2 = NULL;
303 dn1 = ldb_dn_from_ldb_val(ldb, mem_ctx, v1);
304 if ( ! ldb_dn_validate(dn1)) return -1;
306 dn2 = ldb_dn_from_ldb_val(ldb, mem_ctx, v2);
307 if ( ! ldb_dn_validate(dn2)) {
312 ret = ldb_dn_compare(dn1, dn2);
320 compare two utc time values. 1 second resolution
322 static int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx,
323 const struct ldb_val *v1, const struct ldb_val *v2)
326 t1 = ldb_string_to_time((char *)v1->data);
327 t2 = ldb_string_to_time((char *)v2->data);
328 return (int)t2 - (int)t1;
332 canonicalise a utc time
334 static int ldb_canonicalise_utctime(struct ldb_context *ldb, void *mem_ctx,
335 const struct ldb_val *in, struct ldb_val *out)
337 time_t t = ldb_string_to_time((char *)in->data);
338 out->data = (uint8_t *)ldb_timestring(mem_ctx, t);
339 if (out->data == NULL) {
342 out->length = strlen((char *)out->data);
347 table of standard attribute handlers
349 static const struct ldb_schema_syntax ldb_standard_syntaxes[] = {
351 .name = LDB_SYNTAX_INTEGER,
352 .ldif_read_fn = ldb_handler_copy,
353 .ldif_write_fn = ldb_handler_copy,
354 .canonicalise_fn = ldb_canonicalise_Integer,
355 .comparison_fn = ldb_comparison_Integer
358 .name = LDB_SYNTAX_OCTET_STRING,
359 .ldif_read_fn = ldb_handler_copy,
360 .ldif_write_fn = ldb_handler_copy,
361 .canonicalise_fn = ldb_handler_copy,
362 .comparison_fn = ldb_comparison_binary
365 .name = LDB_SYNTAX_DIRECTORY_STRING,
366 .ldif_read_fn = ldb_handler_copy,
367 .ldif_write_fn = ldb_handler_copy,
368 .canonicalise_fn = ldb_handler_fold,
369 .comparison_fn = ldb_comparison_fold
372 .name = LDB_SYNTAX_DN,
373 .ldif_read_fn = ldb_handler_copy,
374 .ldif_write_fn = ldb_handler_copy,
375 .canonicalise_fn = ldb_canonicalise_dn,
376 .comparison_fn = ldb_comparison_dn
379 .name = LDB_SYNTAX_OBJECTCLASS,
380 .ldif_read_fn = ldb_handler_copy,
381 .ldif_write_fn = ldb_handler_copy,
382 .canonicalise_fn = ldb_handler_fold,
383 .comparison_fn = ldb_comparison_fold
386 .name = LDB_SYNTAX_UTC_TIME,
387 .ldif_read_fn = ldb_handler_copy,
388 .ldif_write_fn = ldb_handler_copy,
389 .canonicalise_fn = ldb_canonicalise_utctime,
390 .comparison_fn = ldb_comparison_utctime
393 .name = LDB_SYNTAX_BOOLEAN,
394 .ldif_read_fn = ldb_handler_copy,
395 .ldif_write_fn = ldb_handler_copy,
396 .canonicalise_fn = ldb_canonicalise_Boolean,
397 .comparison_fn = ldb_comparison_Boolean
403 return the attribute handlers for a given syntax name
405 const struct ldb_schema_syntax *ldb_standard_syntax_by_name(struct ldb_context *ldb,
409 unsigned num_handlers = sizeof(ldb_standard_syntaxes)/sizeof(ldb_standard_syntaxes[0]);
410 /* TODO: should be replaced with a binary search */
411 for (i=0;i<num_handlers;i++) {
412 if (strcmp(ldb_standard_syntaxes[i].name, syntax) == 0) {
413 return &ldb_standard_syntaxes[i];