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 2 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, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 attribute handlers for well known attribute types, selected by syntax OID
29 #include "ldb_includes.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)
59 if (!in || !out || !(in->data)) {
63 out->data = (uint8_t *)ldb_casefold(ldb, mem_ctx, (const char *)(in->data));
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 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 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 compare two binary blobs
136 int ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx,
137 const struct ldb_val *v1, const struct ldb_val *v2)
139 if (v1->length != v2->length) {
140 return v1->length - v2->length;
142 return memcmp(v1->data, v2->data, v1->length);
146 compare two case insensitive strings, ignoring multiple whitespaces
147 and leading and trailing whitespaces
148 see rfc2252 section 8.1
150 try to optimize for the ascii case,
151 but if we find out an utf8 codepoint revert to slower but correct function
153 int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx,
154 const struct ldb_val *v1, const struct ldb_val *v2)
156 const char *s1=(const char *)v1->data, *s2=(const char *)v2->data;
160 while (*s1 == ' ') s1++;
161 while (*s2 == ' ') s2++;
162 /* TODO: make utf8 safe, possibly with helper function from application */
164 /* the first 127 (0x7F) chars are ascii and utf8 guarantes they
165 * never appear in multibyte sequences */
166 if (((unsigned char)s1[0]) & 0x80) goto utf8str;
167 if (((unsigned char)s2[0]) & 0x80) goto utf8str;
168 if (toupper((unsigned char)*s1) != toupper((unsigned char)*s2))
171 while (s1[0] == s1[1]) s1++;
172 while (s2[0] == s2[1]) s2++;
176 if (! (*s1 && *s2)) {
177 /* check for trailing spaces only if one of the pointers
178 * has reached the end of the strings otherwise we
179 * can mistakenly match.
180 * ex. "domain users" <-> "domainUpdates"
182 while (*s1 == ' ') s1++;
183 while (*s2 == ' ') s2++;
185 return (int)(toupper(*s1)) - (int)(toupper(*s2));
188 /* no need to recheck from the start, just from the first utf8 char found */
189 b1 = ldb_casefold(ldb, mem_ctx, s1);
190 b2 = ldb_casefold(ldb, mem_ctx, s2);
193 /* Both strings converted correctly */
198 /* One of the strings was not UTF8, so we have no options but to do a binary compare */
208 while (u1[0] == u1[1]) u1++;
209 while (u2[0] == u2[1]) u2++;
213 if (! (*u1 && *u2)) {
214 while (*u1 == ' ') u1++;
215 while (*u2 == ' ') u2++;
217 ret = (int)(*u1 - *u2);
226 canonicalise a attribute in DN format
228 int ldb_canonicalise_dn(struct ldb_context *ldb, void *mem_ctx,
229 const struct ldb_val *in, struct ldb_val *out)
237 dn = ldb_dn_new(ldb, mem_ctx, (char *)in->data);
238 if ( ! ldb_dn_validate(dn)) {
239 return LDB_ERR_INVALID_DN_SYNTAX;
242 out->data = (uint8_t *)ldb_dn_alloc_casefold(mem_ctx, dn);
243 if (out->data == NULL) {
246 out->length = strlen((char *)out->data);
259 int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx,
260 const struct ldb_val *v1, const struct ldb_val *v2)
262 struct ldb_dn *dn1 = NULL, *dn2 = NULL;
265 dn1 = ldb_dn_new(ldb, mem_ctx, (char *)v1->data);
266 if ( ! ldb_dn_validate(dn1)) return -1;
268 dn2 = ldb_dn_new(ldb, mem_ctx, (char *)v2->data);
269 if ( ! ldb_dn_validate(dn2)) {
274 ret = ldb_dn_compare(dn1, dn2);
282 compare two objectclasses, looking at subclasses
284 int ldb_comparison_objectclass(struct ldb_context *ldb, void *mem_ctx,
285 const struct ldb_val *v1, const struct ldb_val *v2)
288 const char **subclasses;
289 ret = ldb_comparison_fold(ldb, mem_ctx, v1, v2);
293 subclasses = ldb_subclass_list(ldb, (char *)v1->data);
294 if (subclasses == NULL) {
297 for (i=0;subclasses[i];i++) {
299 vs.data = discard_const(subclasses[i]);
300 vs.length = strlen(subclasses[i]);
301 if (ldb_comparison_objectclass(ldb, mem_ctx, &vs, v2) == 0) {
309 compare two utc time values. 1 second resolution
311 int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx,
312 const struct ldb_val *v1, const struct ldb_val *v2)
315 t1 = ldb_string_to_time((char *)v1->data);
316 t2 = ldb_string_to_time((char *)v2->data);
317 return (int)t2 - (int)t1;
321 canonicalise a utc time
323 int ldb_canonicalise_utctime(struct ldb_context *ldb, void *mem_ctx,
324 const struct ldb_val *in, struct ldb_val *out)
326 time_t t = ldb_string_to_time((char *)in->data);
327 out->data = (uint8_t *)ldb_timestring(mem_ctx, t);
328 if (out->data == NULL) {
331 out->length = strlen((char *)out->data);
336 table of standard attribute handlers
338 static const struct ldb_schema_syntax ldb_standard_syntaxes[] = {
340 .name = LDB_SYNTAX_INTEGER,
341 .ldif_read_fn = ldb_handler_copy,
342 .ldif_write_fn = ldb_handler_copy,
343 .canonicalise_fn = ldb_canonicalise_Integer,
344 .comparison_fn = ldb_comparison_Integer
347 .name = LDB_SYNTAX_OCTET_STRING,
348 .ldif_read_fn = ldb_handler_copy,
349 .ldif_write_fn = ldb_handler_copy,
350 .canonicalise_fn = ldb_handler_copy,
351 .comparison_fn = ldb_comparison_binary
354 .name = LDB_SYNTAX_DIRECTORY_STRING,
355 .ldif_read_fn = ldb_handler_copy,
356 .ldif_write_fn = ldb_handler_copy,
357 .canonicalise_fn = ldb_handler_fold,
358 .comparison_fn = ldb_comparison_fold
361 .name = LDB_SYNTAX_DN,
362 .ldif_read_fn = ldb_handler_copy,
363 .ldif_write_fn = ldb_handler_copy,
364 .canonicalise_fn = ldb_canonicalise_dn,
365 .comparison_fn = ldb_comparison_dn
368 .name = LDB_SYNTAX_OBJECTCLASS,
369 .ldif_read_fn = ldb_handler_copy,
370 .ldif_write_fn = ldb_handler_copy,
371 .canonicalise_fn = ldb_handler_fold,
372 .comparison_fn = ldb_comparison_objectclass
375 .name = LDB_SYNTAX_UTC_TIME,
376 .ldif_read_fn = ldb_handler_copy,
377 .ldif_write_fn = ldb_handler_copy,
378 .canonicalise_fn = ldb_canonicalise_utctime,
379 .comparison_fn = ldb_comparison_utctime
385 return the attribute handlers for a given syntax name
387 const struct ldb_schema_syntax *ldb_standard_syntax_by_name(struct ldb_context *ldb,
391 unsigned num_handlers = sizeof(ldb_standard_syntaxes)/sizeof(ldb_standard_syntaxes[0]);
392 /* TODO: should be replaced with a binary search */
393 for (i=0;i<num_handlers;i++) {
394 if (strcmp(ldb_standard_syntaxes[i].name, syntax) == 0) {
395 return &ldb_standard_syntaxes[i];