• 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/source3/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 "includes.h"
35#include "ldb/include/includes.h"
36
37#include "ldb/ldb_tdb/ldb_tdb.h"
38
39/*
40  add one element to a message
41*/
42static int msg_add_element(struct ldb_message *ret,
43			   const struct ldb_message_element *el,
44			   int check_duplicates)
45{
46	unsigned int i;
47	struct ldb_message_element *e2, *elnew;
48
49	if (check_duplicates && ldb_msg_find_element(ret, el->name)) {
50		/* its already there */
51		return 0;
52	}
53
54	e2 = talloc_realloc(ret, ret->elements, struct ldb_message_element, ret->num_elements+1);
55	if (!e2) {
56		return -1;
57	}
58	ret->elements = e2;
59
60	elnew = &e2[ret->num_elements];
61
62	elnew->name = talloc_strdup(ret->elements, el->name);
63	if (!elnew->name) {
64		return -1;
65	}
66
67	if (el->num_values) {
68		elnew->values = talloc_array(ret->elements, struct ldb_val, el->num_values);
69		if (!elnew->values) {
70			return -1;
71		}
72	} else {
73		elnew->values = NULL;
74	}
75
76	for (i=0;i<el->num_values;i++) {
77		elnew->values[i] = ldb_val_dup(elnew->values, &el->values[i]);
78		if (elnew->values[i].length != el->values[i].length) {
79			return -1;
80		}
81	}
82
83	elnew->num_values = el->num_values;
84
85	ret->num_elements++;
86
87	return 0;
88}
89
90/*
91  add the special distinguishedName element
92*/
93static int msg_add_distinguished_name(struct ldb_message *msg)
94{
95	struct ldb_message_element el;
96	struct ldb_val val;
97	int ret;
98
99	el.flags = 0;
100	el.name = "distinguishedName";
101	el.num_values = 1;
102	el.values = &val;
103	val.data = (uint8_t *)ldb_dn_linearize(msg, msg->dn);
104	val.length = strlen((char *)val.data);
105
106	ret = msg_add_element(msg, &el, 1);
107	return ret;
108}
109
110/*
111  add all elements from one message into another
112 */
113static int msg_add_all_elements(struct ldb_module *module, struct ldb_message *ret,
114				const struct ldb_message *msg)
115{
116	struct ldb_context *ldb = module->ldb;
117	unsigned int i;
118	int check_duplicates = (ret->num_elements != 0);
119
120	if (msg_add_distinguished_name(ret) != 0) {
121		return -1;
122	}
123
124	for (i=0;i<msg->num_elements;i++) {
125		const struct ldb_attrib_handler *h;
126		h = ldb_attrib_handler(ldb, msg->elements[i].name);
127		if (h->flags & LDB_ATTR_FLAG_HIDDEN) {
128			continue;
129		}
130		if (msg_add_element(ret, &msg->elements[i],
131				    check_duplicates) != 0) {
132			return -1;
133		}
134	}
135
136	return 0;
137}
138
139
140/*
141  pull the specified list of attributes from a message
142 */
143static struct ldb_message *ltdb_pull_attrs(struct ldb_module *module,
144					   TALLOC_CTX *mem_ctx,
145					   const struct ldb_message *msg,
146					   const char * const *attrs)
147{
148	struct ldb_message *ret;
149	int i;
150
151	ret = talloc(mem_ctx, struct ldb_message);
152	if (!ret) {
153		return NULL;
154	}
155
156	ret->dn = ldb_dn_copy(ret, msg->dn);
157	if (!ret->dn) {
158		talloc_free(ret);
159		return NULL;
160	}
161
162	ret->num_elements = 0;
163	ret->elements = NULL;
164
165	if (!attrs) {
166		if (msg_add_all_elements(module, ret, msg) != 0) {
167			talloc_free(ret);
168			return NULL;
169		}
170		return ret;
171	}
172
173	for (i=0;attrs[i];i++) {
174		struct ldb_message_element *el;
175
176		if (strcmp(attrs[i], "*") == 0) {
177			if (msg_add_all_elements(module, ret, msg) != 0) {
178				talloc_free(ret);
179				return NULL;
180			}
181			continue;
182		}
183
184		if (ldb_attr_cmp(attrs[i], "distinguishedName") == 0) {
185			if (msg_add_distinguished_name(ret) != 0) {
186				return NULL;
187			}
188			continue;
189		}
190
191		el = ldb_msg_find_element(msg, attrs[i]);
192		if (!el) {
193			continue;
194		}
195		if (msg_add_element(ret, el, 1) != 0) {
196			talloc_free(ret);
197			return NULL;
198		}
199	}
200
201	return ret;
202}
203
204
205/*
206  search the database for a single simple dn, returning all attributes
207  in a single message
208
209  return 1 on success, 0 on record-not-found and -1 on error
210*/
211int ltdb_search_dn1(struct ldb_module *module, const struct ldb_dn *dn, struct ldb_message *msg)
212{
213	struct ltdb_private *ltdb =
214		(struct ltdb_private *)module->private_data;
215	int ret;
216	TDB_DATA tdb_key, tdb_data;
217
218	memset(msg, 0, sizeof(*msg));
219
220	/* form the key */
221	tdb_key = ltdb_key(module, dn);
222	if (!tdb_key.dptr) {
223		return -1;
224	}
225
226	tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
227	talloc_free(tdb_key.dptr);
228	if (!tdb_data.dptr) {
229		return 0;
230	}
231
232	msg->num_elements = 0;
233	msg->elements = NULL;
234
235	ret = ltdb_unpack_data(module, &tdb_data, msg);
236	free(tdb_data.dptr);
237	if (ret == -1) {
238		return -1;
239	}
240
241	if (!msg->dn) {
242		msg->dn = ldb_dn_copy(msg, dn);
243	}
244	if (!msg->dn) {
245		return -1;
246	}
247
248	return 1;
249}
250
251/*
252  lock the database for read - use by ltdb_search
253*/
254static int ltdb_lock_read(struct ldb_module *module)
255{
256	struct ltdb_private *ltdb =
257		(struct ltdb_private *)module->private_data;
258	return tdb_lockall_read(ltdb->tdb);
259}
260
261/*
262  unlock the database after a ltdb_lock_read()
263*/
264static int ltdb_unlock_read(struct ldb_module *module)
265{
266	struct ltdb_private *ltdb =
267		(struct ltdb_private *)module->private_data;
268	return tdb_unlockall_read(ltdb->tdb);
269}
270
271/*
272  add a set of attributes from a record to a set of results
273  return 0 on success, -1 on failure
274*/
275int ltdb_add_attr_results(struct ldb_module *module,
276			  TALLOC_CTX *mem_ctx,
277			  struct ldb_message *msg,
278			  const char * const attrs[],
279			  unsigned int *count,
280			  struct ldb_message ***res)
281{
282	struct ldb_message *msg2;
283	struct ldb_message **res2;
284
285	/* pull the attributes that the user wants */
286	msg2 = ltdb_pull_attrs(module, mem_ctx, msg, attrs);
287	if (!msg2) {
288		return -1;
289	}
290
291	/* add to the results list */
292	res2 = talloc_realloc(mem_ctx, *res, struct ldb_message *, (*count)+2);
293	if (!res2) {
294		talloc_free(msg2);
295		return -1;
296	}
297
298	(*res) = res2;
299
300	(*res)[*count] = talloc_move(*res, &msg2);
301	(*res)[(*count)+1] = NULL;
302	(*count)++;
303
304	return 0;
305}
306
307
308
309/*
310  filter the specified list of attributes from a message
311  removing not requested attrs.
312 */
313int ltdb_filter_attrs(struct ldb_message *msg, const char * const *attrs)
314{
315	int i, keep_all = 0;
316
317	if (attrs) {
318		/* check for special attrs */
319		for (i = 0; attrs[i]; i++) {
320			if (strcmp(attrs[i], "*") == 0) {
321				keep_all = 1;
322				break;
323			}
324
325			if (ldb_attr_cmp(attrs[i], "distinguishedName") == 0) {
326				if (msg_add_distinguished_name(msg) != 0) {
327					return -1;
328				}
329			}
330		}
331	} else {
332		keep_all = 1;
333	}
334
335	if (keep_all) {
336		if (msg_add_distinguished_name(msg) != 0) {
337			return -1;
338		}
339		return 0;
340	}
341
342	for (i = 0; i < msg->num_elements; i++) {
343		int j, found;
344
345		for (j = 0, found = 0; attrs[j]; j++) {
346			if (ldb_attr_cmp(msg->elements[i].name, attrs[j]) == 0) {
347				found = 1;
348				break;
349			}
350		}
351
352		if (!found) {
353			ldb_msg_remove_attr(msg, msg->elements[i].name);
354			i--;
355		}
356	}
357
358	return 0;
359}
360
361/*
362  search function for a non-indexed search
363 */
364static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
365{
366	struct ldb_handle *handle = talloc_get_type(state, struct ldb_handle);
367	struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context);
368	struct ldb_reply *ares = NULL;
369	int ret;
370
371	if (key.dsize < 4 ||
372	    strncmp((char *)key.dptr, "DN=", 3) != 0) {
373		return 0;
374	}
375
376	ares = talloc_zero(ac, struct ldb_reply);
377	if (!ares) {
378		handle->status = LDB_ERR_OPERATIONS_ERROR;
379		handle->state = LDB_ASYNC_DONE;
380		return -1;
381	}
382
383	ares->message = ldb_msg_new(ares);
384	if (!ares->message) {
385		handle->status = LDB_ERR_OPERATIONS_ERROR;
386		handle->state = LDB_ASYNC_DONE;
387		talloc_free(ares);
388		return -1;
389	}
390
391	/* unpack the record */
392	ret = ltdb_unpack_data(ac->module, &data, ares->message);
393	if (ret == -1) {
394		talloc_free(ares);
395		return -1;
396	}
397
398	if (!ares->message->dn) {
399		ares->message->dn = ldb_dn_explode(ares->message, (char *)key.dptr + 3);
400		if (ares->message->dn == NULL) {
401			handle->status = LDB_ERR_OPERATIONS_ERROR;
402			handle->state = LDB_ASYNC_DONE;
403			talloc_free(ares);
404			return -1;
405		}
406	}
407
408	/* see if it matches the given expression */
409	if (!ldb_match_msg(ac->module->ldb, ares->message, ac->tree,
410			       ac->base, ac->scope)) {
411		talloc_free(ares);
412		return 0;
413	}
414
415	/* filter the attributes that the user wants */
416	ret = ltdb_filter_attrs(ares->message, ac->attrs);
417
418	if (ret == -1) {
419		handle->status = LDB_ERR_OPERATIONS_ERROR;
420		handle->state = LDB_ASYNC_DONE;
421		talloc_free(ares);
422		return -1;
423	}
424
425	ares->type = LDB_REPLY_ENTRY;
426        handle->state = LDB_ASYNC_PENDING;
427	handle->status = ac->callback(ac->module->ldb, ac->context, ares);
428
429	if (handle->status != LDB_SUCCESS) {
430		/* don't try to free ares here, the callback is in charge of that */
431		return -1;
432	}
433
434	return 0;
435}
436
437
438/*
439  search the database with a LDAP-like expression.
440  this is the "full search" non-indexed variant
441*/
442static int ltdb_search_full(struct ldb_handle *handle)
443{
444	struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context);
445	struct ltdb_private *ltdb = talloc_get_type(ac->module->private_data, struct ltdb_private);
446	int ret;
447
448	ret = tdb_traverse_read(ltdb->tdb, search_func, handle);
449
450	if (ret == -1) {
451		handle->status = LDB_ERR_OPERATIONS_ERROR;
452	}
453
454	handle->state = LDB_ASYNC_DONE;
455	return LDB_SUCCESS;
456}
457
458/*
459  search the database with a LDAP-like expression.
460  choses a search method
461*/
462int ltdb_search(struct ldb_module *module, struct ldb_request *req)
463{
464	struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private);
465	struct ltdb_context *ltdb_ac;
466	struct ldb_reply *ares;
467	int ret;
468
469	if ((req->op.search.base == NULL || ldb_dn_get_comp_num(req->op.search.base) == 0) &&
470	    (req->op.search.scope == LDB_SCOPE_BASE || req->op.search.scope == LDB_SCOPE_ONELEVEL))
471		return LDB_ERR_OPERATIONS_ERROR;
472
473	if (ltdb_lock_read(module) != 0) {
474		return LDB_ERR_OPERATIONS_ERROR;
475	}
476
477	if (ltdb_cache_load(module) != 0) {
478		ltdb_unlock_read(module);
479		return LDB_ERR_OPERATIONS_ERROR;
480	}
481
482	if (req->op.search.tree == NULL) {
483		ltdb_unlock_read(module);
484		return LDB_ERR_OPERATIONS_ERROR;
485	}
486
487	req->handle = init_ltdb_handle(ltdb, module, req);
488	if (req->handle == NULL) {
489		ltdb_unlock_read(module);
490		return LDB_ERR_OPERATIONS_ERROR;
491	}
492	ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context);
493
494	ltdb_ac->tree = req->op.search.tree;
495	ltdb_ac->scope = req->op.search.scope;
496	ltdb_ac->base = req->op.search.base;
497	ltdb_ac->attrs = req->op.search.attrs;
498
499	ret = ltdb_search_indexed(req->handle);
500	if (ret == -1) {
501		ret = ltdb_search_full(req->handle);
502	}
503	if (ret != LDB_SUCCESS) {
504		ldb_set_errstring(module->ldb, "Indexed and full searches both failed!\n");
505		req->handle->state = LDB_ASYNC_DONE;
506		req->handle->status = ret;
507	}
508
509	/* Finally send an LDB_REPLY_DONE packet when searching is finished */
510
511	ares = talloc_zero(req, struct ldb_reply);
512	if (!ares) {
513		ltdb_unlock_read(module);
514		return LDB_ERR_OPERATIONS_ERROR;
515	}
516
517	req->handle->state = LDB_ASYNC_DONE;
518	ares->type = LDB_REPLY_DONE;
519
520	ret = req->callback(module->ldb, req->context, ares);
521	req->handle->status = ret;
522
523	ltdb_unlock_read(module);
524
525	return LDB_SUCCESS;
526}
527
528