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
30 #include "ldb/include/includes.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 static int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx,
54 const struct ldb_val *in, struct ldb_val *out)
58 if (!in || !out || !(in->data)) {
62 out->data = (uint8_t *)ldb_casefold(ldb, mem_ctx, (const char *)(in->data));
63 if (out->data == NULL) {
64 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_handler_fold: unable to casefold string [%s]", in->data);
68 s = (char *)(out->data);
70 /* remove trailing spaces if any */
72 while (s[l - 1] == ' ') l--;
75 /* remove leading spaces if any */
77 for (t = s; *s == ' '; s++) ;
79 /* remove leading spaces by moving down the string */
85 /* check middle spaces */
86 while ((t = strchr(s, ' ')) != NULL) {
87 for (s = t; *s == ' '; s++) ;
92 /* remove all spaces but one by moving down the string */
97 out->length = strlen((char *)out->data);
104 canonicalise a ldap Integer
105 rfc2252 specifies it should be in decimal form
107 static int ldb_canonicalise_Integer(struct ldb_context *ldb, void *mem_ctx,
108 const struct ldb_val *in, struct ldb_val *out)
111 long long i = strtoll((char *)in->data, &end, 0);
115 out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%lld", i);
116 if (out->data == NULL) {
119 out->length = strlen((char *)out->data);
126 static int ldb_comparison_Integer(struct ldb_context *ldb, void *mem_ctx,
127 const struct ldb_val *v1, const struct ldb_val *v2)
129 return strtoll((char *)v1->data, NULL, 0) - strtoll((char *)v2->data, NULL, 0);
133 compare two binary blobs
135 int ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx,
136 const struct ldb_val *v1, const struct ldb_val *v2)
138 if (v1->length != v2->length) {
139 return v1->length - v2->length;
141 return memcmp(v1->data, v2->data, v1->length);
145 compare two case insensitive strings, ignoring multiple whitespaces
146 and leading and trailing whitespaces
147 see rfc2252 section 8.1
149 try to optimize for the ascii case,
150 but if we find out an utf8 codepoint revert to slower but correct function
152 static int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx,
153 const struct ldb_val *v1, const struct ldb_val *v2)
155 const char *s1=(const char *)v1->data, *s2=(const char *)v2->data;
156 char *b1, *b2, *u1, *u2;
158 while (*s1 == ' ') s1++;
159 while (*s2 == ' ') s2++;
160 /* TODO: make utf8 safe, possibly with helper function from application */
162 /* the first 127 (0x7F) chars are ascii and utf8 guarantes they
163 * never appear in multibyte sequences */
164 if (((unsigned char)s1[0]) & 0x80) goto utf8str;
165 if (((unsigned char)s2[0]) & 0x80) goto utf8str;
166 if (toupper((unsigned char)*s1) != toupper((unsigned char)*s2))
169 while (s1[0] == s1[1]) s1++;
170 while (s2[0] == s2[1]) s2++;
174 if (! (*s1 && *s2)) {
175 /* check for trailing spaces only if one of the pointers
176 * has reached the end of the strings otherwise we
177 * can mistakenly match.
178 * ex. "domain users" <-> "domainUpdates"
180 while (*s1 == ' ') s1++;
181 while (*s2 == ' ') s2++;
183 return (int)(toupper(*s1)) - (int)(toupper(*s2));
186 /* non need to recheck from the start, just from the first utf8 char found */
187 b1 = u1 = ldb_casefold(ldb, mem_ctx, s1);
188 b2 = u2 = ldb_casefold(ldb, mem_ctx, s2);
194 while (u1[0] == u1[1]) u1++;
195 while (u2[0] == u2[1]) u2++;
199 if (! (*u1 && *u2)) {
200 while (*u1 == ' ') u1++;
201 while (*u2 == ' ') u2++;
203 ret = (int)(*u1 - *u2);
211 canonicalise a attribute in DN format
213 static int ldb_canonicalise_dn(struct ldb_context *ldb, void *mem_ctx,
214 const struct ldb_val *in, struct ldb_val *out)
222 dn = ldb_dn_explode_casefold(ldb, (char *)in->data);
227 out->data = (uint8_t *)ldb_dn_linearize(mem_ctx, dn);
228 if (out->data == NULL) {
231 out->length = strlen((char *)out->data);
244 static int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx,
245 const struct ldb_val *v1, const struct ldb_val *v2)
247 struct ldb_dn *dn1 = NULL, *dn2 = NULL;
250 dn1 = ldb_dn_explode_casefold(mem_ctx, (char *)v1->data);
251 if (dn1 == NULL) return -1;
253 dn2 = ldb_dn_explode_casefold(mem_ctx, (char *)v2->data);
259 ret = ldb_dn_compare(ldb, dn1, dn2);
267 compare two objectclasses, looking at subclasses
269 static int ldb_comparison_objectclass(struct ldb_context *ldb, void *mem_ctx,
270 const struct ldb_val *v1, const struct ldb_val *v2)
273 const char **subclasses;
274 ret = ldb_comparison_fold(ldb, mem_ctx, v1, v2);
278 subclasses = ldb_subclass_list(ldb, (char *)v1->data);
279 if (subclasses == NULL) {
282 for (i=0;subclasses[i];i++) {
284 vs.data = discard_const(subclasses[i]);
285 vs.length = strlen(subclasses[i]);
286 if (ldb_comparison_objectclass(ldb, mem_ctx, &vs, v2) == 0) {
294 compare two utc time values. 1 second resolution
296 static int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx,
297 const struct ldb_val *v1, const struct ldb_val *v2)
300 t1 = ldb_string_to_time((char *)v1->data);
301 t2 = ldb_string_to_time((char *)v2->data);
302 return (int)t2 - (int)t1;
306 canonicalise a utc time
308 static int ldb_canonicalise_utctime(struct ldb_context *ldb, void *mem_ctx,
309 const struct ldb_val *in, struct ldb_val *out)
311 time_t t = ldb_string_to_time((char *)in->data);
312 out->data = (uint8_t *)ldb_timestring(mem_ctx, t);
313 if (out->data == NULL) {
316 out->length = strlen((char *)out->data);
321 table of standard attribute handlers
323 static const struct ldb_attrib_handler ldb_standard_attribs[] = {
325 .attr = LDB_SYNTAX_INTEGER,
327 .ldif_read_fn = ldb_handler_copy,
328 .ldif_write_fn = ldb_handler_copy,
329 .canonicalise_fn = ldb_canonicalise_Integer,
330 .comparison_fn = ldb_comparison_Integer
333 .attr = LDB_SYNTAX_OCTET_STRING,
335 .ldif_read_fn = ldb_handler_copy,
336 .ldif_write_fn = ldb_handler_copy,
337 .canonicalise_fn = ldb_handler_copy,
338 .comparison_fn = ldb_comparison_binary
341 .attr = LDB_SYNTAX_DIRECTORY_STRING,
343 .ldif_read_fn = ldb_handler_copy,
344 .ldif_write_fn = ldb_handler_copy,
345 .canonicalise_fn = ldb_handler_fold,
346 .comparison_fn = ldb_comparison_fold
349 .attr = LDB_SYNTAX_DN,
351 .ldif_read_fn = ldb_handler_copy,
352 .ldif_write_fn = ldb_handler_copy,
353 .canonicalise_fn = ldb_canonicalise_dn,
354 .comparison_fn = ldb_comparison_dn
357 .attr = LDB_SYNTAX_OBJECTCLASS,
359 .ldif_read_fn = ldb_handler_copy,
360 .ldif_write_fn = ldb_handler_copy,
361 .canonicalise_fn = ldb_handler_fold,
362 .comparison_fn = ldb_comparison_objectclass
365 .attr = LDB_SYNTAX_UTC_TIME,
367 .ldif_read_fn = ldb_handler_copy,
368 .ldif_write_fn = ldb_handler_copy,
369 .canonicalise_fn = ldb_canonicalise_utctime,
370 .comparison_fn = ldb_comparison_utctime
376 return the attribute handlers for a given syntax name
378 const struct ldb_attrib_handler *ldb_attrib_handler_syntax(struct ldb_context *ldb,
382 unsigned num_handlers = sizeof(ldb_standard_attribs)/sizeof(ldb_standard_attribs[0]);
383 /* TODO: should be replaced with a binary search */
384 for (i=0;i<num_handlers;i++) {
385 if (strcmp(ldb_standard_attribs[i].attr, syntax) == 0) {
386 return &ldb_standard_attribs[i];