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
29
#include "ldb/include/includes.h"
30
#include "system/locale.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
static int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx,
54
const struct ldb_val *in, struct ldb_val *out)
58
if (!in || !out || !(in->data)) {
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);
68
s = (char *)(out->data);
70
/* remove trailing spaces if any */
72
while (l > 0 && s[l - 1] == ' ') l--;
75
/* remove leading spaces if any */
77
for (t = s; *s == ' '; s++) ;
79
/* remove leading spaces by moving down the string */
85
/* check middle spaces */
86
while ((t = strchr(s, ' ')) != NULL) {
87
for (s = t; *s == ' '; s++) ;
92
/* remove all spaces but one by moving down the string */
97
out->length = strlen((char *)out->data);
104
canonicalise a ldap Integer
105
rfc2252 specifies it should be in decimal form
107
static int ldb_canonicalise_Integer(struct ldb_context *ldb, void *mem_ctx,
108
const struct ldb_val *in, struct ldb_val *out)
111
long long i = strtoll((char *)in->data, &end, 0);
115
out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%lld", i);
116
if (out->data == NULL) {
119
out->length = strlen((char *)out->data);
126
static int ldb_comparison_Integer(struct ldb_context *ldb, void *mem_ctx,
127
const struct ldb_val *v1, const struct ldb_val *v2)
129
return strtoll((char *)v1->data, NULL, 0) - strtoll((char *)v2->data, NULL, 0);
133
compare two binary blobs
135
int ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx,
136
const struct ldb_val *v1, const struct ldb_val *v2)
138
if (v1->length != v2->length) {
139
return v1->length - v2->length;
141
return memcmp(v1->data, v2->data, v1->length);
145
compare two case insensitive strings, ignoring multiple whitespaces
146
and leading and trailing whitespaces
147
see rfc2252 section 8.1
149
try to optimize for the ascii case,
150
but if we find out an utf8 codepoint revert to slower but correct function
152
static int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx,
153
const struct ldb_val *v1, const struct ldb_val *v2)
155
const char *s1=(const char *)v1->data, *s2=(const char *)v2->data;
159
while (*s1 == ' ') s1++;
160
while (*s2 == ' ') s2++;
161
/* TODO: make utf8 safe, possibly with helper function from application */
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))
170
while (s1[0] == s1[1]) s1++;
171
while (s2[0] == s2[1]) s2++;
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"
181
while (*s1 == ' ') s1++;
182
while (*s2 == ' ') s2++;
184
return (int)(toupper(*s1)) - (int)(toupper(*s2));
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);
192
/* Both strings converted correctly */
197
/* One of the strings was not UTF8, so we have no options but to do a binary compare */
207
while (u1[0] == u1[1]) u1++;
208
while (u2[0] == u2[1]) u2++;
212
if (! (*u1 && *u2)) {
213
while (*u1 == ' ') u1++;
214
while (*u2 == ' ') u2++;
216
ret = (int)(*u1 - *u2);
225
canonicalise a attribute in DN format
227
static int ldb_canonicalise_dn(struct ldb_context *ldb, void *mem_ctx,
228
const struct ldb_val *in, struct ldb_val *out)
236
dn = ldb_dn_explode_casefold(ldb, mem_ctx, (char *)in->data);
241
out->data = (uint8_t *)ldb_dn_linearize(mem_ctx, dn);
242
if (out->data == NULL) {
245
out->length = strlen((char *)out->data);
258
static int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx,
259
const struct ldb_val *v1, const struct ldb_val *v2)
261
struct ldb_dn *dn1 = NULL, *dn2 = NULL;
264
dn1 = ldb_dn_explode_casefold(ldb, mem_ctx, (char *)v1->data);
265
if (dn1 == NULL) return -1;
267
dn2 = ldb_dn_explode_casefold(ldb, mem_ctx, (char *)v2->data);
273
ret = ldb_dn_compare(ldb, dn1, dn2);
281
compare two objectclasses, looking at subclasses
283
static int ldb_comparison_objectclass(struct ldb_context *ldb, void *mem_ctx,
284
const struct ldb_val *v1, const struct ldb_val *v2)
287
const char **subclasses;
288
ret = ldb_comparison_fold(ldb, mem_ctx, v1, v2);
292
subclasses = ldb_subclass_list(ldb, (char *)v1->data);
293
if (subclasses == NULL) {
296
for (i=0;subclasses[i];i++) {
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) {
308
compare two utc time values. 1 second resolution
310
static int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx,
311
const struct ldb_val *v1, const struct ldb_val *v2)
314
t1 = ldb_string_to_time((char *)v1->data);
315
t2 = ldb_string_to_time((char *)v2->data);
316
return (int)t2 - (int)t1;
320
canonicalise a utc time
322
static int ldb_canonicalise_utctime(struct ldb_context *ldb, void *mem_ctx,
323
const struct ldb_val *in, struct ldb_val *out)
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) {
330
out->length = strlen((char *)out->data);
335
table of standard attribute handlers
337
static const struct ldb_attrib_handler ldb_standard_attribs[] = {
339
.attr = LDB_SYNTAX_INTEGER,
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
347
.attr = LDB_SYNTAX_OCTET_STRING,
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
355
.attr = LDB_SYNTAX_DIRECTORY_STRING,
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
363
.attr = LDB_SYNTAX_DN,
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
371
.attr = LDB_SYNTAX_OBJECTCLASS,
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
379
.attr = LDB_SYNTAX_UTC_TIME,
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
390
return the attribute handlers for a given syntax name
392
const struct ldb_attrib_handler *ldb_attrib_handler_syntax(struct ldb_context *ldb,
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];