~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/lib/ldb/common/attrib_handlers.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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,
 
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,
 
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,
 
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,
 
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,
 
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,
 
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,
 
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,
 
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,
 
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,
 
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,
 
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,
 
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