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