r25068: Older samba3 DCs will return DCERPC_FAULT_OP_RNG_ERROR for every opcode on the
[Samba.git] / source / lib / ldb / common / attrib_handlers.c
blob2b699aeaa81e5f34d3432d31247b58deafaae8b4
1 /*
2 ldb database library
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
8 ** under the LGPL
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
26 see rfc2252
29 #include "includes.h"
30 #include "ldb/include/includes.h"
31 #include "system/locale.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 static 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;
59 if (!in || !out || !(in->data)) {
60 return -1;
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);
66 return -1;
69 s = (char *)(out->data);
71 /* remove trailing spaces if any */
72 l = strlen(s);
73 while (l > 0 && s[l - 1] == ' ') l--;
74 s[l] = '\0';
76 /* remove leading spaces if any */
77 if (*s == ' ') {
78 for (t = s; *s == ' '; s++) ;
80 /* remove leading spaces by moving down the string */
81 memmove(t, s, l);
83 s = t;
86 /* check middle spaces */
87 while ((t = strchr(s, ' ')) != NULL) {
88 for (s = t; *s == ' '; s++) ;
90 if ((s - t) > 1) {
91 l = strlen(s);
93 /* remove all spaces but one by moving down the string */
94 memmove(t + 1, s, l);
98 out->length = strlen((char *)out->data);
99 return 0;
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)
111 char *end;
112 long long i = strtoll((char *)in->data, &end, 0);
113 if (*end != 0) {
114 return -1;
116 out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%lld", i);
117 if (out->data == NULL) {
118 return -1;
120 out->length = strlen((char *)out->data);
121 return 0;
125 compare two Integers
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 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 static 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;
157 const char *u1, *u2;
158 char *b1, *b2;
159 int ret;
160 while (*s1 == ' ') s1++;
161 while (*s2 == ' ') s2++;
162 /* TODO: make utf8 safe, possibly with helper function from application */
163 while (*s1 && *s2) {
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))
169 break;
170 if (*s1 == ' ') {
171 while (s1[0] == s1[1]) s1++;
172 while (s2[0] == s2[1]) s2++;
174 s1++; 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));
187 utf8str:
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);
192 if (b1 && b2) {
193 /* Both strings converted correctly */
195 u1 = b1;
196 u2 = b2;
197 } else {
198 /* One of the strings was not UTF8, so we have no options but to do a binary compare */
200 u1 = s1;
201 u2 = s2;
204 while (*u1 & *u2) {
205 if (*u1 != *u2)
206 break;
207 if (*u1 == ' ') {
208 while (u1[0] == u1[1]) u1++;
209 while (u2[0] == u2[1]) u2++;
211 u1++; u2++;
213 if (! (*u1 && *u2)) {
214 while (*u1 == ' ') u1++;
215 while (*u2 == ' ') u2++;
217 ret = (int)(*u1 - *u2);
219 talloc_free(b1);
220 talloc_free(b2);
222 return ret;
226 canonicalise a attribute in DN format
228 static int ldb_canonicalise_dn(struct ldb_context *ldb, void *mem_ctx,
229 const struct ldb_val *in, struct ldb_val *out)
231 struct ldb_dn *dn;
232 int ret = -1;
234 out->length = 0;
235 out->data = NULL;
237 dn = ldb_dn_explode_casefold(ldb, mem_ctx, (char *)in->data);
238 if (dn == NULL) {
239 return -1;
242 out->data = (uint8_t *)ldb_dn_linearize(mem_ctx, dn);
243 if (out->data == NULL) {
244 goto done;
246 out->length = strlen((char *)out->data);
248 ret = 0;
250 done:
251 talloc_free(dn);
253 return ret;
257 compare two dns
259 static 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;
263 int ret;
265 dn1 = ldb_dn_explode_casefold(ldb, mem_ctx, (char *)v1->data);
266 if (dn1 == NULL) return -1;
268 dn2 = ldb_dn_explode_casefold(ldb, mem_ctx, (char *)v2->data);
269 if (dn2 == NULL) {
270 talloc_free(dn1);
271 return -1;
274 ret = ldb_dn_compare(ldb, dn1, dn2);
276 talloc_free(dn1);
277 talloc_free(dn2);
278 return ret;
282 compare two objectclasses, looking at subclasses
284 static int ldb_comparison_objectclass(struct ldb_context *ldb, void *mem_ctx,
285 const struct ldb_val *v1, const struct ldb_val *v2)
287 int ret, i;
288 const char **subclasses;
289 ret = ldb_comparison_fold(ldb, mem_ctx, v1, v2);
290 if (ret == 0) {
291 return 0;
293 subclasses = ldb_subclass_list(ldb, (char *)v1->data);
294 if (subclasses == NULL) {
295 return ret;
297 for (i=0;subclasses[i];i++) {
298 struct ldb_val vs;
299 vs.data = discard_const_p(uint8_t, subclasses[i]);
300 vs.length = strlen(subclasses[i]);
301 if (ldb_comparison_objectclass(ldb, mem_ctx, &vs, v2) == 0) {
302 return 0;
305 return ret;
309 compare two utc time values. 1 second resolution
311 static int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx,
312 const struct ldb_val *v1, const struct ldb_val *v2)
314 time_t t1, t2;
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 static 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) {
329 return -1;
331 out->length = strlen((char *)out->data);
332 return 0;
336 table of standard attribute handlers
338 static const struct ldb_attrib_handler ldb_standard_attribs[] = {
340 .attr = LDB_SYNTAX_INTEGER,
341 .flags = 0,
342 .ldif_read_fn = ldb_handler_copy,
343 .ldif_write_fn = ldb_handler_copy,
344 .canonicalise_fn = ldb_canonicalise_Integer,
345 .comparison_fn = ldb_comparison_Integer
348 .attr = LDB_SYNTAX_OCTET_STRING,
349 .flags = 0,
350 .ldif_read_fn = ldb_handler_copy,
351 .ldif_write_fn = ldb_handler_copy,
352 .canonicalise_fn = ldb_handler_copy,
353 .comparison_fn = ldb_comparison_binary
356 .attr = LDB_SYNTAX_DIRECTORY_STRING,
357 .flags = 0,
358 .ldif_read_fn = ldb_handler_copy,
359 .ldif_write_fn = ldb_handler_copy,
360 .canonicalise_fn = ldb_handler_fold,
361 .comparison_fn = ldb_comparison_fold
364 .attr = LDB_SYNTAX_DN,
365 .flags = 0,
366 .ldif_read_fn = ldb_handler_copy,
367 .ldif_write_fn = ldb_handler_copy,
368 .canonicalise_fn = ldb_canonicalise_dn,
369 .comparison_fn = ldb_comparison_dn
372 .attr = LDB_SYNTAX_OBJECTCLASS,
373 .flags = 0,
374 .ldif_read_fn = ldb_handler_copy,
375 .ldif_write_fn = ldb_handler_copy,
376 .canonicalise_fn = ldb_handler_fold,
377 .comparison_fn = ldb_comparison_objectclass
380 .attr = LDB_SYNTAX_UTC_TIME,
381 .flags = 0,
382 .ldif_read_fn = ldb_handler_copy,
383 .ldif_write_fn = ldb_handler_copy,
384 .canonicalise_fn = ldb_canonicalise_utctime,
385 .comparison_fn = ldb_comparison_utctime
391 return the attribute handlers for a given syntax name
393 const struct ldb_attrib_handler *ldb_attrib_handler_syntax(struct ldb_context *ldb,
394 const char *syntax)
396 int i;
397 unsigned num_handlers = sizeof(ldb_standard_attribs)/sizeof(ldb_standard_attribs[0]);
398 /* TODO: should be replaced with a binary search */
399 for (i=0;i<num_handlers;i++) {
400 if (strcmp(ldb_standard_attribs[i].attr, syntax) == 0) {
401 return &ldb_standard_attribs[i];
404 return NULL;