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