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
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
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
) {
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
53 int ldb_handler_fold(struct ldb_context
*ldb
, void *mem_ctx
,
54 const struct ldb_val
*in
, struct ldb_val
*out
)
59 if (!in
|| !out
|| !(in
->data
)) {
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
);
69 s
= (char *)(out
->data
);
71 /* remove trailing spaces if any */
73 while (l
> 0 && s
[l
- 1] == ' ') l
--;
76 /* remove leading spaces if any */
78 for (t
= s
; *s
== ' '; s
++) ;
80 /* remove leading spaces by moving down the string */
86 /* check middle spaces */
87 while ((t
= strchr(s
, ' ')) != NULL
) {
88 for (s
= t
; *s
== ' '; s
++) ;
93 /* remove all spaces but one by moving down the string */
98 out
->length
= strlen((char *)out
->data
);
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
)
112 long long i
= strtoll((char *)in
->data
, &end
, 0);
116 out
->data
= (uint8_t *)talloc_asprintf(mem_ctx
, "%lld", i
);
117 if (out
->data
== NULL
) {
120 out
->length
= strlen((char *)out
->data
);
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
;
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
))
172 while (s1
[0] == s1
[1] && n1
) { s1
++; n1
--; }
173 while (s2
[0] == s2
[1] && n2
) { s2
++; 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
--; }
190 return (int)(toupper(*s1
)) - (int)(toupper(*s2
));
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
);
198 /* Both strings converted correctly */
203 /* One of the strings was not UTF8, so we have no options but to do a binary compare */
213 while (u1
[0] == u1
[1]) u1
++;
214 while (u2
[0] == u2
[1]) u2
++;
218 if (! (*u1
&& *u2
)) {
219 while (*u1
== ' ') u1
++;
220 while (*u2
== ' ') u2
++;
222 ret
= (int)(*u1
- *u2
);
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
)
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
) {
252 out
->length
= strlen((char *)out
->data
);
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
;
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
)) {
280 ret
= ldb_dn_compare(dn1
, dn2
);
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
)
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
) {
310 out
->length
= strlen((char *)out
->data
);
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
,
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
];