r8037: a fairly major update to the internals of ldb. Changes are:
[metze/samba/wip.git] / source4 / lib / ldb / ldb_tdb / ldb_cache.c
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 2 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, write to the Free Software
22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 */
24
25 /*
26  *  Name: ldb
27  *
28  *  Component: ldb tdb cache functions
29  *
30  *  Description: cache special records in a ldb/tdb
31  *
32  *  Author: Andrew Tridgell
33  */
34
35 #include "includes.h"
36 #include "ldb/include/ldb.h"
37 #include "ldb/include/ldb_private.h"
38 #include "ldb/ldb_tdb/ldb_tdb.h"
39
40 #define LTDB_FLAG_CASE_INSENSITIVE (1<<0)
41 #define LTDB_FLAG_INTEGER          (1<<1)
42 #define LTDB_FLAG_WILDCARD         (1<<2)
43 #define LTDB_FLAG_HIDDEN           (1<<3)
44 #define LTDB_FLAG_OBJECTCLASS      (1<<4)
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         { "WILDCARD", LTDB_FLAG_WILDCARD },
54         { "HIDDEN", LTDB_FLAG_HIDDEN },
55         { "NONE", 0 },
56         { NULL, 0 }
57 };
58
59
60 /*
61   de-register any special handlers for @ATTRIBUTES
62 */
63 static void ltdb_attributes_unload(struct ldb_module *module)
64 {
65         struct ltdb_private *ltdb = 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                 const struct ldb_attrib_handler *h;
77                 /* this is rather ugly - a consequence of const handling */
78                 h = ldb_attrib_handler(module->ldb, msg->elements[i].name);
79                 ldb_remove_attrib_handler(module->ldb, msg->elements[i].name);
80                 if (strcmp(h->attr, msg->elements[i].name) == 0) {
81                         talloc_steal(msg, h->attr);
82                 }
83         }
84
85         talloc_free(ltdb->cache->attributes);
86         ltdb->cache->attributes = NULL;
87 }
88
89 /*
90   add up the attrib flags for a @ATTRIBUTES element
91 */
92 static int ltdb_attributes_flags(struct ldb_message_element *el, unsigned *v)
93 {
94         int i;
95         unsigned value = 0;
96         for (i=0;i<el->num_values;i++) {
97                 int j;
98                 for (j=0;ltdb_valid_attr_flags[j].name;j++) {
99                         if (strcmp(ltdb_valid_attr_flags[j].name, 
100                                    el->values[i].data) == 0) {
101                                 value |= ltdb_valid_attr_flags[j].value;
102                                 break;
103                         }
104                 }
105                 if (ltdb_valid_attr_flags[j].name == NULL) {
106                         return -1;
107                 }
108         }
109         *v = value;
110         return 0;
111 }
112
113 /*
114   register any special handlers from @ATTRIBUTES
115 */
116 static int ltdb_attributes_load(struct ldb_module *module)
117 {
118         struct ltdb_private *ltdb = module->private_data;
119         struct ldb_message *msg = ltdb->cache->attributes;
120         int i;
121
122         if (ltdb_search_dn1(module, LTDB_ATTRIBUTES, msg) == -1) {
123                 goto failed;
124         }
125         /* mapping these flags onto ldap 'syntaxes' isn't strictly correct,
126            but its close enough for now */
127         for (i=0;i<msg->num_elements;i++) {
128                 unsigned flags;
129                 const char *syntax;
130                 const struct ldb_attrib_handler *h;
131                 struct ldb_attrib_handler h2;
132
133                 if (ltdb_attributes_flags(&msg->elements[i], &flags) != 0) {
134                         ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Invalid @ATTRIBUTES element for '%s'\n", msg->elements[i].name);
135                         goto failed;
136                 }
137                 switch (flags & ~LTDB_FLAG_HIDDEN) {
138                 case 0:
139                         syntax = LDB_SYNTAX_OCTET_STRING;
140                         break;
141                 case LTDB_FLAG_WILDCARD:
142                 case LTDB_FLAG_WILDCARD | LTDB_FLAG_CASE_INSENSITIVE:
143                         syntax = LDB_SYNTAX_WILDCARD;
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;
156                 }
157
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;
164                 }
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;
169                 }
170         }
171
172         return 0;
173 failed:
174         return -1;
175 }
176
177
178 /*
179   register any subclasses from @SUBCLASSES
180 */
181 static int ltdb_subclasses_load(struct ldb_module *module)
182 {
183         struct ltdb_private *ltdb = module->private_data;
184         struct ldb_message *msg = ltdb->cache->subclasses;
185         int i, j;
186
187         if (ltdb_search_dn1(module, LTDB_SUBCLASSES, msg) == -1) {
188                 goto failed;
189         }
190
191         for (i=0;i<msg->num_elements;i++) {
192                 struct ldb_message_element *el = &msg->elements[i];
193                 for (j=0;j<el->num_values;j++) {
194                         if (ldb_subclass_add(module->ldb, el->name, el->values[j].data) != 0) {
195                                 goto failed;
196                         }
197                 }
198         }
199
200         return 0;
201 failed:
202         return -1;
203 }
204
205
206 /*
207   de-register any @SUBCLASSES
208 */
209 static void ltdb_subclasses_unload(struct ldb_module *module)
210 {
211         struct ltdb_private *ltdb = module->private_data;
212         struct ldb_message *msg;
213         int i;
214
215         if (ltdb->cache->subclasses == NULL) {
216                 /* no previously loaded subclasses */
217                 return;
218         }
219
220         msg = ltdb->cache->subclasses;
221         for (i=0;i<msg->num_elements;i++) {
222                 ldb_subclass_remove(module->ldb, msg->elements[i].name);
223         }
224
225         talloc_free(ltdb->cache->subclasses);
226         ltdb->cache->subclasses = NULL;
227 }
228
229
230 /*
231   initialise the baseinfo record
232 */
233 static int ltdb_baseinfo_init(struct ldb_module *module)
234 {
235         struct ltdb_private *ltdb = module->private_data;
236         struct ldb_message *msg;
237         struct ldb_message_element el;
238         struct ldb_val val;
239         int ret;
240         /* the initial sequence number must be different from the one
241            set in ltdb_cache_free(). Thanks to Jon for pointing this
242            out. */
243         const char *initial_sequence_number = "1";
244
245         ltdb->sequence_number = atof(initial_sequence_number);
246
247         msg = talloc(ltdb, struct ldb_message);
248         if (msg == NULL) {
249                 goto failed;
250         }
251
252         msg->num_elements = 1;
253         msg->elements = &el;
254         msg->dn = talloc_strdup(msg, LTDB_BASEINFO);
255         if (!msg->dn) {
256                 goto failed;
257         }
258         el.name = talloc_strdup(msg, LTDB_SEQUENCE_NUMBER);
259         if (!el.name) {
260                 goto failed;
261         }
262         el.values = &val;
263         el.num_values = 1;
264         el.flags = 0;
265         val.data = talloc_strdup(msg, initial_sequence_number);
266         if (!val.data) {
267                 goto failed;
268         }
269         val.length = 1;
270         
271         ret = ltdb_store(module, msg, TDB_INSERT);
272
273         talloc_free(msg);
274
275         return ret;
276
277 failed:
278         talloc_free(msg);
279         errno = ENOMEM;
280         return -1;
281 }
282
283 /*
284   free any cache records
285  */
286 static void ltdb_cache_free(struct ldb_module *module)
287 {
288         struct ltdb_private *ltdb = module->private_data;
289
290         ltdb->sequence_number = 0;
291         talloc_free(ltdb->cache);
292         ltdb->cache = NULL;
293 }
294
295 /*
296   force a cache reload
297 */
298 int ltdb_cache_reload(struct ldb_module *module)
299 {
300         ltdb_attributes_unload(module);
301         ltdb_subclasses_unload(module);
302         ltdb_cache_free(module);
303         return ltdb_cache_load(module);
304 }
305
306 /*
307   load the cache records
308 */
309 int ltdb_cache_load(struct ldb_module *module)
310 {
311         struct ltdb_private *ltdb = module->private_data;
312         double seq;
313
314         if (ltdb->cache == NULL) {
315                 ltdb->cache = talloc_zero(ltdb, struct ltdb_cache);
316                 if (ltdb->cache == NULL) goto failed;
317                 ltdb->cache->indexlist = talloc_zero(ltdb->cache, struct ldb_message);
318                 ltdb->cache->subclasses = talloc_zero(ltdb->cache, struct ldb_message);
319                 ltdb->cache->attributes = talloc_zero(ltdb->cache, struct ldb_message);
320                 if (ltdb->cache->indexlist == NULL ||
321                     ltdb->cache->subclasses == NULL ||
322                     ltdb->cache->attributes == NULL) {
323                         goto failed;
324                 }
325         }
326
327         talloc_free(ltdb->cache->baseinfo);
328         ltdb->cache->baseinfo = talloc(ltdb->cache, struct ldb_message);
329         if (ltdb->cache->baseinfo == NULL) goto failed;
330         
331         if (ltdb_search_dn1(module, LTDB_BASEINFO, ltdb->cache->baseinfo) == -1) {
332                 goto failed;
333         }
334         
335         /* possibly initialise the baseinfo */
336         if (!ltdb->cache->baseinfo->dn) {
337                 if (ltdb_baseinfo_init(module) != 0) {
338                         goto failed;
339                 }
340                 if (ltdb_search_dn1(module, LTDB_BASEINFO, ltdb->cache->baseinfo) != 1) {
341                         goto failed;
342                 }
343         }
344
345         /* if the current internal sequence number is the same as the one
346            in the database then assume the rest of the cache is OK */
347         seq = ldb_msg_find_double(ltdb->cache->baseinfo, LTDB_SEQUENCE_NUMBER, 0);
348         if (seq == ltdb->sequence_number) {
349                 goto done;
350         }
351         ltdb->sequence_number = seq;
352
353         talloc_free(ltdb->cache->last_attribute.name);
354         memset(&ltdb->cache->last_attribute, 0, sizeof(ltdb->cache->last_attribute));
355
356         ltdb_attributes_unload(module);
357         ltdb_subclasses_unload(module);
358
359         talloc_free(ltdb->cache->indexlist);
360         talloc_free(ltdb->cache->subclasses);
361
362         ltdb->cache->indexlist = talloc_zero(ltdb->cache, struct ldb_message);
363         ltdb->cache->subclasses = talloc_zero(ltdb->cache, struct ldb_message);
364         ltdb->cache->attributes = talloc_zero(ltdb->cache, struct ldb_message);
365         if (ltdb->cache->indexlist == NULL ||
366             ltdb->cache->subclasses == NULL ||
367             ltdb->cache->attributes == NULL) {
368                 goto failed;
369         }
370             
371         if (ltdb_search_dn1(module, LTDB_INDEXLIST, ltdb->cache->indexlist) == -1) {
372                 goto failed;
373         }
374
375         if (ltdb_attributes_load(module) == -1) {
376                 goto failed;
377         }
378         if (ltdb_subclasses_load(module) == -1) {
379                 goto failed;
380         }
381
382 done:
383         return 0;
384
385 failed:
386         return -1;
387 }
388
389
390 /*
391   increase the sequence number to indicate a database change
392 */
393 int ltdb_increase_sequence_number(struct ldb_module *module)
394 {
395         struct ltdb_private *ltdb = module->private_data;
396         struct ldb_message *msg;
397         struct ldb_message_element el;
398         struct ldb_val val;
399         char *s = NULL;
400         int ret;
401
402         msg = talloc(ltdb, struct ldb_message);
403         if (msg == NULL) {
404                 errno = ENOMEM;
405                 return -1;
406         }
407
408         s = talloc_asprintf(msg, "%.0f", ltdb->sequence_number+1);
409         if (!s) {
410                 errno = ENOMEM;
411                 return -1;
412         }
413
414         msg->num_elements = 1;
415         msg->elements = &el;
416         msg->dn = talloc_strdup(msg, LTDB_BASEINFO);
417         el.name = talloc_strdup(msg, LTDB_SEQUENCE_NUMBER);
418         el.values = &val;
419         el.num_values = 1;
420         el.flags = LDB_FLAG_MOD_REPLACE;
421         val.data = s;
422         val.length = strlen(s);
423
424         ret = ltdb_modify_internal(module, msg);
425
426         talloc_free(msg);
427
428         if (ret == 0) {
429                 ltdb->sequence_number += 1;
430         }
431
432         return ret;
433 }
434
435
436 /*
437   return the attribute flags from the @ATTRIBUTES record 
438   for the given attribute
439 */
440 int ltdb_attribute_flags(struct ldb_module *module, const char *attr_name)
441 {
442         struct ltdb_private *ltdb = module->private_data;
443         const struct ldb_message_element *attr_el;
444         int i, j, ret=0;
445
446         if (ltdb->cache->last_attribute.name &&
447             ldb_attr_cmp(ltdb->cache->last_attribute.name, attr_name) == 0) {
448                 return ltdb->cache->last_attribute.flags;
449         }
450
451         /* objectclass is a special default case */
452         if (ldb_attr_cmp(attr_name, LTDB_OBJECTCLASS) == 0) {
453                 ret = LTDB_FLAG_OBJECTCLASS | LTDB_FLAG_CASE_INSENSITIVE;
454         }
455
456         attr_el = ldb_msg_find_element(ltdb->cache->attributes, attr_name);
457
458         if (!attr_el) {
459                 /* check if theres a wildcard attribute */
460                 attr_el = ldb_msg_find_element(ltdb->cache->attributes, "*");
461
462                 if (!attr_el) {
463                         return ret;
464                 }
465         }
466
467         for (i = 0; i < attr_el->num_values; i++) {
468                 for (j=0; ltdb_valid_attr_flags[j].name; j++) {
469                         if (strcmp(ltdb_valid_attr_flags[j].name, 
470                                    attr_el->values[i].data) == 0) {
471                                 ret |= ltdb_valid_attr_flags[j].value;
472                         }
473                 }
474         }
475
476         talloc_free(ltdb->cache->last_attribute.name);
477
478         ltdb->cache->last_attribute.name = talloc_strdup(ltdb->cache, attr_name);
479         ltdb->cache->last_attribute.flags = ret;
480
481         return ret;
482 }
483
484 int ltdb_check_at_attributes_values(const struct ldb_val *value)
485 {
486         int i;
487
488         for (i = 0; ltdb_valid_attr_flags[i].name != NULL; i++) {
489                 if ((strcmp(ltdb_valid_attr_flags[i].name, value->data) == 0)) {
490                         return 0;
491                 }
492         }
493
494         return -1;
495 }
496