r9766: Prevent erroneous OOM message
[sfrench/samba-autobuild/.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/ldb.h"
31 #include "ldb/include/ldb_private.h"
32 #include <ctype.h>
33
34 /*
35   default handler that just copies a ldb_val.
36 */
37 int ldb_handler_copy(struct ldb_context *ldb, void *mem_ctx,
38                      const struct ldb_val *in, struct ldb_val *out)
39 {
40         *out = ldb_val_dup(mem_ctx, in);
41         if (in->length > 0 && out->data == NULL) {
42                 ldb_oom(ldb);
43                 return -1;
44         }
45         return 0;
46 }
47
48 /*
49   a case folding copy handler, removing leading and trailing spaces and
50   multiple internal spaces
51 */
52 static int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx,
53                             const struct ldb_val *in, struct ldb_val *out)
54 {
55         uint8_t *s1, *s2;
56         out->data = talloc_size(mem_ctx, strlen(in->data)+1);
57         if (out->data == NULL) {
58                 ldb_oom(ldb);
59                 return -1;
60         }
61         s1 = in->data;
62         s2 = out->data;
63         while (*s1 == ' ') s1++;
64         while (*s1) {
65                 *s2 = toupper(*s1);
66                 if (s1[0] == ' ') {
67                         while (s1[0] == s1[1]) s1++;
68                 }
69                 s2++; s1++;
70         }
71         *s2 = 0;
72         out->length = strlen(out->data);
73         return 0;
74 }
75
76
77 /*
78   canonicalise a ldap Integer
79   rfc2252 specifies it should be in decimal form
80 */
81 static int ldb_canonicalise_Integer(struct ldb_context *ldb, void *mem_ctx,
82                                     const struct ldb_val *in, struct ldb_val *out)
83 {
84         char *end;
85         long long i = strtoll(in->data, &end, 0);
86         if (*end != 0) {
87                 return -1;
88         }
89         out->data = talloc_asprintf(mem_ctx, "%lld", i);
90         if (out->data == NULL) {
91                 return -1;
92         }
93         out->length = strlen(out->data);
94         return 0;
95 }
96
97 /*
98   compare two Integers
99 */
100 static int ldb_comparison_Integer(struct ldb_context *ldb, void *mem_ctx,
101                                   const struct ldb_val *v1, const struct ldb_val *v2)
102 {
103         return strtoll(v1->data, NULL, 0) - strtoll(v2->data, NULL, 0);
104 }
105
106 /*
107   compare two binary blobs
108 */
109 int ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx,
110                           const struct ldb_val *v1, const struct ldb_val *v2)
111 {
112         if (v1->length != v2->length) {
113                 return v1->length - v2->length;
114         }
115         return memcmp(v1->data, v2->data, v1->length);
116 }
117
118 /*
119   compare two case insensitive strings, ignoring multiple whitespace
120   and leading and trailing whitespace
121   see rfc2252 section 8.1
122 */
123 static int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx,
124                                const struct ldb_val *v1, const struct ldb_val *v2)
125 {
126         const char *s1=v1->data, *s2=v2->data;
127         while (*s1 == ' ') s1++;
128         while (*s2 == ' ') s2++;
129         /* TODO: make utf8 safe, possibly with helper function from application */
130         while (*s1 && *s2) {
131                 if (toupper((unsigned char)*s1) != toupper((unsigned char)*s2))
132                         break;
133                 if (*s1 == ' ') {
134                         while (s1[0] == s1[1]) s1++;
135                         while (s2[0] == s2[1]) s2++;
136                 }
137                 s1++; s2++;
138         }
139         while (*s1 == ' ') s1++;
140         while (*s2 == ' ') s2++;
141         return (int)(*s1) - (int)(*s2);
142 }
143
144 /*
145   canonicalise a attribute in DN format
146 */
147 static int ldb_canonicalise_dn(struct ldb_context *ldb, void *mem_ctx,
148                                const struct ldb_val *in, struct ldb_val *out)
149 {
150         struct ldb_dn *dn;
151         int ret = -1;
152
153         out->length = 0;
154         out->data = NULL;
155
156         dn = ldb_dn_explode_casefold(ldb, in->data);
157         if (dn == NULL) {
158                 return -1;
159         }
160
161         out->data = ldb_dn_linearize(mem_ctx, dn);
162         if (out->data == NULL) {
163                 goto done;
164         }
165         out->length = strlen(out->data);
166
167         ret = 0;
168
169 done:
170         talloc_free(dn);
171
172         return ret;
173 }
174
175 /*
176   compare two dns
177 */
178 static int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx,
179                              const struct ldb_val *v1, const struct ldb_val *v2)
180 {
181         struct ldb_dn *dn1 = NULL, *dn2 = NULL;
182         int ret;
183
184         dn1 = ldb_dn_explode_casefold(mem_ctx, v1->data);
185         if (dn1 == NULL) return -1;
186
187         dn2 = ldb_dn_explode_casefold(mem_ctx, v2->data);
188         if (dn2 == NULL) {
189                 talloc_free(dn1);
190                 return -1;
191         } 
192
193         ret = ldb_dn_compare(ldb, dn1, dn2);
194
195         talloc_free(dn1);
196         talloc_free(dn2);
197         return ret;
198 }
199
200 /*
201   compare two objectclasses, looking at subclasses
202 */
203 static int ldb_comparison_objectclass(struct ldb_context *ldb, void *mem_ctx,
204                                       const struct ldb_val *v1, const struct ldb_val *v2)
205 {
206         int ret, i;
207         const char **subclasses;
208         ret = ldb_comparison_fold(ldb, mem_ctx, v1, v2);
209         if (ret == 0) {
210                 return 0;
211         }
212         subclasses = ldb_subclass_list(ldb, v1->data);
213         if (subclasses == NULL) {
214                 return ret;
215         }
216         for (i=0;subclasses[i];i++) {
217                 struct ldb_val vs;
218                 vs.data = discard_const(subclasses[i]);
219                 vs.length = strlen(subclasses[i]);
220                 if (ldb_comparison_objectclass(ldb, mem_ctx, &vs, v2) == 0) {
221                         return 0;
222                 }
223         }
224         return ret;
225 }
226
227 /*
228   table of standard attribute handlers
229 */
230 static const struct ldb_attrib_handler ldb_standard_attribs[] = {
231         { 
232                 .attr            = LDB_SYNTAX_INTEGER,
233                 .flags           = 0,
234                 .ldif_read_fn    = ldb_handler_copy,
235                 .ldif_write_fn   = ldb_handler_copy,
236                 .canonicalise_fn = ldb_canonicalise_Integer,
237                 .comparison_fn   = ldb_comparison_Integer
238         },
239         { 
240                 .attr            = LDB_SYNTAX_OCTET_STRING,
241                 .flags           = 0,
242                 .ldif_read_fn    = ldb_handler_copy,
243                 .ldif_write_fn   = ldb_handler_copy,
244                 .canonicalise_fn = ldb_handler_copy,
245                 .comparison_fn   = ldb_comparison_binary
246         },
247         { 
248                 .attr            = LDB_SYNTAX_DIRECTORY_STRING,
249                 .flags           = 0,
250                 .ldif_read_fn    = ldb_handler_copy,
251                 .ldif_write_fn   = ldb_handler_copy,
252                 .canonicalise_fn = ldb_handler_fold,
253                 .comparison_fn   = ldb_comparison_fold
254         },
255         { 
256                 .attr            = LDB_SYNTAX_DN,
257                 .flags           = 0,
258                 .ldif_read_fn    = ldb_handler_copy,
259                 .ldif_write_fn   = ldb_handler_copy,
260                 .canonicalise_fn = ldb_canonicalise_dn,
261                 .comparison_fn   = ldb_comparison_dn
262         },
263         { 
264                 .attr            = LDB_SYNTAX_OBJECTCLASS,
265                 .flags           = 0,
266                 .ldif_read_fn    = ldb_handler_copy,
267                 .ldif_write_fn   = ldb_handler_copy,
268                 .canonicalise_fn = ldb_handler_fold,
269                 .comparison_fn   = ldb_comparison_objectclass
270         }
271 };
272
273
274 /*
275   return the attribute handlers for a given syntax name
276 */
277 const struct ldb_attrib_handler *ldb_attrib_handler_syntax(struct ldb_context *ldb,
278                                                            const char *syntax)
279 {
280         int i;
281         unsigned num_handlers = sizeof(ldb_standard_attribs)/sizeof(ldb_standard_attribs[0]);
282         /* TODO: should be replaced with a binary search */
283         for (i=0;i<num_handlers;i++) {
284                 if (strcmp(ldb_standard_attribs[i].attr, syntax) == 0) {
285                         return &ldb_standard_attribs[i];
286                 }
287         }
288         return NULL;
289 }
290