r4486: fixed some memory leaks in the new ldb code, by ensuring that memory is always
[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 "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 /*
41   initialise the baseinfo record
42 */
43 static int ltdb_baseinfo_init(struct ldb_module *module)
44 {
45         struct ltdb_private *ltdb = module->private_data;
46         struct ldb_message *msg;
47         struct ldb_message_element el;
48         struct ldb_val val;
49         int ret;
50         /* the initial sequence number must be different from the one
51            set in ltdb_cache_free(). Thanks to Jon for pointing this
52            out. */
53         const char *initial_sequence_number = "1";
54
55         ltdb->sequence_number = atof(initial_sequence_number);
56
57         msg = talloc_p(ltdb, struct ldb_message);
58         if (msg == NULL) {
59                 goto failed;
60         }
61
62         msg->num_elements = 1;
63         msg->elements = ⪙
64         msg->dn = talloc_strdup(msg, LTDB_BASEINFO);
65         if (!msg->dn) {
66                 goto failed;
67         }
68         el.name = talloc_strdup(msg, LTDB_SEQUENCE_NUMBER);
69         if (!el.name) {
70                 goto failed;
71         }
72         el.values = &val;
73         el.num_values = 1;
74         el.flags = 0;
75         val.data = talloc_strdup(msg, initial_sequence_number);
76         if (!val.data) {
77                 goto failed;
78         }
79         val.length = 1;
80         
81         ret = ltdb_store(module, msg, TDB_INSERT);
82
83         talloc_free(msg);
84
85         return ret;
86
87 failed:
88         talloc_free(msg);
89         errno = ENOMEM;
90         return -1;
91 }
92
93 /*
94   free any cache records
95  */
96 static void ltdb_cache_free(struct ldb_module *module)
97 {
98         struct ltdb_private *ltdb = module->private_data;
99
100         ltdb->sequence_number = 0;
101         talloc_free(ltdb->cache);
102         ltdb->cache = NULL;
103 }
104
105 /*
106   force a cache reload
107 */
108 int ltdb_cache_reload(struct ldb_module *module)
109 {
110         ltdb_cache_free(module);
111         return ltdb_cache_load(module);
112 }
113
114 /*
115   load the cache records
116 */
117 int ltdb_cache_load(struct ldb_module *module)
118 {
119         struct ltdb_private *ltdb = module->private_data;
120         double seq;
121
122         if (ltdb->cache == NULL) {
123                 ltdb->cache = talloc_zero_p(ltdb, struct ltdb_cache);
124                 if (ltdb->cache == NULL) goto failed;
125                 ltdb->cache->indexlist = talloc_zero_p(ltdb->cache, struct ldb_message);
126                 ltdb->cache->subclasses = talloc_zero_p(ltdb->cache, struct ldb_message);
127                 ltdb->cache->attributes = talloc_zero_p(ltdb->cache, struct ldb_message);
128                 if (ltdb->cache->indexlist == NULL ||
129                     ltdb->cache->subclasses == NULL ||
130                     ltdb->cache->attributes == NULL) {
131                         goto failed;
132                 }
133         }
134
135         talloc_free(ltdb->cache->baseinfo);
136         ltdb->cache->baseinfo = talloc_p(ltdb->cache, struct ldb_message);
137         if (ltdb->cache->baseinfo == NULL) goto failed;
138         
139         if (ltdb_search_dn1(module, LTDB_BASEINFO, ltdb->cache->baseinfo) == -1) {
140                 goto failed;
141         }
142         
143         /* possibly initialise the baseinfo */
144         if (!ltdb->cache->baseinfo->dn) {
145                 if (ltdb_baseinfo_init(module) != 0) {
146                         goto failed;
147                 }
148                 if (ltdb_search_dn1(module, LTDB_BASEINFO, ltdb->cache->baseinfo) != 1) {
149                         goto failed;
150                 }
151         }
152
153         /* if the current internal sequence number is the same as the one
154            in the database then assume the rest of the cache is OK */
155         seq = ldb_msg_find_double(ltdb->cache->baseinfo, LTDB_SEQUENCE_NUMBER, 0);
156         if (seq == ltdb->sequence_number) {
157                 goto done;
158         }
159         ltdb->sequence_number = seq;
160
161         talloc_free(ltdb->cache->last_attribute.name);
162         memset(&ltdb->cache->last_attribute, 0, sizeof(ltdb->cache->last_attribute));
163
164         talloc_free(ltdb->cache->indexlist);
165         talloc_free(ltdb->cache->subclasses);
166         talloc_free(ltdb->cache->attributes);
167
168         ltdb->cache->indexlist = talloc_zero_p(ltdb->cache, struct ldb_message);
169         ltdb->cache->subclasses = talloc_zero_p(ltdb->cache, struct ldb_message);
170         ltdb->cache->attributes = talloc_zero_p(ltdb->cache, struct ldb_message);
171         if (ltdb->cache->indexlist == NULL ||
172             ltdb->cache->subclasses == NULL ||
173             ltdb->cache->attributes == NULL) {
174                 goto failed;
175         }
176             
177         if (ltdb_search_dn1(module, LTDB_INDEXLIST, ltdb->cache->indexlist) == -1) {
178                 goto failed;
179         }
180         if (ltdb_search_dn1(module, LTDB_SUBCLASSES, ltdb->cache->subclasses) == -1) {
181                 goto failed;
182         }
183         if (ltdb_search_dn1(module, LTDB_ATTRIBUTES, ltdb->cache->attributes) == -1) {
184                 goto failed;
185         }
186
187 done:
188         return 0;
189
190 failed:
191         return -1;
192 }
193
194
195 /*
196   increase the sequence number to indicate a database change
197 */
198 int ltdb_increase_sequence_number(struct ldb_module *module)
199 {
200         struct ldb_context *ldb = module->ldb;
201         struct ltdb_private *ltdb = module->private_data;
202         struct ldb_message *msg;
203         struct ldb_message_element el;
204         struct ldb_val val;
205         char *s = NULL;
206         int ret;
207
208         msg = talloc_p(ltdb, struct ldb_message);
209         if (msg == NULL) {
210                 errno = ENOMEM;
211                 return -1;
212         }
213
214         s = talloc_asprintf(msg, "%.0f", ltdb->sequence_number+1);
215         if (!s) {
216                 errno = ENOMEM;
217                 return -1;
218         }
219
220         msg->num_elements = 1;
221         msg->elements = ⪙
222         msg->dn = talloc_strdup(msg, LTDB_BASEINFO);
223         el.name = talloc_strdup(msg, LTDB_SEQUENCE_NUMBER);
224         el.values = &val;
225         el.num_values = 1;
226         el.flags = LDB_FLAG_MOD_REPLACE;
227         val.data = s;
228         val.length = strlen(s);
229
230         ret = ltdb_modify_internal(module, msg);
231
232         talloc_free(msg);
233
234         if (ret == 0) {
235                 ltdb->sequence_number += 1;
236         }
237
238         return ret;
239 }
240
241
242 /*
243   return the attribute flags from the @ATTRIBUTES record 
244   for the given attribute
245 */
246 int ltdb_attribute_flags(struct ldb_module *module, const char *attr_name)
247 {
248         struct ltdb_private *ltdb = module->private_data;
249         const char *attrs;
250         const struct {
251                 const char *name;
252                 int value;
253         } names[] = {
254                 { "CASE_INSENSITIVE", LTDB_FLAG_CASE_INSENSITIVE },
255                 { "INTEGER", LTDB_FLAG_INTEGER },
256                 { "WILDCARD", LTDB_FLAG_WILDCARD },
257                 { "HIDDEN", LTDB_FLAG_HIDDEN },
258                 { NULL, 0}
259         };
260         size_t len;
261         int i, ret=0;
262
263         if (ltdb->cache->last_attribute.name &&
264             ldb_attr_cmp(ltdb->cache->last_attribute.name, attr_name) == 0) {
265                 return ltdb->cache->last_attribute.flags;
266         }
267
268         /* objectclass is a special default case */
269         if (ldb_attr_cmp(attr_name, LTDB_OBJECTCLASS) == 0) {
270                 ret = LTDB_FLAG_OBJECTCLASS | LTDB_FLAG_CASE_INSENSITIVE;
271         }
272
273         attrs = ldb_msg_find_string(ltdb->cache->attributes, attr_name, NULL);
274
275         if (!attrs) {
276                 return ret;
277         }
278
279         /* we avoid using strtok and friends due to their nasty
280            interface. This is a little trickier, but much nicer
281            from a C interface point of view */
282         while ((len = strcspn(attrs, " ,")) > 0) {
283                 for (i=0;names[i].name;i++) {
284                         if (strncmp(names[i].name, attrs, len) == 0 &&
285                             names[i].name[len] == 0) {
286                                 ret |= names[i].value;
287                         }
288                 }
289                 attrs += len;
290                 attrs += strspn(attrs, " ,");
291         }
292
293         talloc_free(ltdb->cache->last_attribute.name);
294
295         ltdb->cache->last_attribute.name = talloc_strdup(ltdb->cache, attr_name);
296         ltdb->cache->last_attribute.flags = ret;
297
298         return ret;
299 }