• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src/router/samba-3.5.8/source3/lib/ldb/modules/
1/*
2   ldb database library
3
4   Copyright (C) Simo Sorce  2006
5   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2006
6
7     ** NOTE! The following LGPL license applies to the ldb
8     ** library. This does NOT imply that all of Samba is released
9     ** under the LGPL
10
11   This library is free software; you can redistribute it and/or
12   modify it under the terms of the GNU Lesser General Public
13   License as published by the Free Software Foundation; either
14   version 3 of the License, or (at your option) any later version.
15
16   This library is distributed in the hope that it will be useful,
17   but WITHOUT ANY WARRANTY; without even the implied warranty of
18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19   Lesser General Public License for more details.
20
21   You should have received a copy of the GNU Lesser General Public
22   License along with this library; if not, see <http://www.gnu.org/licenses/>.
23*/
24
25/*
26 *  Name: ldb
27 *
28 *  Component: objectClass sorting module
29 *
30 *  Description: sort the objectClass attribute into the class hierarchy
31 *
32 *  Author: Andrew Bartlett
33 */
34
35#include "includes.h"
36#include "ldb/include/includes.h"
37
38struct oc_context {
39
40	enum oc_step {OC_DO_REQ, OC_SEARCH_SELF, OC_DO_MOD} step;
41
42	struct ldb_module *module;
43	struct ldb_request *orig_req;
44
45	struct ldb_request *down_req;
46
47	struct ldb_request *search_req;
48	struct ldb_reply *search_res;
49
50	struct ldb_request *mod_req;
51};
52
53struct class_list {
54	struct class_list *prev, *next;
55	const char *objectclass;
56};
57
58static struct ldb_handle *oc_init_handle(struct ldb_request *req, struct ldb_module *module)
59{
60	struct oc_context *ac;
61	struct ldb_handle *h;
62
63	h = talloc_zero(req, struct ldb_handle);
64	if (h == NULL) {
65		ldb_set_errstring(module->ldb, "Out of Memory");
66		return NULL;
67	}
68
69	h->module = module;
70
71	ac = talloc_zero(h, struct oc_context);
72	if (ac == NULL) {
73		ldb_set_errstring(module->ldb, "Out of Memory");
74		talloc_free(h);
75		return NULL;
76	}
77
78	h->private_data = (void *)ac;
79
80	h->state = LDB_ASYNC_INIT;
81	h->status = LDB_SUCCESS;
82
83	ac->module = module;
84	ac->orig_req = req;
85
86	return h;
87}
88
89static int objectclass_sort(struct ldb_module *module,
90			    TALLOC_CTX *mem_ctx,
91			    struct ldb_message_element *objectclass_element,
92			    struct class_list **sorted_out)
93{
94	int i;
95	int layer;
96	struct class_list *sorted = NULL, *parent_class = NULL,
97		*subclass = NULL, *unsorted = NULL, *current, *poss_subclass;
98	/* DESIGN:
99	 *
100	 * We work on 4 different 'bins' (implemented here as linked lists):
101	 *
102	 * * sorted:       the eventual list, in the order we wish to push
103	 *                 into the database.  This is the only ordered list.
104	 *
105	 * * parent_class: The current parent class 'bin' we are
106	 *                 trying to find subclasses for
107	 *
108	 * * subclass:     The subclasses we have found so far
109	 *
110	 * * unsorted:     The remaining objectClasses
111	 *
112	 * The process is a matter of filtering objectClasses up from
113	 * unsorted into sorted.  Order is irrelevent in the later 3 'bins'.
114	 *
115	 * We start with 'top' (found and promoted to parent_class
116	 * initially).  Then we find (in unsorted) all the direct
117	 * subclasses of 'top'.  parent_classes is concatenated onto
118	 * the end of 'sorted', and subclass becomes the list in
119	 * parent_class.
120	 *
121	 * We then repeat, until we find no more subclasses.  Any left
122	 * over classes are added to the end.
123	 *
124	 */
125
126	/* Firstly, dump all the objectClass elements into the
127	 * unsorted bin, except for 'top', which is special */
128	for (i=0; i < objectclass_element->num_values; i++) {
129		current = talloc(mem_ctx, struct class_list);
130		if (!current) {
131			ldb_set_errstring(module->ldb, "objectclass: out of memory allocating objectclass list");
132			talloc_free(mem_ctx);
133			return LDB_ERR_OPERATIONS_ERROR;
134		}
135		current->objectclass = (const char *)objectclass_element->values[i].data;
136
137		/* this is the root of the tree.  We will start
138		 * looking for subclasses from here */
139		if (ldb_attr_cmp("top", current->objectclass) == 0) {
140			DLIST_ADD(parent_class, current);
141		} else {
142			DLIST_ADD(unsorted, current);
143		}
144	}
145
146	/* DEBUGGING aid:  how many layers are we down now? */
147	layer = 0;
148	do {
149		layer++;
150		/* Find all the subclasses of classes in the
151		 * parent_classes.  Push them onto the subclass list */
152
153		/* Ensure we don't bother if there are no unsorted entries left */
154		for (current = parent_class; unsorted && current; current = current->next) {
155			const char **subclasses = ldb_subclass_list(module->ldb, current->objectclass);
156
157			/* Walk the list of possible subclasses in unsorted */
158			for (poss_subclass = unsorted; poss_subclass; ) {
159				struct class_list *next;
160
161				/* Save the next pointer, as the DLIST_ macros will change poss_subclass->next */
162				next = poss_subclass->next;
163
164				for (i = 0; subclasses && subclasses[i]; i++) {
165					if (ldb_attr_cmp(poss_subclass->objectclass, subclasses[i]) == 0) {
166						DLIST_REMOVE(unsorted, poss_subclass);
167						DLIST_ADD(subclass, poss_subclass);
168
169						break;
170					}
171				}
172				poss_subclass = next;
173			}
174		}
175
176		/* Now push the parent_classes as sorted, we are done with
177		these.  Add to the END of the list by concatenation */
178		DLIST_CONCATENATE(sorted, parent_class, struct class_list *);
179
180		/* and now find subclasses of these */
181		parent_class = subclass;
182		subclass = NULL;
183
184		/* If we didn't find any subclasses we will fall out
185		 * the bottom here */
186	} while (parent_class);
187
188	/* This shouldn't happen, and would break MMC, but we can't
189	 * afford to loose objectClasses.  Perhaps there was no 'top',
190	 * or some other schema error?
191	 *
192	 * Detecting schema errors is the job of the schema module, so
193	 * at this layer we just try not to loose data
194 	 */
195	DLIST_CONCATENATE(sorted, unsorted, struct class_list *);
196
197	*sorted_out = sorted;
198	return LDB_SUCCESS;
199}
200
201static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
202{
203	struct ldb_message_element *objectclass_element;
204	struct class_list *sorted, *current;
205	struct ldb_request *down_req;
206	struct ldb_message *msg;
207	int ret;
208	TALLOC_CTX *mem_ctx;
209
210	ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
211
212	if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
213		return ldb_next_request(module, req);
214	}
215
216	objectclass_element = ldb_msg_find_element(req->op.add.message, "objectClass");
217
218	/* If no part of this add has an objectClass, then we don't
219	 * need to make any changes. cn=rootdse doesn't have an objectClass */
220	if (!objectclass_element) {
221		return ldb_next_request(module, req);
222	}
223
224	mem_ctx = talloc_new(req);
225	if (mem_ctx == NULL) {
226		return LDB_ERR_OPERATIONS_ERROR;
227	}
228
229	ret = objectclass_sort(module, mem_ctx, objectclass_element, &sorted);
230	if (ret != LDB_SUCCESS) {
231		return ret;
232	}
233
234	/* prepare the first operation */
235	down_req = talloc(req, struct ldb_request);
236	if (down_req == NULL) {
237		ldb_set_errstring(module->ldb, "Out of memory!");
238		talloc_free(mem_ctx);
239		return LDB_ERR_OPERATIONS_ERROR;
240	}
241
242	*down_req = *req; /* copy the request */
243
244	down_req->op.add.message = msg = ldb_msg_copy_shallow(down_req, req->op.add.message);
245
246	if (down_req->op.add.message == NULL) {
247		talloc_free(mem_ctx);
248		return LDB_ERR_OPERATIONS_ERROR;
249	}
250
251	ldb_msg_remove_attr(msg, "objectClass");
252	ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
253
254	if (ret != LDB_SUCCESS) {
255		talloc_free(mem_ctx);
256		return ret;
257	}
258
259	/* We must completely replace the existing objectClass entry,
260	 * because we need it sorted */
261
262	/* Move from the linked list back into an ldb msg */
263	for (current = sorted; current; current = current->next) {
264		ret = ldb_msg_add_string(msg, "objectClass", current->objectclass);
265		if (ret != LDB_SUCCESS) {
266			ldb_set_errstring(module->ldb, "objectclass: could not re-add sorted objectclass to modify msg");
267			talloc_free(mem_ctx);
268			return ret;
269		}
270	}
271
272	talloc_free(mem_ctx);
273	ret = ldb_msg_sanity_check(module->ldb, msg);
274
275	if (ret != LDB_SUCCESS) {
276		return ret;
277	}
278
279	/* go on with the call chain */
280	ret = ldb_next_request(module, down_req);
281
282	/* do not free down_req as the call results may be linked to it,
283	 * it will be freed when the upper level request get freed */
284	if (ret == LDB_SUCCESS) {
285		req->handle = down_req->handle;
286	}
287	return ret;
288}
289
290static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
291{
292	struct ldb_message_element *objectclass_element;
293	struct ldb_message *msg;
294	ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
295
296	if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
297		return ldb_next_request(module, req);
298	}
299
300	objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass");
301
302	/* If no part of this touches the objectClass, then we don't
303	 * need to make any changes.  */
304	/* If the only operation is the deletion of the objectClass then go on */
305	if (!objectclass_element) {
306		return ldb_next_request(module, req);
307	}
308
309	switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
310	case LDB_FLAG_MOD_DELETE:
311		/* Delete everything?  Probably totally illigal, but hey! */
312		if (objectclass_element->num_values == 0) {
313			return ldb_next_request(module, req);
314		}
315		break;
316	case LDB_FLAG_MOD_REPLACE:
317	{
318		struct ldb_request *down_req;
319		struct class_list *sorted, *current;
320		TALLOC_CTX *mem_ctx;
321		int ret;
322		mem_ctx = talloc_new(req);
323		if (mem_ctx == NULL) {
324			return LDB_ERR_OPERATIONS_ERROR;
325		}
326
327		/* prepare the first operation */
328		down_req = talloc(req, struct ldb_request);
329		if (down_req == NULL) {
330			ldb_set_errstring(module->ldb, "Out of memory!");
331			talloc_free(mem_ctx);
332			return LDB_ERR_OPERATIONS_ERROR;
333		}
334
335		*down_req = *req; /* copy the request */
336
337		down_req->op.mod.message = msg = ldb_msg_copy_shallow(down_req, req->op.mod.message);
338
339		if (down_req->op.add.message == NULL) {
340			talloc_free(mem_ctx);
341			return LDB_ERR_OPERATIONS_ERROR;
342		}
343
344		ret = objectclass_sort(module, mem_ctx, objectclass_element, &sorted);
345		if (ret != LDB_SUCCESS) {
346			return ret;
347		}
348
349		/* We must completely replace the existing objectClass entry,
350		 * because we need it sorted */
351
352		ldb_msg_remove_attr(msg, "objectClass");
353		ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
354
355		if (ret != LDB_SUCCESS) {
356			talloc_free(mem_ctx);
357			return ret;
358		}
359
360		/* Move from the linked list back into an ldb msg */
361		for (current = sorted; current; current = current->next) {
362			ret = ldb_msg_add_string(msg, "objectClass", current->objectclass);
363			if (ret != LDB_SUCCESS) {
364				ldb_set_errstring(module->ldb, "objectclass: could not re-add sorted objectclass to modify msg");
365				talloc_free(mem_ctx);
366				return ret;
367			}
368		}
369
370		talloc_free(mem_ctx);
371
372		ret = ldb_msg_sanity_check(module->ldb, msg);
373		if (ret != LDB_SUCCESS) {
374			talloc_free(mem_ctx);
375			return ret;
376		}
377
378		/* go on with the call chain */
379		ret = ldb_next_request(module, down_req);
380
381		/* do not free down_req as the call results may be linked to it,
382		 * it will be freed when the upper level request get freed */
383		if (ret == LDB_SUCCESS) {
384			req->handle = down_req->handle;
385		}
386		return ret;
387	}
388	}
389
390	{
391		struct ldb_handle *h;
392		struct oc_context *ac;
393
394		h = oc_init_handle(req, module);
395		if (!h) {
396			return LDB_ERR_OPERATIONS_ERROR;
397		}
398		ac = talloc_get_type(h->private_data, struct oc_context);
399
400		/* return or own handle to deal with this call */
401		req->handle = h;
402
403		/* prepare the first operation */
404		ac->down_req = talloc(ac, struct ldb_request);
405		if (ac->down_req == NULL) {
406			ldb_set_errstring(module->ldb, "Out of memory!");
407			return LDB_ERR_OPERATIONS_ERROR;
408		}
409
410		*(ac->down_req) = *req; /* copy the request */
411
412		ac->down_req->context = NULL;
413		ac->down_req->callback = NULL;
414		ldb_set_timeout_from_prev_req(module->ldb, req, ac->down_req);
415
416		ac->step = OC_DO_REQ;
417
418		return ldb_next_request(module, ac->down_req);
419	}
420}
421
422static int get_self_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
423{
424	struct oc_context *ac;
425
426	if (!context || !ares) {
427		ldb_set_errstring(ldb, "NULL Context or Result in callback");
428		return LDB_ERR_OPERATIONS_ERROR;
429	}
430
431	ac = talloc_get_type(context, struct oc_context);
432
433	/* we are interested only in the single reply (base search) we receive here */
434	if (ares->type == LDB_REPLY_ENTRY) {
435		if (ac->search_res != NULL) {
436			ldb_set_errstring(ldb, "Too many results");
437			talloc_free(ares);
438			return LDB_ERR_OPERATIONS_ERROR;
439		}
440
441		ac->search_res = talloc_move(ac, &ares);
442	} else {
443		talloc_free(ares);
444	}
445
446	return LDB_SUCCESS;
447}
448
449static int objectclass_search_self(struct ldb_handle *h) {
450
451	struct oc_context *ac;
452	static const char * const attrs[] = { "objectClass", NULL };
453
454	ac = talloc_get_type(h->private_data, struct oc_context);
455
456	/* prepare the search operation */
457	ac->search_req = talloc_zero(ac, struct ldb_request);
458	if (ac->search_req == NULL) {
459		ldb_debug(ac->module->ldb, LDB_DEBUG_ERROR, "Out of Memory!\n");
460		return LDB_ERR_OPERATIONS_ERROR;
461	}
462
463	ac->search_req->operation = LDB_SEARCH;
464	ac->search_req->op.search.base = ac->orig_req->op.mod.message->dn;
465	ac->search_req->op.search.scope = LDB_SCOPE_BASE;
466	ac->search_req->op.search.tree = ldb_parse_tree(ac->search_req, NULL);
467	if (ac->search_req->op.search.tree == NULL) {
468		ldb_set_errstring(ac->module->ldb, "objectclass: Internal error producing null search");
469		return LDB_ERR_OPERATIONS_ERROR;
470	}
471	ac->search_req->op.search.attrs = attrs;
472	ac->search_req->controls = NULL;
473	ac->search_req->context = ac;
474	ac->search_req->callback = get_self_callback;
475	ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req);
476
477	ac->step = OC_SEARCH_SELF;
478
479	return ldb_next_request(ac->module, ac->search_req);
480}
481
482static int objectclass_do_mod(struct ldb_handle *h) {
483
484	struct oc_context *ac;
485	struct ldb_message_element *objectclass_element;
486	struct ldb_message *msg;
487	TALLOC_CTX *mem_ctx;
488	struct class_list *sorted, *current;
489	int ret;
490
491	ac = talloc_get_type(h->private_data, struct oc_context);
492
493	mem_ctx = talloc_new(ac);
494	if (mem_ctx == NULL) {
495		return LDB_ERR_OPERATIONS_ERROR;
496	}
497
498	ac->mod_req = talloc(ac, struct ldb_request);
499	if (ac->mod_req == NULL) {
500		talloc_free(mem_ctx);
501		return LDB_ERR_OPERATIONS_ERROR;
502	}
503
504	ac->mod_req->operation = LDB_MODIFY;
505	ac->mod_req->controls = NULL;
506	ac->mod_req->context = ac;
507	ac->mod_req->callback = NULL;
508	ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->mod_req);
509
510	/* use a new message structure */
511	ac->mod_req->op.mod.message = msg = ldb_msg_new(ac->mod_req);
512	if (msg == NULL) {
513		ldb_set_errstring(ac->module->ldb, "objectclass: could not create new modify msg");
514		talloc_free(mem_ctx);
515		return LDB_ERR_OPERATIONS_ERROR;
516	}
517
518	/* This is now the objectClass list from the database */
519	objectclass_element = ldb_msg_find_element(ac->search_res->message,
520						   "objectClass");
521	if (!objectclass_element) {
522		/* Where did it go?  Move along now, nothing to see here */
523		talloc_free(mem_ctx);
524		return LDB_SUCCESS;
525	}
526
527	/* modify dn */
528	msg->dn = ac->orig_req->op.mod.message->dn;
529
530	ret = objectclass_sort(ac->module, mem_ctx, objectclass_element, &sorted);
531	if (ret != LDB_SUCCESS) {
532		return ret;
533	}
534
535	/* We must completely replace the existing objectClass entry.
536	 * We could do a constrained add/del, but we are meant to be
537	 * in a transaction... */
538
539	ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
540	if (ret != LDB_SUCCESS) {
541		ldb_set_errstring(ac->module->ldb, "objectclass: could not clear objectclass in modify msg");
542		talloc_free(mem_ctx);
543		return ret;
544	}
545
546	/* Move from the linked list back into an ldb msg */
547	for (current = sorted; current; current = current->next) {
548		ret = ldb_msg_add_string(msg, "objectClass", current->objectclass);
549		if (ret != LDB_SUCCESS) {
550			ldb_set_errstring(ac->module->ldb, "objectclass: could not re-add sorted objectclass to modify msg");
551			talloc_free(mem_ctx);
552			return ret;
553		}
554	}
555
556	ret = ldb_msg_sanity_check(ac->module->ldb, msg);
557	if (ret != LDB_SUCCESS) {
558		talloc_free(mem_ctx);
559		return ret;
560	}
561
562
563	h->state = LDB_ASYNC_INIT;
564	h->status = LDB_SUCCESS;
565
566	ac->step = OC_DO_MOD;
567
568	talloc_free(mem_ctx);
569	/* perform the search */
570	return ldb_next_request(ac->module, ac->mod_req);
571}
572
573static int oc_wait(struct ldb_handle *handle) {
574	struct oc_context *ac;
575	int ret;
576
577	if (!handle || !handle->private_data) {
578		return LDB_ERR_OPERATIONS_ERROR;
579	}
580
581	if (handle->state == LDB_ASYNC_DONE) {
582		return handle->status;
583	}
584
585	handle->state = LDB_ASYNC_PENDING;
586	handle->status = LDB_SUCCESS;
587
588	ac = talloc_get_type(handle->private_data, struct oc_context);
589
590	switch (ac->step) {
591	case OC_DO_REQ:
592		ret = ldb_wait(ac->down_req->handle, LDB_WAIT_NONE);
593
594		if (ret != LDB_SUCCESS) {
595			handle->status = ret;
596			goto done;
597		}
598		if (ac->down_req->handle->status != LDB_SUCCESS) {
599			handle->status = ac->down_req->handle->status;
600			goto done;
601		}
602
603		if (ac->down_req->handle->state != LDB_ASYNC_DONE) {
604			return LDB_SUCCESS;
605		}
606
607		/* mods done, go on */
608		return objectclass_search_self(handle);
609
610	case OC_SEARCH_SELF:
611		ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE);
612
613		if (ret != LDB_SUCCESS) {
614			handle->status = ret;
615			goto done;
616		}
617		if (ac->search_req->handle->status != LDB_SUCCESS) {
618			handle->status = ac->search_req->handle->status;
619			goto done;
620		}
621
622		if (ac->search_req->handle->state != LDB_ASYNC_DONE) {
623			return LDB_SUCCESS;
624		}
625
626		/* self search done, go on */
627		return objectclass_do_mod(handle);
628
629	case OC_DO_MOD:
630		ret = ldb_wait(ac->mod_req->handle, LDB_WAIT_NONE);
631
632		if (ret != LDB_SUCCESS) {
633			handle->status = ret;
634			goto done;
635		}
636		if (ac->mod_req->handle->status != LDB_SUCCESS) {
637			handle->status = ac->mod_req->handle->status;
638			goto done;
639		}
640
641		if (ac->mod_req->handle->state != LDB_ASYNC_DONE) {
642			return LDB_SUCCESS;
643		}
644
645		break;
646
647	default:
648		ret = LDB_ERR_OPERATIONS_ERROR;
649		goto done;
650	}
651
652	ret = LDB_SUCCESS;
653
654done:
655	handle->state = LDB_ASYNC_DONE;
656	return ret;
657}
658
659static int oc_wait_all(struct ldb_handle *handle) {
660
661	int ret;
662
663	while (handle->state != LDB_ASYNC_DONE) {
664		ret = oc_wait(handle);
665		if (ret != LDB_SUCCESS) {
666			return ret;
667		}
668	}
669
670	return handle->status;
671}
672
673static int objectclass_wait(struct ldb_handle *handle, enum ldb_wait_type type)
674{
675	if (type == LDB_WAIT_ALL) {
676		return oc_wait_all(handle);
677	} else {
678		return oc_wait(handle);
679	}
680}
681
682static const struct ldb_module_ops objectclass_ops = {
683	.name		   = "objectclass",
684	.add           = objectclass_add,
685	.modify        = objectclass_modify,
686	.wait          = objectclass_wait
687};
688
689int ldb_objectclass_init(void)
690{
691	return ldb_register_module(&objectclass_ops);
692}
693
694