r13335: Fix the build and add an utf8 safe ldb_hadler_fold function
[jra/samba/.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 2 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, write to the Free Software
22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 */
24 /*
25   attribute handlers for well known attribute types, selected by syntax OID
26   see rfc2252
27 */
28
29 #include "includes.h"
30 #include "ldb/include/includes.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 static 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 (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 static 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 static 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 static int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx,
150                                const struct ldb_val *v1, const struct ldb_val *v2)
151 {
152         const char *s1=(const char *)v1->data, *s2=(const char *)v2->data;
153         while (*s1 == ' ') s1++;
154         while (*s2 == ' ') s2++;
155         /* TODO: make utf8 safe, possibly with helper function from application */
156         while (*s1 && *s2) {
157                 if (toupper((unsigned char)*s1) != toupper((unsigned char)*s2))
158                         break;
159                 if (*s1 == ' ') {
160                         while (s1[0] == s1[1]) s1++;
161                         while (s2[0] == s2[1]) s2++;
162                 }
163                 s1++; s2++;
164         }
165         if (! (*s1 && *s2)) {
166                 /* remove trailing spaces only if one of the pointers
167                  * has reached the end of the strings otherwise we
168                  * can mistakenly match.
169                  * ex. "domain users" <-> "domainUpdates"
170                  */
171                 while (*s1 == ' ') s1++;
172                 while (*s2 == ' ') s2++;
173         }
174         return (int)(toupper(*s1)) - (int)(toupper(*s2));
175 }
176
177 /*
178   canonicalise a attribute in DN format
179 */
180 static int ldb_canonicalise_dn(struct ldb_context *ldb, void *mem_ctx,
181                                const struct ldb_val *in, struct ldb_val *out)
182 {
183         struct ldb_dn *dn;
184         int ret = -1;
185
186         out->length = 0;
187         out->data = NULL;
188
189         dn = ldb_dn_explode_casefold(ldb, (char *)in->data);
190         if (dn == NULL) {
191                 return -1;
192         }
193
194         out->data = (uint8_t *)ldb_dn_linearize(mem_ctx, dn);
195         if (out->data == NULL) {
196                 goto done;
197         }
198         out->length = strlen((char *)out->data);
199
200         ret = 0;
201
202 done:
203         talloc_free(dn);
204
205         return ret;
206 }
207
208 /*
209   compare two dns
210 */
211 static int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx,
212                              const struct ldb_val *v1, const struct ldb_val *v2)
213 {
214         struct ldb_dn *dn1 = NULL, *dn2 = NULL;
215         int ret;
216
217         dn1 = ldb_dn_explode_casefold(mem_ctx, (char *)v1->data);
218         if (dn1 == NULL) return -1;
219
220         dn2 = ldb_dn_explode_casefold(mem_ctx, (char *)v2->data);
221         if (dn2 == NULL) {
222                 talloc_free(dn1);
223                 return -1;
224         } 
225
226         ret = ldb_dn_compare(ldb, dn1, dn2);
227
228         talloc_free(dn1);
229         talloc_free(dn2);
230         return ret;
231 }
232
233 /*
234   compare two objectclasses, looking at subclasses
235 */
236 static int ldb_comparison_objectclass(struct ldb_context *ldb, void *mem_ctx,
237                                       const struct ldb_val *v1, const struct ldb_val *v2)
238 {
239         int ret, i;
240         const char **subclasses;
241         ret = ldb_comparison_fold(ldb, mem_ctx, v1, v2);
242         if (ret == 0) {
243                 return 0;
244         }
245         subclasses = ldb_subclass_list(ldb, (char *)v1->data);
246         if (subclasses == NULL) {
247                 return ret;
248         }
249         for (i=0;subclasses[i];i++) {
250                 struct ldb_val vs;
251                 vs.data = discard_const(subclasses[i]);
252                 vs.length = strlen(subclasses[i]);
253                 if (ldb_comparison_objectclass(ldb, mem_ctx, &vs, v2) == 0) {
254                         return 0;
255                 }
256         }
257         return ret;
258 }
259
260 /*
261   compare two utc time values. 1 second resolution
262 */
263 static int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx,
264                                   const struct ldb_val *v1, const struct ldb_val *v2)
265 {
266         time_t t1, t2;
267         t1 = ldb_string_to_time((char *)v1->data);
268         t2 = ldb_string_to_time((char *)v2->data);
269         return (int)t2 - (int)t1;
270 }
271
272 /*
273   canonicalise a utc time
274 */
275 static int ldb_canonicalise_utctime(struct ldb_context *ldb, void *mem_ctx,
276                                     const struct ldb_val *in, struct ldb_val *out)
277 {
278         time_t t = ldb_string_to_time((char *)in->data);
279         out->data = (uint8_t *)ldb_timestring(mem_ctx, t);
280         if (out->data == NULL) {
281                 return -1;
282         }
283         out->length = strlen((char *)out->data);
284         return 0;
285 }
286
287 /*
288   table of standard attribute handlers
289 */
290 static const struct ldb_attrib_handler ldb_standard_attribs[] = {
291         { 
292                 .attr            = LDB_SYNTAX_INTEGER,
293                 .flags           = 0,
294                 .ldif_read_fn    = ldb_handler_copy,
295                 .ldif_write_fn   = ldb_handler_copy,
296                 .canonicalise_fn = ldb_canonicalise_Integer,
297                 .comparison_fn   = ldb_comparison_Integer
298         },
299         { 
300                 .attr            = LDB_SYNTAX_OCTET_STRING,
301                 .flags           = 0,
302                 .ldif_read_fn    = ldb_handler_copy,
303                 .ldif_write_fn   = ldb_handler_copy,
304                 .canonicalise_fn = ldb_handler_copy,
305                 .comparison_fn   = ldb_comparison_binary
306         },
307         { 
308                 .attr            = LDB_SYNTAX_DIRECTORY_STRING,
309                 .flags           = 0,
310                 .ldif_read_fn    = ldb_handler_copy,
311                 .ldif_write_fn   = ldb_handler_copy,
312                 .canonicalise_fn = ldb_handler_fold,
313                 .comparison_fn   = ldb_comparison_fold
314         },
315         { 
316                 .attr            = LDB_SYNTAX_DN,
317                 .flags           = 0,
318                 .ldif_read_fn    = ldb_handler_copy,
319                 .ldif_write_fn   = ldb_handler_copy,
320                 .canonicalise_fn = ldb_canonicalise_dn,
321                 .comparison_fn   = ldb_comparison_dn
322         },
323         { 
324                 .attr            = LDB_SYNTAX_OBJECTCLASS,
325                 .flags           = 0,
326                 .ldif_read_fn    = ldb_handler_copy,
327                 .ldif_write_fn   = ldb_handler_copy,
328                 .canonicalise_fn = ldb_handler_fold,
329                 .comparison_fn   = ldb_comparison_objectclass
330         },
331         { 
332                 .attr            = LDB_SYNTAX_UTC_TIME,
333                 .flags           = 0,
334                 .ldif_read_fn    = ldb_handler_copy,
335                 .ldif_write_fn   = ldb_handler_copy,
336                 .canonicalise_fn = ldb_canonicalise_utctime,
337                 .comparison_fn   = ldb_comparison_utctime
338         }
339 };
340
341
342 /*
343   return the attribute handlers for a given syntax name
344 */
345 const struct ldb_attrib_handler *ldb_attrib_handler_syntax(struct ldb_context *ldb,
346                                                            const char *syntax)
347 {
348         int i;
349         unsigned num_handlers = sizeof(ldb_standard_attribs)/sizeof(ldb_standard_attribs[0]);
350         /* TODO: should be replaced with a binary search */
351         for (i=0;i<num_handlers;i++) {
352                 if (strcmp(ldb_standard_attribs[i].attr, syntax) == 0) {
353                         return &ldb_standard_attribs[i];
354                 }
355         }
356         return NULL;
357 }
358