~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/lib/ldb/ldb_tdb/ldb_cache.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  2004
 
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
/*
 
25
 *  Name: ldb
 
26
 *
 
27
 *  Component: ldb tdb cache functions
 
28
 *
 
29
 *  Description: cache special records in a ldb/tdb
 
30
 *
 
31
 *  Author: Andrew Tridgell
 
32
 */
 
33
 
 
34
#include "includes.h"
 
35
#include "ldb/include/includes.h"
 
36
 
 
37
#include "ldb/ldb_tdb/ldb_tdb.h"
 
38
 
 
39
#define LTDB_FLAG_CASE_INSENSITIVE (1<<0)
 
40
#define LTDB_FLAG_INTEGER          (1<<1)
 
41
#define LTDB_FLAG_HIDDEN           (1<<2)
 
42
#define LTDB_FLAG_OBJECTCLASS      (1<<3)
 
43
 
 
44
int ltdb_attribute_flags(struct ldb_module *module, const char *attr_name);
 
45
 
 
46
/* valid attribute flags */
 
47
static const struct {
 
48
        const char *name;
 
49
        int value;
 
50
} ltdb_valid_attr_flags[] = {
 
51
        { "CASE_INSENSITIVE", LTDB_FLAG_CASE_INSENSITIVE },
 
52
        { "INTEGER", LTDB_FLAG_INTEGER },
 
53
        { "HIDDEN", LTDB_FLAG_HIDDEN },
 
54
        { "NONE", 0 },
 
55
        { NULL, 0 }
 
56
};
 
57
 
 
58
 
 
59
/*
 
60
  de-register any special handlers for @ATTRIBUTES
 
61
*/
 
62
static void ltdb_attributes_unload(struct ldb_module *module)
 
63
{
 
64
        struct ltdb_private *ltdb =
 
65
                (struct ltdb_private *)module->private_data;
 
66
        struct ldb_message *msg;
 
67
        int i;
 
68
 
 
69
        if (ltdb->cache->attributes == NULL) {
 
70
                /* no previously loaded attributes */
 
71
                return;
 
72
        }
 
73
 
 
74
        msg = ltdb->cache->attributes;
 
75
        for (i=0;i<msg->num_elements;i++) {
 
76
                ldb_remove_attrib_handler(module->ldb, msg->elements[i].name);
 
77
        }
 
78
 
 
79
        talloc_free(ltdb->cache->attributes);
 
80
        ltdb->cache->attributes = NULL;
 
81
}
 
82
 
 
83
/*
 
84
  add up the attrib flags for a @ATTRIBUTES element
 
85
*/
 
86
static int ltdb_attributes_flags(struct ldb_message_element *el, unsigned *v)
 
87
{
 
88
        int i;
 
89
        unsigned value = 0;
 
90
        for (i=0;i<el->num_values;i++) {
 
91
                int j;
 
92
                for (j=0;ltdb_valid_attr_flags[j].name;j++) {
 
93
                        if (strcmp(ltdb_valid_attr_flags[j].name, 
 
94
                                   (char *)el->values[i].data) == 0) {
 
95
                                value |= ltdb_valid_attr_flags[j].value;
 
96
                                break;
 
97
                        }
 
98
                }
 
99
                if (ltdb_valid_attr_flags[j].name == NULL) {
 
100
                        return -1;
 
101
                }
 
102
        }
 
103
        *v = value;
 
104
        return 0;
 
105
}
 
106
 
 
107
/*
 
108
  register any special handlers from @ATTRIBUTES
 
109
*/
 
110
static int ltdb_attributes_load(struct ldb_module *module)
 
111
{
 
112
        struct ltdb_private *ltdb =
 
113
                (struct ltdb_private *)module->private_data;
 
114
        struct ldb_message *msg = ltdb->cache->attributes;
 
115
        struct ldb_dn *dn;
 
116
        int i;
 
117
 
 
118
        dn = ldb_dn_explode(module->ldb, LTDB_ATTRIBUTES);
 
119
        if (dn == NULL) goto failed;
 
120
 
 
121
        if (ltdb_search_dn1(module, dn, msg) == -1) {
 
122
                talloc_free(dn);
 
123
                goto failed;
 
124
        }
 
125
        talloc_free(dn);
 
126
        /* mapping these flags onto ldap 'syntaxes' isn't strictly correct,
 
127
           but its close enough for now */
 
128
        for (i=0;i<msg->num_elements;i++) {
 
129
                unsigned flags;
 
130
                const char *syntax;
 
131
                const struct ldb_attrib_handler *h;
 
132
                struct ldb_attrib_handler h2;
 
133
 
 
134
                if (ltdb_attributes_flags(&msg->elements[i], &flags) != 0) {
 
135
                        ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Invalid @ATTRIBUTES element for '%s'\n", msg->elements[i].name);
 
136
                        goto failed;
 
137
                }
 
138
                switch (flags & ~LTDB_FLAG_HIDDEN) {
 
139
                case 0:
 
140
                        syntax = LDB_SYNTAX_OCTET_STRING;
 
141
                        break;
 
142
                case LTDB_FLAG_CASE_INSENSITIVE:
 
143
                        syntax = LDB_SYNTAX_DIRECTORY_STRING;
 
144
                        break;
 
145
                case LTDB_FLAG_INTEGER:
 
146
                        syntax = LDB_SYNTAX_INTEGER;
 
147
                        break;
 
148
                default:
 
149
                        ldb_debug(module->ldb, LDB_DEBUG_ERROR, 
 
150
                                  "Invalid flag combination 0x%x for '%s' in @ATTRIBUTES\n",
 
151
                                  flags, msg->elements[i].name);
 
152
                        goto failed;
 
153
                }
 
154
 
 
155
                h = ldb_attrib_handler_syntax(module->ldb, syntax);
 
156
                if (h == NULL) {
 
157
                        ldb_debug(module->ldb, LDB_DEBUG_ERROR, 
 
158
                                  "Invalid attribute syntax '%s' for '%s' in @ATTRIBUTES\n",
 
159
                                  syntax, msg->elements[i].name);
 
160
                        goto failed;
 
161
                }
 
162
                h2 = *h;
 
163
                h2.attr = msg->elements[i].name;
 
164
                h2.flags |= LDB_ATTR_FLAG_ALLOCATED;
 
165
                if (ldb_set_attrib_handlers(module->ldb, &h2, 1) != 0) {
 
166
                        goto failed;
 
167
                }
 
168
        }
 
169
 
 
170
        return 0;
 
171
failed:
 
172
        return -1;
 
173
}
 
174
 
 
175
 
 
176
/*
 
177
  register any subclasses from @SUBCLASSES
 
178
*/
 
179
static int ltdb_subclasses_load(struct ldb_module *module)
 
180
{
 
181
        struct ltdb_private *ltdb =
 
182
                (struct ltdb_private *)module->private_data;
 
183
        struct ldb_message *msg = ltdb->cache->subclasses;
 
184
        struct ldb_dn *dn;
 
185
        int i, j;
 
186
 
 
187
        dn = ldb_dn_explode(module->ldb, LTDB_SUBCLASSES);
 
188
        if (dn == NULL) goto failed;
 
189
 
 
190
        if (ltdb_search_dn1(module, dn, msg) == -1) {
 
191
                talloc_free(dn);
 
192
                goto failed;
 
193
        }
 
194
        talloc_free(dn);
 
195
 
 
196
        for (i=0;i<msg->num_elements;i++) {
 
197
                struct ldb_message_element *el = &msg->elements[i];
 
198
                for (j=0;j<el->num_values;j++) {
 
199
                        if (ldb_subclass_add(module->ldb, el->name, 
 
200
                                             (char *)el->values[j].data) != 0) {
 
201
                                goto failed;
 
202
                        }
 
203
                }
 
204
        }
 
205
 
 
206
        return 0;
 
207
failed:
 
208
        return -1;
 
209
}
 
210
 
 
211
 
 
212
/*
 
213
  de-register any @SUBCLASSES
 
214
*/
 
215
static void ltdb_subclasses_unload(struct ldb_module *module)
 
216
{
 
217
        struct ltdb_private *ltdb =
 
218
                (struct ltdb_private *)module->private_data;
 
219
        struct ldb_message *msg;
 
220
        int i;
 
221
 
 
222
        if (ltdb->cache->subclasses == NULL) {
 
223
                /* no previously loaded subclasses */
 
224
                return;
 
225
        }
 
226
 
 
227
        msg = ltdb->cache->subclasses;
 
228
        for (i=0;i<msg->num_elements;i++) {
 
229
                ldb_subclass_remove(module->ldb, msg->elements[i].name);
 
230
        }
 
231
 
 
232
        talloc_free(ltdb->cache->subclasses);
 
233
        ltdb->cache->subclasses = NULL;
 
234
}
 
235
 
 
236
 
 
237
/*
 
238
  initialise the baseinfo record
 
239
*/
 
240
static int ltdb_baseinfo_init(struct ldb_module *module)
 
241
{
 
242
        struct ltdb_private *ltdb =
 
243
                (struct ltdb_private *)module->private_data;
 
244
        struct ldb_message *msg;
 
245
        struct ldb_message_element el;
 
246
        struct ldb_val val;
 
247
        int ret;
 
248
        /* the initial sequence number must be different from the one
 
249
           set in ltdb_cache_free(). Thanks to Jon for pointing this
 
250
           out. */
 
251
        const char *initial_sequence_number = "1";
 
252
 
 
253
        ltdb->sequence_number = atof(initial_sequence_number);
 
254
 
 
255
        msg = talloc(ltdb, struct ldb_message);
 
256
        if (msg == NULL) {
 
257
                goto failed;
 
258
        }
 
259
 
 
260
        msg->num_elements = 1;
 
261
        msg->elements = &el;
 
262
        msg->dn = ldb_dn_explode(msg, LTDB_BASEINFO);
 
263
        if (!msg->dn) {
 
264
                goto failed;
 
265
        }
 
266
        el.name = talloc_strdup(msg, LTDB_SEQUENCE_NUMBER);
 
267
        if (!el.name) {
 
268
                goto failed;
 
269
        }
 
270
        el.values = &val;
 
271
        el.num_values = 1;
 
272
        el.flags = 0;
 
273
        val.data = (uint8_t *)talloc_strdup(msg, initial_sequence_number);
 
274
        if (!val.data) {
 
275
                goto failed;
 
276
        }
 
277
        val.length = 1;
 
278
        
 
279
        ret = ltdb_store(module, msg, TDB_INSERT);
 
280
 
 
281
        talloc_free(msg);
 
282
 
 
283
        return ret;
 
284
 
 
285
failed:
 
286
        talloc_free(msg);
 
287
        errno = ENOMEM;
 
288
        return -1;
 
289
}
 
290
 
 
291
/*
 
292
  free any cache records
 
293
 */
 
294
static void ltdb_cache_free(struct ldb_module *module)
 
295
{
 
296
        struct ltdb_private *ltdb =
 
297
                (struct ltdb_private *)module->private_data;
 
298
 
 
299
        ltdb->sequence_number = 0;
 
300
        talloc_free(ltdb->cache);
 
301
        ltdb->cache = NULL;
 
302
}
 
303
 
 
304
/*
 
305
  force a cache reload
 
306
*/
 
307
int ltdb_cache_reload(struct ldb_module *module)
 
308
{
 
309
        ltdb_attributes_unload(module);
 
310
        ltdb_subclasses_unload(module);
 
311
        ltdb_cache_free(module);
 
312
        return ltdb_cache_load(module);
 
313
}
 
314
 
 
315
/*
 
316
  load the cache records
 
317
*/
 
318
int ltdb_cache_load(struct ldb_module *module)
 
319
{
 
320
        struct ltdb_private *ltdb =
 
321
                (struct ltdb_private *)module->private_data;
 
322
        struct ldb_dn *baseinfo_dn = NULL;
 
323
        struct ldb_dn *indexlist_dn = NULL;
 
324
        uint64_t seq;
 
325
        struct ldb_message *baseinfo = NULL;
 
326
 
 
327
        /* a very fast check to avoid extra database reads */
 
328
        if (ltdb->cache != NULL && 
 
329
            tdb_get_seqnum(ltdb->tdb) == ltdb->tdb_seqnum) {
 
330
                return 0;
 
331
        }
 
332
 
 
333
        if (ltdb->cache == NULL) {
 
334
                ltdb->cache = talloc_zero(ltdb, struct ltdb_cache);
 
335
                if (ltdb->cache == NULL) goto failed;
 
336
                ltdb->cache->indexlist = talloc_zero(ltdb->cache, struct ldb_message);
 
337
                ltdb->cache->subclasses = talloc_zero(ltdb->cache, struct ldb_message);
 
338
                ltdb->cache->attributes = talloc_zero(ltdb->cache, struct ldb_message);
 
339
                if (ltdb->cache->indexlist == NULL ||
 
340
                    ltdb->cache->subclasses == NULL ||
 
341
                    ltdb->cache->attributes == NULL) {
 
342
                        goto failed;
 
343
                }
 
344
        }
 
345
 
 
346
        baseinfo = talloc(ltdb->cache, struct ldb_message);
 
347
        if (baseinfo == NULL) goto failed;
 
348
 
 
349
        baseinfo_dn = ldb_dn_explode(module->ldb, LTDB_BASEINFO);
 
350
        if (baseinfo_dn == NULL) goto failed;
 
351
 
 
352
        if (ltdb_search_dn1(module, baseinfo_dn, baseinfo) == -1) {
 
353
                goto failed;
 
354
        }
 
355
        
 
356
        /* possibly initialise the baseinfo */
 
357
        if (!baseinfo->dn) {
 
358
                if (ltdb_baseinfo_init(module) != 0) {
 
359
                        goto failed;
 
360
                }
 
361
                if (ltdb_search_dn1(module, baseinfo_dn, baseinfo) != 1) {
 
362
                        goto failed;
 
363
                }
 
364
        }
 
365
 
 
366
        ltdb->tdb_seqnum = tdb_get_seqnum(ltdb->tdb);
 
367
 
 
368
        /* if the current internal sequence number is the same as the one
 
369
           in the database then assume the rest of the cache is OK */
 
370
        seq = ldb_msg_find_attr_as_uint64(baseinfo, LTDB_SEQUENCE_NUMBER, 0);
 
371
        if (seq == ltdb->sequence_number) {
 
372
                goto done;
 
373
        }
 
374
        ltdb->sequence_number = seq;
 
375
 
 
376
        talloc_free(ltdb->cache->last_attribute.name);
 
377
        memset(&ltdb->cache->last_attribute, 0, sizeof(ltdb->cache->last_attribute));
 
378
 
 
379
        ltdb_attributes_unload(module);
 
380
        ltdb_subclasses_unload(module);
 
381
 
 
382
        talloc_free(ltdb->cache->indexlist);
 
383
        talloc_free(ltdb->cache->subclasses);
 
384
 
 
385
        ltdb->cache->indexlist = talloc_zero(ltdb->cache, struct ldb_message);
 
386
        ltdb->cache->subclasses = talloc_zero(ltdb->cache, struct ldb_message);
 
387
        ltdb->cache->attributes = talloc_zero(ltdb->cache, struct ldb_message);
 
388
        if (ltdb->cache->indexlist == NULL ||
 
389
            ltdb->cache->subclasses == NULL ||
 
390
            ltdb->cache->attributes == NULL) {
 
391
                goto failed;
 
392
        }
 
393
            
 
394
        indexlist_dn = ldb_dn_explode(module->ldb, LTDB_INDEXLIST);
 
395
        if (indexlist_dn == NULL) goto failed;
 
396
 
 
397
        if (ltdb_search_dn1(module, indexlist_dn, ltdb->cache->indexlist) == -1) {
 
398
                goto failed;
 
399
        }
 
400
 
 
401
        if (ltdb_attributes_load(module) == -1) {
 
402
                goto failed;
 
403
        }
 
404
        if (ltdb_subclasses_load(module) == -1) {
 
405
                goto failed;
 
406
        }
 
407
 
 
408
done:
 
409
        talloc_free(baseinfo);
 
410
        talloc_free(baseinfo_dn);
 
411
        talloc_free(indexlist_dn);
 
412
        return 0;
 
413
 
 
414
failed:
 
415
        talloc_free(baseinfo);
 
416
        talloc_free(baseinfo_dn);
 
417
        talloc_free(indexlist_dn);
 
418
        return -1;
 
419
}
 
420
 
 
421
 
 
422
/*
 
423
  increase the sequence number to indicate a database change
 
424
*/
 
425
int ltdb_increase_sequence_number(struct ldb_module *module)
 
426
{
 
427
        struct ltdb_private *ltdb =
 
428
                (struct ltdb_private *)module->private_data;
 
429
        struct ldb_message *msg;
 
430
        struct ldb_message_element el[2];
 
431
        struct ldb_val val;
 
432
        struct ldb_val val_time;
 
433
        time_t t = time(NULL);
 
434
        char *s = NULL;
 
435
        int ret;
 
436
 
 
437
        msg = talloc(ltdb, struct ldb_message);
 
438
        if (msg == NULL) {
 
439
                errno = ENOMEM;
 
440
                return -1;
 
441
        }
 
442
 
 
443
        s = talloc_asprintf(msg, "%llu", ltdb->sequence_number+1);
 
444
        if (!s) {
 
445
                errno = ENOMEM;
 
446
                return -1;
 
447
        }
 
448
 
 
449
        msg->num_elements = ARRAY_SIZE(el);
 
450
        msg->elements = el;
 
451
        msg->dn = ldb_dn_explode(msg, LTDB_BASEINFO);
 
452
        if (msg->dn == NULL) {
 
453
                talloc_free(msg);
 
454
                errno = ENOMEM;
 
455
                return -1;
 
456
        }
 
457
        el[0].name = talloc_strdup(msg, LTDB_SEQUENCE_NUMBER);
 
458
        if (el[0].name == NULL) {
 
459
                talloc_free(msg);
 
460
                errno = ENOMEM;
 
461
                return -1;
 
462
        }
 
463
        el[0].values = &val;
 
464
        el[0].num_values = 1;
 
465
        el[0].flags = LDB_FLAG_MOD_REPLACE;
 
466
        val.data = (uint8_t *)s;
 
467
        val.length = strlen(s);
 
468
 
 
469
        el[1].name = talloc_strdup(msg, LTDB_MOD_TIMESTAMP);
 
470
        if (el[1].name == NULL) {
 
471
                talloc_free(msg);
 
472
                errno = ENOMEM;
 
473
                return -1;
 
474
        }
 
475
        el[1].values = &val_time;
 
476
        el[1].num_values = 1;
 
477
        el[1].flags = LDB_FLAG_MOD_REPLACE;
 
478
 
 
479
        s = ldb_timestring(msg, t);
 
480
        if (s == NULL) {
 
481
                return -1;
 
482
        }
 
483
 
 
484
        val_time.data = (uint8_t *)s;
 
485
        val_time.length = strlen(s);
 
486
 
 
487
        ret = ltdb_modify_internal(module, msg);
 
488
 
 
489
        talloc_free(msg);
 
490
 
 
491
        if (ret == 0) {
 
492
                ltdb->sequence_number += 1;
 
493
        }
 
494
 
 
495
        return ret;
 
496
}
 
497
 
 
498
 
 
499
/*
 
500
  return the attribute flags from the @ATTRIBUTES record 
 
501
  for the given attribute
 
502
*/
 
503
int ltdb_attribute_flags(struct ldb_module *module, const char *attr_name)
 
504
{
 
505
        struct ltdb_private *ltdb =
 
506
                (struct ltdb_private *)module->private_data;
 
507
        const struct ldb_message_element *attr_el;
 
508
        int i, j, ret=0;
 
509
 
 
510
        if (ltdb->cache->last_attribute.name &&
 
511
            ldb_attr_cmp(ltdb->cache->last_attribute.name, attr_name) == 0) {
 
512
                return ltdb->cache->last_attribute.flags;
 
513
        }
 
514
 
 
515
        /* objectclass is a special default case */
 
516
        if (ldb_attr_cmp(attr_name, LTDB_OBJECTCLASS) == 0) {
 
517
                ret = LTDB_FLAG_OBJECTCLASS | LTDB_FLAG_CASE_INSENSITIVE;
 
518
        }
 
519
 
 
520
        attr_el = ldb_msg_find_element(ltdb->cache->attributes, attr_name);
 
521
 
 
522
        if (!attr_el) {
 
523
                /* check if theres a wildcard attribute */
 
524
                attr_el = ldb_msg_find_element(ltdb->cache->attributes, "*");
 
525
 
 
526
                if (!attr_el) {
 
527
                        return ret;
 
528
                }
 
529
        }
 
530
 
 
531
        for (i = 0; i < attr_el->num_values; i++) {
 
532
                for (j=0; ltdb_valid_attr_flags[j].name; j++) {
 
533
                        if (strcmp(ltdb_valid_attr_flags[j].name, 
 
534
                                   (char *)attr_el->values[i].data) == 0) {
 
535
                                ret |= ltdb_valid_attr_flags[j].value;
 
536
                        }
 
537
                }
 
538
        }
 
539
 
 
540
        talloc_free(ltdb->cache->last_attribute.name);
 
541
 
 
542
        ltdb->cache->last_attribute.name = talloc_strdup(ltdb->cache, attr_name);
 
543
        ltdb->cache->last_attribute.flags = ret;
 
544
 
 
545
        return ret;
 
546
}
 
547
 
 
548
int ltdb_check_at_attributes_values(const struct ldb_val *value)
 
549
{
 
550
        int i;
 
551
 
 
552
        for (i = 0; ltdb_valid_attr_flags[i].name != NULL; i++) {
 
553
                if ((strcmp(ltdb_valid_attr_flags[i].name, (char *)value->data) == 0)) {
 
554
                        return 0;
 
555
                }
 
556
        }
 
557
 
 
558
        return -1;
 
559
}
 
560