r19071: Backport to SAMBA_3_0 as well
[Samba.git] / source / lib / ldb / ldb_tdb / ldb_cache.c
bloba6092c45f93c0d0b49009593c0b5a41e48e4ec2b
1 /*
2 ldb database library
4 Copyright (C) Andrew Tridgell 2004
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 2 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, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 * Name: ldb
28 * Component: ldb tdb cache functions
30 * Description: cache special records in a ldb/tdb
32 * Author: Andrew Tridgell
35 #include "includes.h"
36 #include "ldb/include/includes.h"
38 #include "ldb/ldb_tdb/ldb_tdb.h"
40 #define LTDB_FLAG_CASE_INSENSITIVE (1<<0)
41 #define LTDB_FLAG_INTEGER (1<<1)
42 #define LTDB_FLAG_HIDDEN (1<<2)
43 #define LTDB_FLAG_OBJECTCLASS (1<<3)
45 /* valid attribute flags */
46 static const struct {
47 const char *name;
48 int value;
49 } ltdb_valid_attr_flags[] = {
50 { "CASE_INSENSITIVE", LTDB_FLAG_CASE_INSENSITIVE },
51 { "INTEGER", LTDB_FLAG_INTEGER },
52 { "HIDDEN", LTDB_FLAG_HIDDEN },
53 { "NONE", 0 },
54 { NULL, 0 }
59 de-register any special handlers for @ATTRIBUTES
61 static void ltdb_attributes_unload(struct ldb_module *module)
63 struct ltdb_private *ltdb = module->private_data;
64 struct ldb_message *msg;
65 int i;
67 if (ltdb->cache->attributes == NULL) {
68 /* no previously loaded attributes */
69 return;
72 msg = ltdb->cache->attributes;
73 for (i=0;i<msg->num_elements;i++) {
74 const struct ldb_attrib_handler *h;
75 /* this is rather ugly - a consequence of const handling */
76 h = ldb_attrib_handler(module->ldb, msg->elements[i].name);
77 ldb_remove_attrib_handler(module->ldb, msg->elements[i].name);
78 if (strcmp(h->attr, msg->elements[i].name) == 0) {
79 talloc_steal(msg, h->attr);
83 talloc_free(ltdb->cache->attributes);
84 ltdb->cache->attributes = NULL;
88 add up the attrib flags for a @ATTRIBUTES element
90 static int ltdb_attributes_flags(struct ldb_message_element *el, unsigned *v)
92 int i;
93 unsigned value = 0;
94 for (i=0;i<el->num_values;i++) {
95 int j;
96 for (j=0;ltdb_valid_attr_flags[j].name;j++) {
97 if (strcmp(ltdb_valid_attr_flags[j].name,
98 (char *)el->values[i].data) == 0) {
99 value |= ltdb_valid_attr_flags[j].value;
100 break;
103 if (ltdb_valid_attr_flags[j].name == NULL) {
104 return -1;
107 *v = value;
108 return 0;
112 register any special handlers from @ATTRIBUTES
114 static int ltdb_attributes_load(struct ldb_module *module)
116 struct ltdb_private *ltdb = module->private_data;
117 struct ldb_message *msg = ltdb->cache->attributes;
118 struct ldb_dn *dn;
119 int i;
121 dn = ldb_dn_explode(module->ldb, LTDB_ATTRIBUTES);
122 if (dn == NULL) goto failed;
124 if (ltdb_search_dn1(module, dn, msg) == -1) {
125 talloc_free(dn);
126 goto failed;
128 talloc_free(dn);
129 /* mapping these flags onto ldap 'syntaxes' isn't strictly correct,
130 but its close enough for now */
131 for (i=0;i<msg->num_elements;i++) {
132 unsigned flags;
133 const char *syntax;
134 const struct ldb_attrib_handler *h;
135 struct ldb_attrib_handler h2;
137 if (ltdb_attributes_flags(&msg->elements[i], &flags) != 0) {
138 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Invalid @ATTRIBUTES element for '%s'\n", msg->elements[i].name);
139 goto failed;
141 switch (flags & ~LTDB_FLAG_HIDDEN) {
142 case 0:
143 syntax = LDB_SYNTAX_OCTET_STRING;
144 break;
145 case LTDB_FLAG_CASE_INSENSITIVE:
146 syntax = LDB_SYNTAX_DIRECTORY_STRING;
147 break;
148 case LTDB_FLAG_INTEGER:
149 syntax = LDB_SYNTAX_INTEGER;
150 break;
151 default:
152 ldb_debug(module->ldb, LDB_DEBUG_ERROR,
153 "Invalid flag combination 0x%x for '%s' in @ATTRIBUTES\n",
154 flags, msg->elements[i].name);
155 goto failed;
158 h = ldb_attrib_handler_syntax(module->ldb, syntax);
159 if (h == NULL) {
160 ldb_debug(module->ldb, LDB_DEBUG_ERROR,
161 "Invalid attribute syntax '%s' for '%s' in @ATTRIBUTES\n",
162 syntax, msg->elements[i].name);
163 goto failed;
165 h2 = *h;
166 h2.attr = talloc_strdup(module, msg->elements[i].name);
167 if (ldb_set_attrib_handlers(module->ldb, &h2, 1) != 0) {
168 goto failed;
172 return 0;
173 failed:
174 return -1;
179 register any subclasses from @SUBCLASSES
181 static int ltdb_subclasses_load(struct ldb_module *module)
183 struct ltdb_private *ltdb = module->private_data;
184 struct ldb_message *msg = ltdb->cache->subclasses;
185 struct ldb_dn *dn;
186 int i, j;
188 dn = ldb_dn_explode(module->ldb, LTDB_SUBCLASSES);
189 if (dn == NULL) goto failed;
191 if (ltdb_search_dn1(module, dn, msg) == -1) {
192 talloc_free(dn);
193 goto failed;
195 talloc_free(dn);
197 for (i=0;i<msg->num_elements;i++) {
198 struct ldb_message_element *el = &msg->elements[i];
199 for (j=0;j<el->num_values;j++) {
200 if (ldb_subclass_add(module->ldb, el->name,
201 (char *)el->values[j].data) != 0) {
202 goto failed;
207 return 0;
208 failed:
209 return -1;
214 de-register any @SUBCLASSES
216 static void ltdb_subclasses_unload(struct ldb_module *module)
218 struct ltdb_private *ltdb = module->private_data;
219 struct ldb_message *msg;
220 int i;
222 if (ltdb->cache->subclasses == NULL) {
223 /* no previously loaded subclasses */
224 return;
227 msg = ltdb->cache->subclasses;
228 for (i=0;i<msg->num_elements;i++) {
229 ldb_subclass_remove(module->ldb, msg->elements[i].name);
232 talloc_free(ltdb->cache->subclasses);
233 ltdb->cache->subclasses = NULL;
238 initialise the baseinfo record
240 static int ltdb_baseinfo_init(struct ldb_module *module)
242 struct ltdb_private *ltdb = module->private_data;
243 struct ldb_message *msg;
244 struct ldb_message_element el;
245 struct ldb_val val;
246 int ret;
247 /* the initial sequence number must be different from the one
248 set in ltdb_cache_free(). Thanks to Jon for pointing this
249 out. */
250 const char *initial_sequence_number = "1";
252 ltdb->sequence_number = atof(initial_sequence_number);
254 msg = talloc(ltdb, struct ldb_message);
255 if (msg == NULL) {
256 goto failed;
259 msg->num_elements = 1;
260 msg->elements = &el;
261 msg->dn = ldb_dn_explode(msg, LTDB_BASEINFO);
262 if (!msg->dn) {
263 goto failed;
265 el.name = talloc_strdup(msg, LTDB_SEQUENCE_NUMBER);
266 if (!el.name) {
267 goto failed;
269 el.values = &val;
270 el.num_values = 1;
271 el.flags = 0;
272 val.data = (uint8_t *)talloc_strdup(msg, initial_sequence_number);
273 if (!val.data) {
274 goto failed;
276 val.length = 1;
278 ret = ltdb_store(module, msg, TDB_INSERT);
280 talloc_free(msg);
282 return ret;
284 failed:
285 talloc_free(msg);
286 errno = ENOMEM;
287 return -1;
291 free any cache records
293 static void ltdb_cache_free(struct ldb_module *module)
295 struct ltdb_private *ltdb = module->private_data;
297 ltdb->sequence_number = 0;
298 talloc_free(ltdb->cache);
299 ltdb->cache = NULL;
303 force a cache reload
305 int ltdb_cache_reload(struct ldb_module *module)
307 ltdb_attributes_unload(module);
308 ltdb_subclasses_unload(module);
309 ltdb_cache_free(module);
310 return ltdb_cache_load(module);
314 load the cache records
316 int ltdb_cache_load(struct ldb_module *module)
318 struct ltdb_private *ltdb = module->private_data;
319 struct ldb_dn *baseinfo_dn = NULL;
320 struct ldb_dn *indexlist_dn = NULL;
321 uint64_t seq;
323 if (ltdb->cache == NULL) {
324 ltdb->cache = talloc_zero(ltdb, struct ltdb_cache);
325 if (ltdb->cache == NULL) goto failed;
326 ltdb->cache->indexlist = talloc_zero(ltdb->cache, struct ldb_message);
327 ltdb->cache->subclasses = talloc_zero(ltdb->cache, struct ldb_message);
328 ltdb->cache->attributes = talloc_zero(ltdb->cache, struct ldb_message);
329 if (ltdb->cache->indexlist == NULL ||
330 ltdb->cache->subclasses == NULL ||
331 ltdb->cache->attributes == NULL) {
332 goto failed;
336 talloc_free(ltdb->cache->baseinfo);
337 ltdb->cache->baseinfo = talloc(ltdb->cache, struct ldb_message);
338 if (ltdb->cache->baseinfo == NULL) goto failed;
340 baseinfo_dn = ldb_dn_explode(module->ldb, LTDB_BASEINFO);
341 if (baseinfo_dn == NULL) goto failed;
343 if (ltdb_search_dn1(module, baseinfo_dn, ltdb->cache->baseinfo) == -1) {
344 goto failed;
347 /* possibly initialise the baseinfo */
348 if (!ltdb->cache->baseinfo->dn) {
349 if (ltdb_baseinfo_init(module) != 0) {
350 goto failed;
352 if (ltdb_search_dn1(module, baseinfo_dn, ltdb->cache->baseinfo) != 1) {
353 goto failed;
357 /* if the current internal sequence number is the same as the one
358 in the database then assume the rest of the cache is OK */
359 seq = ldb_msg_find_attr_as_uint64(ltdb->cache->baseinfo, LTDB_SEQUENCE_NUMBER, 0);
360 if (seq == ltdb->sequence_number) {
361 goto done;
363 ltdb->sequence_number = seq;
365 talloc_free(ltdb->cache->last_attribute.name);
366 memset(&ltdb->cache->last_attribute, 0, sizeof(ltdb->cache->last_attribute));
368 ltdb_attributes_unload(module);
369 ltdb_subclasses_unload(module);
371 talloc_free(ltdb->cache->indexlist);
372 talloc_free(ltdb->cache->subclasses);
374 ltdb->cache->indexlist = talloc_zero(ltdb->cache, struct ldb_message);
375 ltdb->cache->subclasses = talloc_zero(ltdb->cache, struct ldb_message);
376 ltdb->cache->attributes = talloc_zero(ltdb->cache, struct ldb_message);
377 if (ltdb->cache->indexlist == NULL ||
378 ltdb->cache->subclasses == NULL ||
379 ltdb->cache->attributes == NULL) {
380 goto failed;
383 indexlist_dn = ldb_dn_explode(module->ldb, LTDB_INDEXLIST);
384 if (indexlist_dn == NULL) goto failed;
386 if (ltdb_search_dn1(module, indexlist_dn, ltdb->cache->indexlist) == -1) {
387 goto failed;
390 if (ltdb_attributes_load(module) == -1) {
391 goto failed;
393 if (ltdb_subclasses_load(module) == -1) {
394 goto failed;
397 done:
398 talloc_free(baseinfo_dn);
399 talloc_free(indexlist_dn);
400 return 0;
402 failed:
403 talloc_free(baseinfo_dn);
404 talloc_free(indexlist_dn);
405 return -1;
410 increase the sequence number to indicate a database change
412 int ltdb_increase_sequence_number(struct ldb_module *module)
414 struct ltdb_private *ltdb = module->private_data;
415 struct ldb_message *msg;
416 struct ldb_message_element el[2];
417 struct ldb_val val;
418 struct ldb_val val_time;
419 time_t t = time(NULL);
420 char *s = NULL;
421 int ret;
423 msg = talloc(ltdb, struct ldb_message);
424 if (msg == NULL) {
425 errno = ENOMEM;
426 return -1;
429 s = talloc_asprintf(msg, "%llu", ltdb->sequence_number+1);
430 if (!s) {
431 errno = ENOMEM;
432 return -1;
435 msg->num_elements = ARRAY_SIZE(el);
436 msg->elements = el;
437 msg->dn = ldb_dn_explode(msg, LTDB_BASEINFO);
438 if (msg->dn == NULL) {
439 talloc_free(msg);
440 errno = ENOMEM;
441 return -1;
443 el[0].name = talloc_strdup(msg, LTDB_SEQUENCE_NUMBER);
444 if (el[0].name == NULL) {
445 talloc_free(msg);
446 errno = ENOMEM;
447 return -1;
449 el[0].values = &val;
450 el[0].num_values = 1;
451 el[0].flags = LDB_FLAG_MOD_REPLACE;
452 val.data = (uint8_t *)s;
453 val.length = strlen(s);
455 el[1].name = talloc_strdup(msg, LTDB_MOD_TIMESTAMP);
456 if (el[1].name == NULL) {
457 talloc_free(msg);
458 errno = ENOMEM;
459 return -1;
461 el[1].values = &val_time;
462 el[1].num_values = 1;
463 el[1].flags = LDB_FLAG_MOD_REPLACE;
465 s = ldb_timestring(msg, t);
466 if (s == NULL) {
467 return -1;
470 val_time.data = (uint8_t *)s;
471 val_time.length = strlen(s);
473 ret = ltdb_modify_internal(module, msg);
475 talloc_free(msg);
477 if (ret == 0) {
478 ltdb->sequence_number += 1;
481 return ret;
486 return the attribute flags from the @ATTRIBUTES record
487 for the given attribute
489 int ltdb_attribute_flags(struct ldb_module *module, const char *attr_name)
491 struct ltdb_private *ltdb = module->private_data;
492 const struct ldb_message_element *attr_el;
493 int i, j, ret=0;
495 if (ltdb->cache->last_attribute.name &&
496 ldb_attr_cmp(ltdb->cache->last_attribute.name, attr_name) == 0) {
497 return ltdb->cache->last_attribute.flags;
500 /* objectclass is a special default case */
501 if (ldb_attr_cmp(attr_name, LTDB_OBJECTCLASS) == 0) {
502 ret = LTDB_FLAG_OBJECTCLASS | LTDB_FLAG_CASE_INSENSITIVE;
505 attr_el = ldb_msg_find_element(ltdb->cache->attributes, attr_name);
507 if (!attr_el) {
508 /* check if theres a wildcard attribute */
509 attr_el = ldb_msg_find_element(ltdb->cache->attributes, "*");
511 if (!attr_el) {
512 return ret;
516 for (i = 0; i < attr_el->num_values; i++) {
517 for (j=0; ltdb_valid_attr_flags[j].name; j++) {
518 if (strcmp(ltdb_valid_attr_flags[j].name,
519 (char *)attr_el->values[i].data) == 0) {
520 ret |= ltdb_valid_attr_flags[j].value;
525 talloc_free(ltdb->cache->last_attribute.name);
527 ltdb->cache->last_attribute.name = talloc_strdup(ltdb->cache, attr_name);
528 ltdb->cache->last_attribute.flags = ret;
530 return ret;
533 int ltdb_check_at_attributes_values(const struct ldb_val *value)
535 int i;
537 for (i = 0; ltdb_valid_attr_flags[i].name != NULL; i++) {
538 if ((strcmp(ltdb_valid_attr_flags[i].name, (char *)value->data) == 0)) {
539 return 0;
543 return -1;