• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/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 search functions
28 *
29 *  Description: functions to search ldb+tdb databases
30 *
31 *  Author: Andrew Tridgell
32 */
33
34#include "ldb_tdb.h"
35
36/*
37  add one element to a message
38*/
39static int msg_add_element(struct ldb_message *ret,
40			   const struct ldb_message_element *el,
41			   int check_duplicates)
42{
43	unsigned int i;
44	struct ldb_message_element *e2, *elnew;
45
46	if (check_duplicates && ldb_msg_find_element(ret, el->name)) {
47		/* its already there */
48		return 0;
49	}
50
51	e2 = talloc_realloc(ret, ret->elements, struct ldb_message_element, ret->num_elements+1);
52	if (!e2) {
53		return -1;
54	}
55	ret->elements = e2;
56
57	elnew = &e2[ret->num_elements];
58
59	elnew->name = talloc_strdup(ret->elements, el->name);
60	if (!elnew->name) {
61		return -1;
62	}
63
64	if (el->num_values) {
65		elnew->values = talloc_array(ret->elements, struct ldb_val, el->num_values);
66		if (!elnew->values) {
67			return -1;
68		}
69	} else {
70		elnew->values = NULL;
71	}
72
73	for (i=0;i<el->num_values;i++) {
74		elnew->values[i] = ldb_val_dup(elnew->values, &el->values[i]);
75		if (elnew->values[i].length != el->values[i].length) {
76			return -1;
77		}
78	}
79
80	elnew->num_values = el->num_values;
81
82	ret->num_elements++;
83
84	return 0;
85}
86
87/*
88  add the special distinguishedName element
89*/
90static int msg_add_distinguished_name(struct ldb_message *msg)
91{
92	struct ldb_message_element el;
93	struct ldb_val val;
94	int ret;
95
96	el.flags = 0;
97	el.name = "distinguishedName";
98	el.num_values = 1;
99	el.values = &val;
100	val.data = (uint8_t *)ldb_dn_alloc_linearized(msg, msg->dn);
101	val.length = strlen((char *)val.data);
102
103	ret = msg_add_element(msg, &el, 1);
104	return ret;
105}
106
107/*
108  add all elements from one message into another
109 */
110static int msg_add_all_elements(struct ldb_module *module, struct ldb_message *ret,
111				const struct ldb_message *msg)
112{
113	struct ldb_context *ldb;
114	unsigned int i;
115	int check_duplicates = (ret->num_elements != 0);
116
117	ldb = ldb_module_get_ctx(module);
118
119	if (msg_add_distinguished_name(ret) != 0) {
120		return -1;
121	}
122
123	for (i=0;i<msg->num_elements;i++) {
124		const struct ldb_schema_attribute *a;
125		a = ldb_schema_attribute_by_name(ldb, msg->elements[i].name);
126		if (a->flags & LDB_ATTR_FLAG_HIDDEN) {
127			continue;
128		}
129		if (msg_add_element(ret, &msg->elements[i],
130				    check_duplicates) != 0) {
131			return -1;
132		}
133	}
134
135	return 0;
136}
137
138
139/*
140  pull the specified list of attributes from a message
141 */
142static struct ldb_message *ltdb_pull_attrs(struct ldb_module *module,
143					   TALLOC_CTX *mem_ctx,
144					   const struct ldb_message *msg,
145					   const char * const *attrs)
146{
147	struct ldb_message *ret;
148	int i;
149
150	ret = talloc(mem_ctx, struct ldb_message);
151	if (!ret) {
152		return NULL;
153	}
154
155	ret->dn = ldb_dn_copy(ret, msg->dn);
156	if (!ret->dn) {
157		talloc_free(ret);
158		return NULL;
159	}
160
161	ret->num_elements = 0;
162	ret->elements = NULL;
163
164	if (!attrs) {
165		if (msg_add_all_elements(module, ret, msg) != 0) {
166			talloc_free(ret);
167			return NULL;
168		}
169		return ret;
170	}
171
172	for (i=0;attrs[i];i++) {
173		struct ldb_message_element *el;
174
175		if (strcmp(attrs[i], "*") == 0) {
176			if (msg_add_all_elements(module, ret, msg) != 0) {
177				talloc_free(ret);
178				return NULL;
179			}
180			continue;
181		}
182
183		if (ldb_attr_cmp(attrs[i], "distinguishedName") == 0) {
184			if (msg_add_distinguished_name(ret) != 0) {
185				return NULL;
186			}
187			continue;
188		}
189
190		el = ldb_msg_find_element(msg, attrs[i]);
191		if (!el) {
192			continue;
193		}
194		if (msg_add_element(ret, el, 1) != 0) {
195			talloc_free(ret);
196			return NULL;
197		}
198	}
199
200	return ret;
201}
202
203/*
204  search the database for a single simple dn.
205  return LDB_ERR_NO_SUCH_OBJECT on record-not-found
206  and LDB_SUCCESS on success
207*/
208static int ltdb_search_base(struct ldb_module *module, struct ldb_dn *dn)
209{
210	void *data = ldb_module_get_private(module);
211	struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
212	TDB_DATA tdb_key, tdb_data;
213
214	if (ldb_dn_is_null(dn)) {
215		return LDB_ERR_NO_SUCH_OBJECT;
216	}
217
218	/* form the key */
219	tdb_key = ltdb_key(module, dn);
220	if (!tdb_key.dptr) {
221		return LDB_ERR_OPERATIONS_ERROR;
222	}
223
224	tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
225	talloc_free(tdb_key.dptr);
226	if (!tdb_data.dptr) {
227		return LDB_ERR_NO_SUCH_OBJECT;
228	}
229
230	free(tdb_data.dptr);
231	return LDB_SUCCESS;
232}
233
234/*
235  search the database for a single simple dn, returning all attributes
236  in a single message
237
238  return LDB_ERR_NO_SUCH_OBJECT on record-not-found
239  and LDB_SUCCESS on success
240*/
241int ltdb_search_dn1(struct ldb_module *module, struct ldb_dn *dn, struct ldb_message *msg)
242{
243	void *data = ldb_module_get_private(module);
244	struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
245	int ret;
246	TDB_DATA tdb_key, tdb_data;
247
248	memset(msg, 0, sizeof(*msg));
249
250	/* form the key */
251	tdb_key = ltdb_key(module, dn);
252	if (!tdb_key.dptr) {
253		return LDB_ERR_OPERATIONS_ERROR;
254	}
255
256	tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
257	talloc_free(tdb_key.dptr);
258	if (!tdb_data.dptr) {
259		return LDB_ERR_NO_SUCH_OBJECT;
260	}
261
262	msg->num_elements = 0;
263	msg->elements = NULL;
264
265	ret = ltdb_unpack_data(module, &tdb_data, msg);
266	free(tdb_data.dptr);
267	if (ret == -1) {
268		struct ldb_context *ldb = ldb_module_get_ctx(module);
269		ldb_debug(ldb, LDB_DEBUG_ERROR, "Invalid data for index %s\n",
270			  ldb_dn_get_linearized(msg->dn));
271		return LDB_ERR_OPERATIONS_ERROR;
272	}
273
274	if (!msg->dn) {
275		msg->dn = ldb_dn_copy(msg, dn);
276	}
277	if (!msg->dn) {
278		return LDB_ERR_OPERATIONS_ERROR;
279	}
280
281	return LDB_SUCCESS;
282}
283
284/*
285  add a set of attributes from a record to a set of results
286  return 0 on success, -1 on failure
287*/
288int ltdb_add_attr_results(struct ldb_module *module,
289			  TALLOC_CTX *mem_ctx,
290			  struct ldb_message *msg,
291			  const char * const attrs[],
292			  unsigned int *count,
293			  struct ldb_message ***res)
294{
295	struct ldb_message *msg2;
296	struct ldb_message **res2;
297
298	/* pull the attributes that the user wants */
299	msg2 = ltdb_pull_attrs(module, mem_ctx, msg, attrs);
300	if (!msg2) {
301		return -1;
302	}
303
304	/* add to the results list */
305	res2 = talloc_realloc(mem_ctx, *res, struct ldb_message *, (*count)+2);
306	if (!res2) {
307		talloc_free(msg2);
308		return -1;
309	}
310
311	(*res) = res2;
312
313	(*res)[*count] = talloc_move(*res, &msg2);
314	(*res)[(*count)+1] = NULL;
315	(*count)++;
316
317	return 0;
318}
319
320
321
322/*
323  filter the specified list of attributes from a message
324  removing not requested attrs.
325 */
326int ltdb_filter_attrs(struct ldb_message *msg, const char * const *attrs)
327{
328	int i, keep_all = 0;
329
330	if (attrs) {
331		/* check for special attrs */
332		for (i = 0; attrs[i]; i++) {
333			if (strcmp(attrs[i], "*") == 0) {
334				keep_all = 1;
335				break;
336			}
337
338			if (ldb_attr_cmp(attrs[i], "distinguishedName") == 0) {
339				if (msg_add_distinguished_name(msg) != 0) {
340					return -1;
341				}
342			}
343		}
344	} else {
345		keep_all = 1;
346	}
347
348	if (keep_all) {
349		if (msg_add_distinguished_name(msg) != 0) {
350			return -1;
351		}
352		return 0;
353	}
354
355	for (i = 0; i < msg->num_elements; i++) {
356		int j, found;
357
358		for (j = 0, found = 0; attrs[j]; j++) {
359			if (ldb_attr_cmp(msg->elements[i].name, attrs[j]) == 0) {
360				found = 1;
361				break;
362			}
363		}
364
365		if (!found) {
366			ldb_msg_remove_attr(msg, msg->elements[i].name);
367			i--;
368		}
369	}
370
371	return 0;
372}
373
374/*
375  search function for a non-indexed search
376 */
377static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
378{
379	struct ldb_context *ldb;
380	struct ltdb_context *ac;
381	struct ldb_message *msg;
382	int ret;
383
384	ac = talloc_get_type(state, struct ltdb_context);
385	ldb = ldb_module_get_ctx(ac->module);
386
387	if (key.dsize < 4 ||
388	    strncmp((char *)key.dptr, "DN=", 3) != 0) {
389		return 0;
390	}
391
392	msg = ldb_msg_new(ac);
393	if (!msg) {
394		return -1;
395	}
396
397	/* unpack the record */
398	ret = ltdb_unpack_data(ac->module, &data, msg);
399	if (ret == -1) {
400		talloc_free(msg);
401		return -1;
402	}
403
404	if (!msg->dn) {
405		msg->dn = ldb_dn_new(msg, ldb,
406				     (char *)key.dptr + 3);
407		if (msg->dn == NULL) {
408			talloc_free(msg);
409			return -1;
410		}
411	}
412
413	/* see if it matches the given expression */
414	if (!ldb_match_msg(ldb, msg,
415			   ac->tree, ac->base, ac->scope)) {
416		talloc_free(msg);
417		return 0;
418	}
419
420	/* filter the attributes that the user wants */
421	ret = ltdb_filter_attrs(msg, ac->attrs);
422
423	if (ret == -1) {
424		talloc_free(msg);
425		return -1;
426	}
427
428	ret = ldb_module_send_entry(ac->req, msg, NULL);
429	if (ret != LDB_SUCCESS) {
430		ac->request_terminated = true;
431		/* the callback failed, abort the operation */
432		return -1;
433	}
434
435	return 0;
436}
437
438
439/*
440  search the database with a LDAP-like expression.
441  this is the "full search" non-indexed variant
442*/
443static int ltdb_search_full(struct ltdb_context *ctx)
444{
445	void *data = ldb_module_get_private(ctx->module);
446	struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
447	int ret;
448
449	if (ltdb->in_transaction != 0) {
450		ret = tdb_traverse(ltdb->tdb, search_func, ctx);
451	} else {
452		ret = tdb_traverse_read(ltdb->tdb, search_func, ctx);
453	}
454
455	if (ret == -1) {
456		return LDB_ERR_OPERATIONS_ERROR;
457	}
458
459	return LDB_SUCCESS;
460}
461
462/*
463  search the database with a LDAP-like expression.
464  choses a search method
465*/
466int ltdb_search(struct ltdb_context *ctx)
467{
468	struct ldb_context *ldb;
469	struct ldb_module *module = ctx->module;
470	struct ldb_request *req = ctx->req;
471	void *data = ldb_module_get_private(module);
472	struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
473	int ret;
474
475	ldb = ldb_module_get_ctx(module);
476
477	ldb_request_set_state(req, LDB_ASYNC_PENDING);
478
479	if (ltdb_lock_read(module) != 0) {
480		return LDB_ERR_OPERATIONS_ERROR;
481	}
482
483	if (ltdb_cache_load(module) != 0) {
484		ltdb_unlock_read(module);
485		return LDB_ERR_OPERATIONS_ERROR;
486	}
487
488	if (req->op.search.tree == NULL) {
489		ltdb_unlock_read(module);
490		return LDB_ERR_OPERATIONS_ERROR;
491	}
492
493	if ((req->op.search.base == NULL) || (ldb_dn_is_null(req->op.search.base) == true)) {
494
495		/* Check what we should do with a NULL dn */
496		switch (req->op.search.scope) {
497		case LDB_SCOPE_BASE:
498			ldb_asprintf_errstring(ldb,
499					       "NULL Base DN invalid for a base search");
500			ret = LDB_ERR_INVALID_DN_SYNTAX;
501			break;
502		case LDB_SCOPE_ONELEVEL:
503			ldb_asprintf_errstring(ldb,
504					       "NULL Base DN invalid for a one-level search");
505			ret = LDB_ERR_INVALID_DN_SYNTAX;
506			break;
507		case LDB_SCOPE_SUBTREE:
508		default:
509			/* We accept subtree searches from a NULL base DN, ie over the whole DB */
510			ret = LDB_SUCCESS;
511		}
512	} else if (ldb_dn_is_valid(req->op.search.base) == false) {
513
514		/* We don't want invalid base DNs here */
515		ldb_asprintf_errstring(ldb,
516				       "Invalid Base DN: %s",
517				       ldb_dn_get_linearized(req->op.search.base));
518		ret = LDB_ERR_INVALID_DN_SYNTAX;
519
520	} else if (ltdb->check_base) {
521		/* This database has been marked as 'checkBaseOnSearch', so do a spot check of the base dn */
522		ret = ltdb_search_base(module, req->op.search.base);
523
524		if (ret == LDB_ERR_NO_SUCH_OBJECT) {
525			ldb_asprintf_errstring(ldb,
526					       "No such Base DN: %s",
527					       ldb_dn_get_linearized(req->op.search.base));
528		}
529
530	} else {
531		/* If we are not checking the base DN life is easy */
532		ret = LDB_SUCCESS;
533	}
534
535	ctx->tree = req->op.search.tree;
536	ctx->scope = req->op.search.scope;
537	ctx->base = req->op.search.base;
538	ctx->attrs = req->op.search.attrs;
539
540	if (ret == LDB_SUCCESS) {
541		uint32_t match_count = 0;
542
543		ret = ltdb_search_indexed(ctx, &match_count);
544		if (ret == LDB_ERR_NO_SUCH_OBJECT) {
545			/* Not in the index, therefore OK! */
546			ret = LDB_SUCCESS;
547
548		}
549		/* Check if we got just a normal error.
550		 * In that case proceed to a full search unless we got a
551		 * callback error */
552		if ( ! ctx->request_terminated && ret != LDB_SUCCESS) {
553			/* Not indexed, so we need to do a full scan */
554#if 0
555			/* useful for debugging when slow performance
556			 * is caused by unindexed searches */
557			char *expression = ldb_filter_from_tree(ctx, ctx->tree);
558			printf("FULL SEARCH: %s\n", expression);
559			talloc_free(expression);
560#endif
561			if (match_count != 0) {
562				/* the indexing code gave an error
563				 * after having returned at least one
564				 * entry. This means the indexes are
565				 * corrupt or a database record is
566				 * corrupt. We cannot continue with a
567				 * full search or we may return
568				 * duplicate entries
569				 */
570				return LDB_ERR_OPERATIONS_ERROR;
571			}
572			ret = ltdb_search_full(ctx);
573			if (ret != LDB_SUCCESS) {
574				ldb_set_errstring(ldb, "Indexed and full searches both failed!\n");
575			}
576		}
577	}
578
579	ltdb_unlock_read(module);
580
581	return ret;
582}
583
584