/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- ldb_handler_copy
- ldb_handler_fold
- ldb_canonicalise_Integer
- ldb_comparison_Integer
- ldb_comparison_binary
- ldb_comparison_fold
- ldb_canonicalise_dn
- ldb_comparison_dn
- ldb_comparison_objectclass
- ldb_comparison_utctime
- ldb_canonicalise_utctime
- ldb_attrib_handler_syntax
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 "includes.h"
29 #include "ldb/include/includes.h"
30 #include "system/locale.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,
/* [<][>][^][v][top][bottom][index][help] */
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,
/* [<][>][^][v][top][bottom][index][help] */
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 static int ldb_canonicalise_Integer(struct ldb_context *ldb, void *mem_ctx,
/* [<][>][^][v][top][bottom][index][help] */
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,
/* [<][>][^][v][top][bottom][index][help] */
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,
/* [<][>][^][v][top][bottom][index][help] */
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 static int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx,
/* [<][>][^][v][top][bottom][index][help] */
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 static int ldb_canonicalise_dn(struct ldb_context *ldb, void *mem_ctx,
/* [<][>][^][v][top][bottom][index][help] */
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_explode_casefold(ldb, mem_ctx, (char *)in->data);
237 if (dn == NULL) {
238 return -1;
239 }
240
241 out->data = (uint8_t *)ldb_dn_linearize(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 static int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx,
/* [<][>][^][v][top][bottom][index][help] */
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_explode_casefold(ldb, mem_ctx, (char *)v1->data);
265 if (dn1 == NULL) return -1;
266
267 dn2 = ldb_dn_explode_casefold(ldb, mem_ctx, (char *)v2->data);
268 if (dn2 == NULL) {
269 talloc_free(dn1);
270 return -1;
271 }
272
273 ret = ldb_dn_compare(ldb, dn1, dn2);
274
275 talloc_free(dn1);
276 talloc_free(dn2);
277 return ret;
278 }
279
280 /*
281 compare two objectclasses, looking at subclasses
282 */
283 static int ldb_comparison_objectclass(struct ldb_context *ldb, void *mem_ctx,
/* [<][>][^][v][top][bottom][index][help] */
284 const struct ldb_val *v1, const struct ldb_val *v2)
285 {
286 int ret, i;
287 const char **subclasses;
288 ret = ldb_comparison_fold(ldb, mem_ctx, v1, v2);
289 if (ret == 0) {
290 return 0;
291 }
292 subclasses = ldb_subclass_list(ldb, (char *)v1->data);
293 if (subclasses == NULL) {
294 return ret;
295 }
296 for (i=0;subclasses[i];i++) {
297 struct ldb_val vs;
298 vs.data = discard_const_p(uint8_t, subclasses[i]);
299 vs.length = strlen(subclasses[i]);
300 if (ldb_comparison_objectclass(ldb, mem_ctx, &vs, v2) == 0) {
301 return 0;
302 }
303 }
304 return ret;
305 }
306
307 /*
308 compare two utc time values. 1 second resolution
309 */
310 static int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx,
/* [<][>][^][v][top][bottom][index][help] */
311 const struct ldb_val *v1, const struct ldb_val *v2)
312 {
313 time_t t1, t2;
314 t1 = ldb_string_to_time((char *)v1->data);
315 t2 = ldb_string_to_time((char *)v2->data);
316 return (int)t2 - (int)t1;
317 }
318
319 /*
320 canonicalise a utc time
321 */
322 static int ldb_canonicalise_utctime(struct ldb_context *ldb, void *mem_ctx,
/* [<][>][^][v][top][bottom][index][help] */
323 const struct ldb_val *in, struct ldb_val *out)
324 {
325 time_t t = ldb_string_to_time((char *)in->data);
326 out->data = (uint8_t *)ldb_timestring(mem_ctx, t);
327 if (out->data == NULL) {
328 return -1;
329 }
330 out->length = strlen((char *)out->data);
331 return 0;
332 }
333
334 /*
335 table of standard attribute handlers
336 */
337 static const struct ldb_attrib_handler ldb_standard_attribs[] = {
338 {
339 .attr = LDB_SYNTAX_INTEGER,
340 .flags = 0,
341 .ldif_read_fn = ldb_handler_copy,
342 .ldif_write_fn = ldb_handler_copy,
343 .canonicalise_fn = ldb_canonicalise_Integer,
344 .comparison_fn = ldb_comparison_Integer
345 },
346 {
347 .attr = LDB_SYNTAX_OCTET_STRING,
348 .flags = 0,
349 .ldif_read_fn = ldb_handler_copy,
350 .ldif_write_fn = ldb_handler_copy,
351 .canonicalise_fn = ldb_handler_copy,
352 .comparison_fn = ldb_comparison_binary
353 },
354 {
355 .attr = LDB_SYNTAX_DIRECTORY_STRING,
356 .flags = 0,
357 .ldif_read_fn = ldb_handler_copy,
358 .ldif_write_fn = ldb_handler_copy,
359 .canonicalise_fn = ldb_handler_fold,
360 .comparison_fn = ldb_comparison_fold
361 },
362 {
363 .attr = LDB_SYNTAX_DN,
364 .flags = 0,
365 .ldif_read_fn = ldb_handler_copy,
366 .ldif_write_fn = ldb_handler_copy,
367 .canonicalise_fn = ldb_canonicalise_dn,
368 .comparison_fn = ldb_comparison_dn
369 },
370 {
371 .attr = LDB_SYNTAX_OBJECTCLASS,
372 .flags = 0,
373 .ldif_read_fn = ldb_handler_copy,
374 .ldif_write_fn = ldb_handler_copy,
375 .canonicalise_fn = ldb_handler_fold,
376 .comparison_fn = ldb_comparison_objectclass
377 },
378 {
379 .attr = LDB_SYNTAX_UTC_TIME,
380 .flags = 0,
381 .ldif_read_fn = ldb_handler_copy,
382 .ldif_write_fn = ldb_handler_copy,
383 .canonicalise_fn = ldb_canonicalise_utctime,
384 .comparison_fn = ldb_comparison_utctime
385 }
386 };
387
388
389 /*
390 return the attribute handlers for a given syntax name
391 */
392 const struct ldb_attrib_handler *ldb_attrib_handler_syntax(struct ldb_context *ldb,
/* [<][>][^][v][top][bottom][index][help] */
393 const char *syntax)
394 {
395 int i;
396 unsigned num_handlers = sizeof(ldb_standard_attribs)/sizeof(ldb_standard_attribs[0]);
397 /* TODO: should be replaced with a binary search */
398 for (i=0;i<num_handlers;i++) {
399 if (strcmp(ldb_standard_attribs[i].attr, syntax) == 0) {
400 return &ldb_standard_attribs[i];
401 }
402 }
403 return NULL;
404 }
405