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