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