]> git.samba.org - metze/samba/wip.git/blob - source4/lib/ldb/common/attrib_handlers.c
Merge commit 'release-4-0-0alpha1' into v4-0-test
[metze/samba/wip.git] / source4 / lib / ldb / common / attrib_handlers.c
1 /* 
2    ldb database library
3
4    Copyright (C) Andrew Tridgell  2005
5
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
9    
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.
14
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.
19
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/>.
22 */
23 /*
24   attribute handlers for well known attribute types, selected by syntax OID
25   see rfc2252
26 */
27
28 #include "ldb_includes.h"
29 #include "system/locale.h"
30 #include "ldb_handlers.h"
31
32 /*
33   default handler that just copies a ldb_val.
34 */
35 int ldb_handler_copy(struct ldb_context *ldb, void *mem_ctx,
36                      const struct ldb_val *in, struct ldb_val *out)
37 {
38         *out = ldb_val_dup(mem_ctx, in);
39         if (in->length > 0 && out->data == NULL) {
40                 ldb_oom(ldb);
41                 return -1;
42         }
43         return 0;
44 }
45
46 /*
47   a case folding copy handler, removing leading and trailing spaces and
48   multiple internal spaces
49
50   We exploit the fact that utf8 never uses the space octet except for
51   the space itself
52 */
53 int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx,
54                             const struct ldb_val *in, struct ldb_val *out)
55 {
56         char *s, *t;
57         int l;
58         if (!in || !out || !(in->data)) {
59                 return -1;
60         }
61
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);
65                 return -1;
66         }
67
68         s = (char *)(out->data);
69         
70         /* remove trailing spaces if any */
71         l = strlen(s);
72         while (l > 0 && s[l - 1] == ' ') l--;
73         s[l] = '\0';
74         
75         /* remove leading spaces if any */
76         if (*s == ' ') {
77                 for (t = s; *s == ' '; s++) ;
78
79                 /* remove leading spaces by moving down the string */
80                 memmove(t, s, l);
81
82                 s = t;
83         }
84
85         /* check middle spaces */
86         while ((t = strchr(s, ' ')) != NULL) {
87                 for (s = t; *s == ' '; s++) ;
88
89                 if ((s - t) > 1) {
90                         l = strlen(s);
91
92                         /* remove all spaces but one by moving down the string */
93                         memmove(t + 1, s, l);
94                 }
95         }
96
97         out->length = strlen((char *)out->data);
98         return 0;
99 }
100
101
102
103 /*
104   canonicalise a ldap Integer
105   rfc2252 specifies it should be in decimal form
106 */
107 int ldb_canonicalise_Integer(struct ldb_context *ldb, void *mem_ctx,
108                                     const struct ldb_val *in, struct ldb_val *out)
109 {
110         char *end;
111         long long i = strtoll((char *)in->data, &end, 0);
112         if (*end != 0) {
113                 return -1;
114         }
115         out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%lld", i);
116         if (out->data == NULL) {
117                 return -1;
118         }
119         out->length = strlen((char *)out->data);
120         return 0;
121 }
122
123 /*
124   compare two Integers
125 */
126 int ldb_comparison_Integer(struct ldb_context *ldb, void *mem_ctx,
127                                   const struct ldb_val *v1, const struct ldb_val *v2)
128 {
129         return strtoll((char *)v1->data, NULL, 0) - strtoll((char *)v2->data, NULL, 0);
130 }
131
132 /*
133   compare two binary blobs
134 */
135 int ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx,
136                           const struct ldb_val *v1, const struct ldb_val *v2)
137 {
138         if (v1->length != v2->length) {
139                 return v1->length - v2->length;
140         }
141         return memcmp(v1->data, v2->data, v1->length);
142 }
143
144 /*
145   compare two case insensitive strings, ignoring multiple whitespaces
146   and leading and trailing whitespaces
147   see rfc2252 section 8.1
148         
149   try to optimize for the ascii case,
150   but if we find out an utf8 codepoint revert to slower but correct function
151 */
152 int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx,
153                                const struct ldb_val *v1, const struct ldb_val *v2)
154 {
155         const char *s1=(const char *)v1->data, *s2=(const char *)v2->data;
156         const char *u1, *u2;
157         char *b1, *b2;
158         int ret;
159         while (*s1 == ' ') s1++;
160         while (*s2 == ' ') s2++;
161         /* TODO: make utf8 safe, possibly with helper function from application */
162         while (*s1 && *s2) {
163                 /* the first 127 (0x7F) chars are ascii and utf8 guarantes they
164                  * never appear in multibyte sequences */
165                 if (((unsigned char)s1[0]) & 0x80) goto utf8str;
166                 if (((unsigned char)s2[0]) & 0x80) goto utf8str;
167                 if (toupper((unsigned char)*s1) != toupper((unsigned char)*s2))
168                         break;
169                 if (*s1 == ' ') {
170                         while (s1[0] == s1[1]) s1++;
171                         while (s2[0] == s2[1]) s2++;
172                 }
173                 s1++; s2++;
174         }
175         if (! (*s1 && *s2)) {
176                 /* check for trailing spaces only if one of the pointers
177                  * has reached the end of the strings otherwise we
178                  * can mistakenly match.
179                  * ex. "domain users" <-> "domainUpdates"
180                  */
181                 while (*s1 == ' ') s1++;
182                 while (*s2 == ' ') s2++;
183         }
184         return (int)(toupper(*s1)) - (int)(toupper(*s2));
185
186 utf8str:
187         /* no need to recheck from the start, just from the first utf8 char found */
188         b1 = ldb_casefold(ldb, mem_ctx, s1);
189         b2 = ldb_casefold(ldb, mem_ctx, s2);
190
191         if (b1 && b2) {
192                 /* Both strings converted correctly */
193
194                 u1 = b1;
195                 u2 = b2;
196         } else {
197                 /* One of the strings was not UTF8, so we have no options but to do a binary compare */
198
199                 u1 = s1;
200                 u2 = s2;
201         }
202
203         while (*u1 & *u2) {
204                 if (*u1 != *u2)
205                         break;
206                 if (*u1 == ' ') {
207                         while (u1[0] == u1[1]) u1++;
208                         while (u2[0] == u2[1]) u2++;
209                 }
210                 u1++; u2++;
211         }
212         if (! (*u1 && *u2)) {
213                 while (*u1 == ' ') u1++;
214                 while (*u2 == ' ') u2++;
215         }
216         ret = (int)(*u1 - *u2);
217
218         talloc_free(b1);
219         talloc_free(b2);
220         
221         return ret;
222 }
223
224 /*
225   canonicalise a attribute in DN format
226 */
227 int ldb_canonicalise_dn(struct ldb_context *ldb, void *mem_ctx,
228                                const struct ldb_val *in, struct ldb_val *out)
229 {
230         struct ldb_dn *dn;
231         int ret = -1;
232
233         out->length = 0;
234         out->data = NULL;
235
236         dn = ldb_dn_new(ldb, mem_ctx, (char *)in->data);
237         if ( ! ldb_dn_validate(dn)) {
238                 return LDB_ERR_INVALID_DN_SYNTAX;
239         }
240
241         out->data = (uint8_t *)ldb_dn_alloc_casefold(mem_ctx, dn);
242         if (out->data == NULL) {
243                 goto done;
244         }
245         out->length = strlen((char *)out->data);
246
247         ret = 0;
248
249 done:
250         talloc_free(dn);
251
252         return ret;
253 }
254
255 /*
256   compare two dns
257 */
258 int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx,
259                              const struct ldb_val *v1, const struct ldb_val *v2)
260 {
261         struct ldb_dn *dn1 = NULL, *dn2 = NULL;
262         int ret;
263
264         dn1 = ldb_dn_new(ldb, mem_ctx, (char *)v1->data);
265         if ( ! ldb_dn_validate(dn1)) return -1;
266
267         dn2 = ldb_dn_new(ldb, mem_ctx, (char *)v2->data);
268         if ( ! ldb_dn_validate(dn2)) {
269                 talloc_free(dn1);
270                 return -1;
271         } 
272
273         ret = ldb_dn_compare(dn1, dn2);
274
275         talloc_free(dn1);
276         talloc_free(dn2);
277         return ret;
278 }
279
280 /*
281   compare two utc time values. 1 second resolution
282 */
283 int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx,
284                                   const struct ldb_val *v1, const struct ldb_val *v2)
285 {
286         time_t t1, t2;
287         t1 = ldb_string_to_time((char *)v1->data);
288         t2 = ldb_string_to_time((char *)v2->data);
289         return (int)t2 - (int)t1;
290 }
291
292 /*
293   canonicalise a utc time
294 */
295 int ldb_canonicalise_utctime(struct ldb_context *ldb, void *mem_ctx,
296                                     const struct ldb_val *in, struct ldb_val *out)
297 {
298         time_t t = ldb_string_to_time((char *)in->data);
299         out->data = (uint8_t *)ldb_timestring(mem_ctx, t);
300         if (out->data == NULL) {
301                 return -1;
302         }
303         out->length = strlen((char *)out->data);
304         return 0;
305 }
306
307 /*
308   table of standard attribute handlers
309 */
310 static const struct ldb_schema_syntax ldb_standard_syntaxes[] = {
311         { 
312                 .name            = LDB_SYNTAX_INTEGER,
313                 .ldif_read_fn    = ldb_handler_copy,
314                 .ldif_write_fn   = ldb_handler_copy,
315                 .canonicalise_fn = ldb_canonicalise_Integer,
316                 .comparison_fn   = ldb_comparison_Integer
317         },
318         { 
319                 .name            = LDB_SYNTAX_OCTET_STRING,
320                 .ldif_read_fn    = ldb_handler_copy,
321                 .ldif_write_fn   = ldb_handler_copy,
322                 .canonicalise_fn = ldb_handler_copy,
323                 .comparison_fn   = ldb_comparison_binary
324         },
325         { 
326                 .name            = LDB_SYNTAX_DIRECTORY_STRING,
327                 .ldif_read_fn    = ldb_handler_copy,
328                 .ldif_write_fn   = ldb_handler_copy,
329                 .canonicalise_fn = ldb_handler_fold,
330                 .comparison_fn   = ldb_comparison_fold
331         },
332         { 
333                 .name            = LDB_SYNTAX_DN,
334                 .ldif_read_fn    = ldb_handler_copy,
335                 .ldif_write_fn   = ldb_handler_copy,
336                 .canonicalise_fn = ldb_canonicalise_dn,
337                 .comparison_fn   = ldb_comparison_dn
338         },
339         { 
340                 .name            = LDB_SYNTAX_OBJECTCLASS,
341                 .ldif_read_fn    = ldb_handler_copy,
342                 .ldif_write_fn   = ldb_handler_copy,
343                 .canonicalise_fn = ldb_handler_fold,
344                 .comparison_fn   = ldb_comparison_fold
345         },
346         { 
347                 .name            = LDB_SYNTAX_UTC_TIME,
348                 .ldif_read_fn    = ldb_handler_copy,
349                 .ldif_write_fn   = ldb_handler_copy,
350                 .canonicalise_fn = ldb_canonicalise_utctime,
351                 .comparison_fn   = ldb_comparison_utctime
352         }
353 };
354
355
356 /*
357   return the attribute handlers for a given syntax name
358 */
359 const struct ldb_schema_syntax *ldb_standard_syntax_by_name(struct ldb_context *ldb,
360                                                             const char *syntax)
361 {
362         int i;
363         unsigned num_handlers = sizeof(ldb_standard_syntaxes)/sizeof(ldb_standard_syntaxes[0]);
364         /* TODO: should be replaced with a binary search */
365         for (i=0;i<num_handlers;i++) {
366                 if (strcmp(ldb_standard_syntaxes[i].name, syntax) == 0) {
367                         return &ldb_standard_syntaxes[i];
368                 }
369         }
370         return NULL;
371 }