Use ldb_dn_from_ldb_val to avoid possible over-run of the value.
[Samba/vfs_proxy.git] / source4 / lib / ldb / common / attrib_handlers.c
blob5ec86b5b8fbe7f09fd078e7efb62e07149f39cef
1 /*
2 ldb database library
4 Copyright (C) Andrew Tridgell 2005
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
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.
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.
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/>.
24 attribute handlers for well known attribute types, selected by syntax OID
25 see rfc2252
28 #include "ldb_includes.h"
29 #include "system/locale.h"
30 #include "ldb_handlers.h"
33 default handler that just copies a ldb_val.
35 int ldb_handler_copy(struct ldb_context *ldb, void *mem_ctx,
36 const struct ldb_val *in, struct ldb_val *out)
38 *out = ldb_val_dup(mem_ctx, in);
39 if (in->length > 0 && out->data == NULL) {
40 ldb_oom(ldb);
41 return -1;
43 return 0;
47 a case folding copy handler, removing leading and trailing spaces and
48 multiple internal spaces
50 We exploit the fact that utf8 never uses the space octet except for
51 the space itself
53 int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx,
54 const struct ldb_val *in, struct ldb_val *out)
56 char *s, *t;
57 int l;
59 if (!in || !out || !(in->data)) {
60 return -1;
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;
69 s = (char *)(out->data);
71 /* remove trailing spaces if any */
72 l = strlen(s);
73 while (l > 0 && s[l - 1] == ' ') l--;
74 s[l] = '\0';
76 /* remove leading spaces if any */
77 if (*s == ' ') {
78 for (t = s; *s == ' '; s++) ;
80 /* remove leading spaces by moving down the string */
81 memmove(t, s, l);
83 s = t;
86 /* check middle spaces */
87 while ((t = strchr(s, ' ')) != NULL) {
88 for (s = t; *s == ' '; s++) ;
90 if ((s - t) > 1) {
91 l = strlen(s);
93 /* remove all spaces but one by moving down the string */
94 memmove(t + 1, s, l);
98 out->length = strlen((char *)out->data);
99 return 0;
105 canonicalise a ldap Integer
106 rfc2252 specifies it should be in decimal form
108 int ldb_canonicalise_Integer(struct ldb_context *ldb, void *mem_ctx,
109 const struct ldb_val *in, struct ldb_val *out)
111 char *end;
112 long long i = strtoll((char *)in->data, &end, 0);
113 if (*end != 0) {
114 return -1;
116 out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%lld", i);
117 if (out->data == NULL) {
118 return -1;
120 out->length = strlen((char *)out->data);
121 return 0;
125 compare two Integers
127 int ldb_comparison_Integer(struct ldb_context *ldb, void *mem_ctx,
128 const struct ldb_val *v1, const struct ldb_val *v2)
130 return strtoll((char *)v1->data, NULL, 0) - strtoll((char *)v2->data, NULL, 0);
134 compare two binary blobs
136 int ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx,
137 const struct ldb_val *v1, const struct ldb_val *v2)
139 if (v1->length != v2->length) {
140 return v1->length - v2->length;
142 return memcmp(v1->data, v2->data, v1->length);
146 compare two case insensitive strings, ignoring multiple whitespaces
147 and leading and trailing whitespaces
148 see rfc2252 section 8.1
150 try to optimize for the ascii case,
151 but if we find out an utf8 codepoint revert to slower but correct function
153 int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx,
154 const struct ldb_val *v1, const struct ldb_val *v2)
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--; }
175 s1++; s2++;
176 n1--; n2--;
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"
184 while (*s1 == ' ') { s1++; n1--; }
185 while (*s2 == ' ') { s2++; n2--; }
187 if (n1 != n2) {
188 return n1 - n2;
190 return (int)(toupper(*s1)) - (int)(toupper(*s2));
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);
197 if (b1 && b2) {
198 /* Both strings converted correctly */
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 */
205 u1 = s1;
206 u2 = s2;
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++;
216 u1++; u2++;
218 if (! (*u1 && *u2)) {
219 while (*u1 == ' ') u1++;
220 while (*u2 == ' ') u2++;
222 ret = (int)(*u1 - *u2);
224 talloc_free(b1);
225 talloc_free(b2);
227 return ret;
232 canonicalise a attribute in DN format
234 int ldb_canonicalise_dn(struct ldb_context *ldb, void *mem_ctx,
235 const struct ldb_val *in, struct ldb_val *out)
237 struct ldb_dn *dn;
238 int ret = -1;
240 out->length = 0;
241 out->data = NULL;
243 dn = ldb_dn_from_ldb_val(ldb, mem_ctx, in);
244 if ( ! ldb_dn_validate(dn)) {
245 return LDB_ERR_INVALID_DN_SYNTAX;
248 out->data = (uint8_t *)ldb_dn_alloc_casefold(mem_ctx, dn);
249 if (out->data == NULL) {
250 goto done;
252 out->length = strlen((char *)out->data);
254 ret = 0;
256 done:
257 talloc_free(dn);
259 return ret;
263 compare two dns
265 int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx,
266 const struct ldb_val *v1, const struct ldb_val *v2)
268 struct ldb_dn *dn1 = NULL, *dn2 = NULL;
269 int ret;
271 dn1 = ldb_dn_from_ldb_val(ldb, mem_ctx, v1);
272 if ( ! ldb_dn_validate(dn1)) return -1;
274 dn2 = ldb_dn_from_ldb_val(ldb, mem_ctx, v2);
275 if ( ! ldb_dn_validate(dn2)) {
276 talloc_free(dn1);
277 return -1;
280 ret = ldb_dn_compare(dn1, dn2);
282 talloc_free(dn1);
283 talloc_free(dn2);
284 return ret;
288 compare two utc time values. 1 second resolution
290 int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx,
291 const struct ldb_val *v1, const struct ldb_val *v2)
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;
300 canonicalise a utc time
302 int ldb_canonicalise_utctime(struct ldb_context *ldb, void *mem_ctx,
303 const struct ldb_val *in, struct ldb_val *out)
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;
310 out->length = strlen((char *)out->data);
311 return 0;
315 table of standard attribute handlers
317 static const struct ldb_schema_syntax ldb_standard_syntaxes[] = {
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
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
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
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
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
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
364 return the attribute handlers for a given syntax name
366 const struct ldb_schema_syntax *ldb_standard_syntax_by_name(struct ldb_context *ldb,
367 const char *syntax)
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];
377 return NULL;