r12829: fix ldb headers, to not include '<...>' files in .c files
[kamenim/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 static int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx,
51                             const struct ldb_val *in, struct ldb_val *out)
52 {
53         uint8_t *s1, *s2;
54         out->data = talloc_size(mem_ctx, strlen((char *)in->data)+1);
55         if (out->data == NULL) {
56                 ldb_oom(ldb);
57                 return -1;
58         }
59         s1 = in->data;
60         s2 = out->data;
61         while (*s1 == ' ') s1++;
62         while (*s1) {
63                 *s2 = toupper(*s1);
64                 if (s1[0] == ' ') {
65                         while (s1[0] == s1[1]) s1++;
66                 }
67                 s2++; s1++;
68         }
69         *s2 = 0;
70         out->length = strlen((char *)out->data);
71         return 0;
72 }
73
74
75 /*
76   canonicalise a ldap Integer
77   rfc2252 specifies it should be in decimal form
78 */
79 static int ldb_canonicalise_Integer(struct ldb_context *ldb, void *mem_ctx,
80                                     const struct ldb_val *in, struct ldb_val *out)
81 {
82         char *end;
83         long long i = strtoll((char *)in->data, &end, 0);
84         if (*end != 0) {
85                 return -1;
86         }
87         out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%lld", i);
88         if (out->data == NULL) {
89                 return -1;
90         }
91         out->length = strlen((char *)out->data);
92         return 0;
93 }
94
95 /*
96   compare two Integers
97 */
98 static int ldb_comparison_Integer(struct ldb_context *ldb, void *mem_ctx,
99                                   const struct ldb_val *v1, const struct ldb_val *v2)
100 {
101         return strtoll((char *)v1->data, NULL, 0) - strtoll((char *)v2->data, NULL, 0);
102 }
103
104 /*
105   compare two binary blobs
106 */
107 int ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx,
108                           const struct ldb_val *v1, const struct ldb_val *v2)
109 {
110         if (v1->length != v2->length) {
111                 return v1->length - v2->length;
112         }
113         return memcmp(v1->data, v2->data, v1->length);
114 }
115
116 /*
117   compare two case insensitive strings, ignoring multiple whitespace
118   and leading and trailing whitespace
119   see rfc2252 section 8.1
120 */
121 static int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx,
122                                const struct ldb_val *v1, const struct ldb_val *v2)
123 {
124         const char *s1=(const char *)v1->data, *s2=(const char *)v2->data;
125         while (*s1 == ' ') s1++;
126         while (*s2 == ' ') s2++;
127         /* TODO: make utf8 safe, possibly with helper function from application */
128         while (*s1 && *s2) {
129                 if (toupper((unsigned char)*s1) != toupper((unsigned char)*s2))
130                         break;
131                 if (*s1 == ' ') {
132                         while (s1[0] == s1[1]) s1++;
133                         while (s2[0] == s2[1]) s2++;
134                 }
135                 s1++; s2++;
136         }
137         if (! (*s1 && *s2)) {
138                 /* remove trailing spaces only if one of the pointers
139                  * has reached the end of the strings otherwise we
140                  * can mistakenly match.
141                  * ex. "domain users" <-> "domainUpdates"
142                  */
143                 while (*s1 == ' ') s1++;
144                 while (*s2 == ' ') s2++;
145         }
146         return (int)(toupper(*s1)) - (int)(toupper(*s2));
147 }
148
149 /*
150   canonicalise a attribute in DN format
151 */
152 static int ldb_canonicalise_dn(struct ldb_context *ldb, void *mem_ctx,
153                                const struct ldb_val *in, struct ldb_val *out)
154 {
155         struct ldb_dn *dn;
156         int ret = -1;
157
158         out->length = 0;
159         out->data = NULL;
160
161         dn = ldb_dn_explode_casefold(ldb, (char *)in->data);
162         if (dn == NULL) {
163                 return -1;
164         }
165
166         out->data = (uint8_t *)ldb_dn_linearize(mem_ctx, dn);
167         if (out->data == NULL) {
168                 goto done;
169         }
170         out->length = strlen((char *)out->data);
171
172         ret = 0;
173
174 done:
175         talloc_free(dn);
176
177         return ret;
178 }
179
180 /*
181   compare two dns
182 */
183 static int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx,
184                              const struct ldb_val *v1, const struct ldb_val *v2)
185 {
186         struct ldb_dn *dn1 = NULL, *dn2 = NULL;
187         int ret;
188
189         dn1 = ldb_dn_explode_casefold(mem_ctx, (char *)v1->data);
190         if (dn1 == NULL) return -1;
191
192         dn2 = ldb_dn_explode_casefold(mem_ctx, (char *)v2->data);
193         if (dn2 == NULL) {
194                 talloc_free(dn1);
195                 return -1;
196         } 
197
198         ret = ldb_dn_compare(ldb, dn1, dn2);
199
200         talloc_free(dn1);
201         talloc_free(dn2);
202         return ret;
203 }
204
205 /*
206   compare two objectclasses, looking at subclasses
207 */
208 static int ldb_comparison_objectclass(struct ldb_context *ldb, void *mem_ctx,
209                                       const struct ldb_val *v1, const struct ldb_val *v2)
210 {
211         int ret, i;
212         const char **subclasses;
213         ret = ldb_comparison_fold(ldb, mem_ctx, v1, v2);
214         if (ret == 0) {
215                 return 0;
216         }
217         subclasses = ldb_subclass_list(ldb, (char *)v1->data);
218         if (subclasses == NULL) {
219                 return ret;
220         }
221         for (i=0;subclasses[i];i++) {
222                 struct ldb_val vs;
223                 vs.data = discard_const(subclasses[i]);
224                 vs.length = strlen(subclasses[i]);
225                 if (ldb_comparison_objectclass(ldb, mem_ctx, &vs, v2) == 0) {
226                         return 0;
227                 }
228         }
229         return ret;
230 }
231
232 /*
233   compare two utc time values. 1 second resolution
234 */
235 static int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx,
236                                   const struct ldb_val *v1, const struct ldb_val *v2)
237 {
238         time_t t1, t2;
239         t1 = ldb_string_to_time((char *)v1->data);
240         t2 = ldb_string_to_time((char *)v2->data);
241         return (int)t2 - (int)t1;
242 }
243
244 /*
245   canonicalise a utc time
246 */
247 static int ldb_canonicalise_utctime(struct ldb_context *ldb, void *mem_ctx,
248                                     const struct ldb_val *in, struct ldb_val *out)
249 {
250         time_t t = ldb_string_to_time((char *)in->data);
251         out->data = (uint8_t *)ldb_timestring(mem_ctx, t);
252         if (out->data == NULL) {
253                 return -1;
254         }
255         out->length = strlen((char *)out->data);
256         return 0;
257 }
258
259 /*
260   table of standard attribute handlers
261 */
262 static const struct ldb_attrib_handler ldb_standard_attribs[] = {
263         { 
264                 .attr            = LDB_SYNTAX_INTEGER,
265                 .flags           = 0,
266                 .ldif_read_fn    = ldb_handler_copy,
267                 .ldif_write_fn   = ldb_handler_copy,
268                 .canonicalise_fn = ldb_canonicalise_Integer,
269                 .comparison_fn   = ldb_comparison_Integer
270         },
271         { 
272                 .attr            = LDB_SYNTAX_OCTET_STRING,
273                 .flags           = 0,
274                 .ldif_read_fn    = ldb_handler_copy,
275                 .ldif_write_fn   = ldb_handler_copy,
276                 .canonicalise_fn = ldb_handler_copy,
277                 .comparison_fn   = ldb_comparison_binary
278         },
279         { 
280                 .attr            = LDB_SYNTAX_DIRECTORY_STRING,
281                 .flags           = 0,
282                 .ldif_read_fn    = ldb_handler_copy,
283                 .ldif_write_fn   = ldb_handler_copy,
284                 .canonicalise_fn = ldb_handler_fold,
285                 .comparison_fn   = ldb_comparison_fold
286         },
287         { 
288                 .attr            = LDB_SYNTAX_DN,
289                 .flags           = 0,
290                 .ldif_read_fn    = ldb_handler_copy,
291                 .ldif_write_fn   = ldb_handler_copy,
292                 .canonicalise_fn = ldb_canonicalise_dn,
293                 .comparison_fn   = ldb_comparison_dn
294         },
295         { 
296                 .attr            = LDB_SYNTAX_OBJECTCLASS,
297                 .flags           = 0,
298                 .ldif_read_fn    = ldb_handler_copy,
299                 .ldif_write_fn   = ldb_handler_copy,
300                 .canonicalise_fn = ldb_handler_fold,
301                 .comparison_fn   = ldb_comparison_objectclass
302         },
303         { 
304                 .attr            = LDB_SYNTAX_UTC_TIME,
305                 .flags           = 0,
306                 .ldif_read_fn    = ldb_handler_copy,
307                 .ldif_write_fn   = ldb_handler_copy,
308                 .canonicalise_fn = ldb_canonicalise_utctime,
309                 .comparison_fn   = ldb_comparison_utctime
310         }
311 };
312
313
314 /*
315   return the attribute handlers for a given syntax name
316 */
317 const struct ldb_attrib_handler *ldb_attrib_handler_syntax(struct ldb_context *ldb,
318                                                            const char *syntax)
319 {
320         int i;
321         unsigned num_handlers = sizeof(ldb_standard_attribs)/sizeof(ldb_standard_attribs[0]);
322         /* TODO: should be replaced with a binary search */
323         for (i=0;i<num_handlers;i++) {
324                 if (strcmp(ldb_standard_attribs[i].attr, syntax) == 0) {
325                         return &ldb_standard_attribs[i];
326                 }
327         }
328         return NULL;
329 }
330