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