• 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/dsdb/samdb/ldb_modules/
1/*
2   ldb database library
3
4   Copyright (C) Simo Sorce  2006-2008
5   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2007
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 3 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program.  If not, see <http://www.gnu.org/licenses/>.
19*/
20
21/*
22 *  Name: ldb
23 *
24 *  Component: objectClass sorting module
25 *
26 *  Description:
27 *  - sort the objectClass attribute into the class
28 *    hierarchy,
29 *  - fix DNs and attributes into 'standard' case
30 *  - Add objectCategory and ntSecurityDescriptor defaults
31 *
32 *  Author: Andrew Bartlett
33 */
34
35
36#include "includes.h"
37#include "ldb_module.h"
38#include "dlinklist.h"
39#include "dsdb/samdb/samdb.h"
40#include "librpc/ndr/libndr.h"
41#include "librpc/gen_ndr/ndr_security.h"
42#include "libcli/security/security.h"
43#include "auth/auth.h"
44#include "param/param.h"
45
46struct oc_context {
47
48	struct ldb_module *module;
49	struct ldb_request *req;
50
51	struct ldb_reply *search_res;
52
53	int (*step_fn)(struct oc_context *);
54};
55
56struct class_list {
57	struct class_list *prev, *next;
58	const struct dsdb_class *objectclass;
59};
60
61static struct oc_context *oc_init_context(struct ldb_module *module,
62					  struct ldb_request *req)
63{
64	struct ldb_context *ldb;
65	struct oc_context *ac;
66
67	ldb = ldb_module_get_ctx(module);
68
69	ac = talloc_zero(req, struct oc_context);
70	if (ac == NULL) {
71		ldb_set_errstring(ldb, "Out of Memory");
72		return NULL;
73	}
74
75	ac->module = module;
76	ac->req = req;
77
78	return ac;
79}
80
81static int objectclass_do_add(struct oc_context *ac);
82
83/* Sort objectClasses into correct order, and validate that all
84 * objectClasses specified actually exist in the schema
85 */
86
87static int objectclass_sort(struct ldb_module *module,
88			    const struct dsdb_schema *schema,
89			    TALLOC_CTX *mem_ctx,
90			    struct ldb_message_element *objectclass_element,
91			    struct class_list **sorted_out)
92{
93	struct ldb_context *ldb;
94	int i;
95	int layer;
96	struct class_list *sorted = NULL, *parent_class = NULL,
97		*subclass = NULL, *unsorted = NULL, *current, *poss_subclass, *poss_parent, *new_parent;
98
99	ldb = ldb_module_get_ctx(module);
100
101	/* DESIGN:
102	 *
103	 * We work on 4 different 'bins' (implemented here as linked lists):
104	 *
105	 * * sorted:       the eventual list, in the order we wish to push
106	 *                 into the database.  This is the only ordered list.
107	 *
108	 * * parent_class: The current parent class 'bin' we are
109	 *                 trying to find subclasses for
110	 *
111	 * * subclass:     The subclasses we have found so far
112	 *
113	 * * unsorted:     The remaining objectClasses
114	 *
115	 * The process is a matter of filtering objectClasses up from
116	 * unsorted into sorted.  Order is irrelevent in the later 3 'bins'.
117	 *
118	 * We start with 'top' (found and promoted to parent_class
119	 * initially).  Then we find (in unsorted) all the direct
120	 * subclasses of 'top'.  parent_classes is concatenated onto
121	 * the end of 'sorted', and subclass becomes the list in
122	 * parent_class.
123	 *
124	 * We then repeat, until we find no more subclasses.  Any left
125	 * over classes are added to the end.
126	 *
127	 */
128
129	/* Firstly, dump all the objectClass elements into the
130	 * unsorted bin, except for 'top', which is special */
131	for (i=0; i < objectclass_element->num_values; i++) {
132		current = talloc(mem_ctx, struct class_list);
133		if (!current) {
134			ldb_oom(ldb);
135			return LDB_ERR_OPERATIONS_ERROR;
136		}
137		current->objectclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &objectclass_element->values[i]);
138		if (!current->objectclass) {
139			ldb_asprintf_errstring(ldb, "objectclass %.*s is not a valid objectClass in schema",
140					       (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
141			return LDB_ERR_OBJECT_CLASS_VIOLATION;
142		}
143
144		/* this is the root of the tree.  We will start
145		 * looking for subclasses from here */
146		if (ldb_attr_cmp("top", current->objectclass->lDAPDisplayName) == 0) {
147			DLIST_ADD_END(parent_class, current, struct class_list *);
148		} else {
149			DLIST_ADD_END(unsorted, current, struct class_list *);
150		}
151	}
152
153	if (parent_class == NULL) {
154		current = talloc(mem_ctx, struct class_list);
155		current->objectclass = dsdb_class_by_lDAPDisplayName(schema, "top");
156		DLIST_ADD_END(parent_class, current, struct class_list *);
157	}
158
159	/* For each object:  find parent chain */
160	for (current = unsorted; schema && current; current = current->next) {
161		for (poss_parent = unsorted; poss_parent; poss_parent = poss_parent->next) {
162			if (ldb_attr_cmp(poss_parent->objectclass->lDAPDisplayName, current->objectclass->subClassOf) == 0) {
163				break;
164			}
165		}
166		/* If we didn't get to the end of the list, we need to add this parent */
167		if (poss_parent || (ldb_attr_cmp("top", current->objectclass->subClassOf) == 0)) {
168			continue;
169		}
170
171		new_parent = talloc(mem_ctx, struct class_list);
172		new_parent->objectclass = dsdb_class_by_lDAPDisplayName(schema, current->objectclass->subClassOf);
173		DLIST_ADD_END(unsorted, new_parent, struct class_list *);
174	}
175
176	/* DEBUGGING aid:  how many layers are we down now? */
177	layer = 0;
178	do {
179		layer++;
180		/* Find all the subclasses of classes in the
181		 * parent_classes.  Push them onto the subclass list */
182
183		/* Ensure we don't bother if there are no unsorted entries left */
184		for (current = parent_class; schema && unsorted && current; current = current->next) {
185			/* Walk the list of possible subclasses in unsorted */
186			for (poss_subclass = unsorted; poss_subclass; ) {
187				struct class_list *next;
188
189				/* Save the next pointer, as the DLIST_ macros will change poss_subclass->next */
190				next = poss_subclass->next;
191
192				if (ldb_attr_cmp(poss_subclass->objectclass->subClassOf, current->objectclass->lDAPDisplayName) == 0) {
193					DLIST_REMOVE(unsorted, poss_subclass);
194					DLIST_ADD(subclass, poss_subclass);
195
196					break;
197				}
198				poss_subclass = next;
199			}
200		}
201
202		/* Now push the parent_classes as sorted, we are done with
203		these.  Add to the END of the list by concatenation */
204		DLIST_CONCATENATE(sorted, parent_class, struct class_list *);
205
206		/* and now find subclasses of these */
207		parent_class = subclass;
208		subclass = NULL;
209
210		/* If we didn't find any subclasses we will fall out
211		 * the bottom here */
212	} while (parent_class);
213
214	if (!unsorted) {
215		*sorted_out = sorted;
216		return LDB_SUCCESS;
217	}
218
219	if (!schema) {
220		/* If we don't have schema yet, then just merge the lists again */
221		DLIST_CONCATENATE(sorted, unsorted, struct class_list *);
222		*sorted_out = sorted;
223		return LDB_SUCCESS;
224	}
225
226	/* This shouldn't happen, and would break MMC, perhaps there
227	 * was no 'top', a conflict in the objectClasses or some other
228	 * schema error?
229	 */
230	ldb_asprintf_errstring(ldb, "objectclass %s is not a valid objectClass in objectClass chain", unsorted->objectclass->lDAPDisplayName);
231	return LDB_ERR_OBJECT_CLASS_VIOLATION;
232}
233
234static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
235{
236	struct ldb_context *ldb;
237	struct oc_context *ac;
238	int ret;
239
240	ac = talloc_get_type(req->context, struct oc_context);
241	ldb = ldb_module_get_ctx(ac->module);
242
243	if (!ares) {
244		return ldb_module_done(ac->req, NULL, NULL,
245					LDB_ERR_OPERATIONS_ERROR);
246	}
247	if (ares->error != LDB_SUCCESS &&
248	    ares->error != LDB_ERR_NO_SUCH_OBJECT) {
249		return ldb_module_done(ac->req, ares->controls,
250					ares->response, ares->error);
251	}
252
253	ldb_reset_err_string(ldb);
254
255	switch (ares->type) {
256	case LDB_REPLY_ENTRY:
257		if (ac->search_res != NULL) {
258			ldb_set_errstring(ldb, "Too many results");
259			talloc_free(ares);
260			return ldb_module_done(ac->req, NULL, NULL,
261						LDB_ERR_OPERATIONS_ERROR);
262		}
263
264		ac->search_res = talloc_steal(ac, ares);
265		break;
266
267	case LDB_REPLY_REFERRAL:
268		/* ignore */
269		talloc_free(ares);
270		break;
271
272	case LDB_REPLY_DONE:
273		talloc_free(ares);
274		ret = ac->step_fn(ac);
275		if (ret != LDB_SUCCESS) {
276			return ldb_module_done(ac->req, NULL, NULL, ret);
277		}
278		break;
279	}
280
281	return LDB_SUCCESS;
282}
283
284static int oc_op_callback(struct ldb_request *req, struct ldb_reply *ares)
285{
286	struct oc_context *ac;
287
288	ac = talloc_get_type(req->context, struct oc_context);
289
290	if (!ares) {
291		return ldb_module_done(ac->req, NULL, NULL,
292					LDB_ERR_OPERATIONS_ERROR);
293	}
294	if (ares->error != LDB_SUCCESS) {
295		return ldb_module_done(ac->req, ares->controls,
296					ares->response, ares->error);
297	}
298
299	if (ares->type != LDB_REPLY_DONE) {
300		talloc_free(ares);
301		return ldb_module_done(ac->req, NULL, NULL,
302					LDB_ERR_OPERATIONS_ERROR);
303	}
304
305	return ldb_module_done(ac->req, ares->controls,
306				ares->response, ares->error);
307}
308
309/* Fix up the DN to be in the standard form, taking particular care to match the parent DN
310
311   This should mean that if the parent is:
312    CN=Users,DC=samba,DC=example,DC=com
313   and a proposed child is
314    cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
315
316   The resulting DN should be:
317
318    CN=Admins,CN=Users,DC=samba,DC=example,DC=com
319
320 */
321static int fix_dn(TALLOC_CTX *mem_ctx,
322		  struct ldb_dn *newdn, struct ldb_dn *parent_dn,
323		  struct ldb_dn **fixed_dn)
324{
325	char *upper_rdn_attr;
326	/* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
327	*fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
328
329	/* We need the attribute name in upper case */
330	upper_rdn_attr = strupper_talloc(*fixed_dn,
331					 ldb_dn_get_rdn_name(newdn));
332	if (!upper_rdn_attr) {
333		return LDB_ERR_OPERATIONS_ERROR;
334	}
335
336	/* Create a new child */
337	if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
338		return LDB_ERR_OPERATIONS_ERROR;
339	}
340
341	/* And replace it with CN=foo (we need the attribute in upper case */
342	return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr,
343				    *ldb_dn_get_rdn_val(newdn));
344}
345
346/* Fix all attribute names to be in the correct case, and check they are all valid per the schema */
347static int fix_attributes(struct ldb_context *ldb, const struct dsdb_schema *schema, struct ldb_message *msg)
348{
349	int i;
350	for (i=0; i < msg->num_elements; i++) {
351		const struct dsdb_attribute *attribute = dsdb_attribute_by_lDAPDisplayName(schema, msg->elements[i].name);
352		/* Add in a very special case for 'clearTextPassword',
353		 * which is used for internal processing only, and is
354		 * not presented in the schema */
355		if (!attribute) {
356			if (strcasecmp(msg->elements[i].name, "clearTextPassword") != 0) {
357				ldb_asprintf_errstring(ldb, "attribute %s is not a valid attribute in schema", msg->elements[i].name);
358				return LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE;
359			}
360		} else {
361			msg->elements[i].name = attribute->lDAPDisplayName;
362		}
363	}
364
365	return LDB_SUCCESS;
366}
367
368static int objectclass_do_add(struct oc_context *ac);
369
370static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
371{
372	struct ldb_context *ldb;
373	struct ldb_request *search_req;
374	struct oc_context *ac;
375	struct ldb_dn *parent_dn;
376	int ret;
377	static const char * const parent_attrs[] = { "objectGUID", NULL };
378
379	ldb = ldb_module_get_ctx(module);
380
381	ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
382
383	/* do not manipulate our control entries */
384	if (ldb_dn_is_special(req->op.add.message->dn)) {
385		return ldb_next_request(module, req);
386	}
387
388	/* the objectClass must be specified on add */
389	if (ldb_msg_find_element(req->op.add.message,
390				 "objectClass") == NULL) {
391		return LDB_ERR_OBJECT_CLASS_VIOLATION;
392	}
393
394	ac = oc_init_context(module, req);
395	if (ac == NULL) {
396		return LDB_ERR_OPERATIONS_ERROR;
397	}
398
399	/* If there isn't a parent, just go on to the add processing */
400	if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
401		return objectclass_do_add(ac);
402	}
403
404	/* get copy of parent DN */
405	parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
406	if (parent_dn == NULL) {
407		ldb_oom(ldb);
408		return LDB_ERR_OPERATIONS_ERROR;
409	}
410
411	ret = ldb_build_search_req(&search_req, ldb,
412				   ac, parent_dn, LDB_SCOPE_BASE,
413				   "(objectClass=*)", parent_attrs,
414				   NULL,
415				   ac, get_search_callback,
416				   req);
417	if (ret != LDB_SUCCESS) {
418		return ret;
419	}
420	talloc_steal(search_req, parent_dn);
421
422	ac->step_fn = objectclass_do_add;
423
424	return ldb_next_request(ac->module, search_req);
425}
426
427static int objectclass_do_add(struct oc_context *ac)
428{
429	struct ldb_context *ldb;
430	const struct dsdb_schema *schema;
431	struct ldb_request *add_req;
432	char *value;
433	struct ldb_message_element *objectclass_element;
434	struct ldb_message *msg;
435	TALLOC_CTX *mem_ctx;
436	struct class_list *sorted, *current;
437	int ret;
438
439	ldb = ldb_module_get_ctx(ac->module);
440	schema = dsdb_get_schema(ldb);
441
442	mem_ctx = talloc_new(ac);
443	if (mem_ctx == NULL) {
444		return LDB_ERR_OPERATIONS_ERROR;
445	}
446
447	msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
448
449	/* Check we have a valid parent */
450	if (ac->search_res == NULL) {
451		if (ldb_dn_compare(ldb_get_root_basedn(ldb),
452								msg->dn) == 0) {
453			/* Allow the tree to be started */
454
455			/* but don't keep any error string, it's meaningless */
456			ldb_set_errstring(ldb, NULL);
457		} else {
458			ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!",
459					       ldb_dn_get_linearized(msg->dn));
460			talloc_free(mem_ctx);
461			return LDB_ERR_UNWILLING_TO_PERFORM;
462		}
463	} else {
464		const struct ldb_val *parent_guid;
465
466		/* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
467		ret = fix_dn(msg,
468			     ac->req->op.add.message->dn,
469			     ac->search_res->message->dn,
470			     &msg->dn);
471
472		if (ret != LDB_SUCCESS) {
473			ldb_asprintf_errstring(ldb, "Could not munge DN %s into normal form",
474					       ldb_dn_get_linearized(ac->req->op.add.message->dn));
475			talloc_free(mem_ctx);
476			return ret;
477		}
478
479		parent_guid = ldb_msg_find_ldb_val(ac->search_res->message, "objectGUID");
480		if (parent_guid == NULL) {
481			ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not have an objectGUID!",
482					       ldb_dn_get_linearized(msg->dn));
483			talloc_free(mem_ctx);
484			return LDB_ERR_UNWILLING_TO_PERFORM;
485		}
486
487		/* TODO: Check this is a valid child to this parent,
488		 * by reading the allowedChildClasses and
489		 * allowedChildClasssesEffective attributes */
490		ret = ldb_msg_add_steal_value(msg, "parentGUID", discard_const(parent_guid));
491		if (ret != LDB_SUCCESS) {
492			ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, failed to add parentGUID",
493					       ldb_dn_get_linearized(msg->dn));
494			talloc_free(mem_ctx);
495			return LDB_ERR_UNWILLING_TO_PERFORM;
496		}
497	}
498	if (schema) {
499		ret = fix_attributes(ldb, schema, msg);
500		if (ret != LDB_SUCCESS) {
501			talloc_free(mem_ctx);
502			return ret;
503		}
504
505		/* This is now the objectClass list from the database */
506		objectclass_element = ldb_msg_find_element(msg, "objectClass");
507
508		if (!objectclass_element) {
509			/* Where did it go?  bail now... */
510			talloc_free(mem_ctx);
511			return LDB_ERR_OPERATIONS_ERROR;
512		}
513		ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
514		if (ret != LDB_SUCCESS) {
515			talloc_free(mem_ctx);
516			return ret;
517		}
518
519		ldb_msg_remove_attr(msg, "objectClass");
520		ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
521
522		if (ret != LDB_SUCCESS) {
523			talloc_free(mem_ctx);
524			return ret;
525		}
526
527		/* We must completely replace the existing objectClass entry,
528		 * because we need it sorted */
529
530		/* Move from the linked list back into an ldb msg */
531		for (current = sorted; current; current = current->next) {
532			value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
533			if (value == NULL) {
534				ldb_oom(ldb);
535				talloc_free(mem_ctx);
536				return LDB_ERR_OPERATIONS_ERROR;
537			}
538			ret = ldb_msg_add_string(msg, "objectClass", value);
539			if (ret != LDB_SUCCESS) {
540				ldb_set_errstring(ldb,
541						  "objectclass: could not re-add sorted "
542						  "objectclass to modify msg");
543				talloc_free(mem_ctx);
544				return ret;
545			}
546			/* Last one is the critical one */
547			if (!current->next) {
548				struct ldb_message_element *el;
549				int32_t systemFlags = 0;
550				DATA_BLOB *sd;
551				if (!ldb_msg_find_element(msg, "objectCategory")) {
552					value = talloc_strdup(msg, current->objectclass->defaultObjectCategory);
553					if (value == NULL) {
554						ldb_oom(ldb);
555						talloc_free(mem_ctx);
556						return LDB_ERR_OPERATIONS_ERROR;
557					}
558					ldb_msg_add_string(msg, "objectCategory", value);
559				}
560				if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (current->objectclass->defaultHidingValue == true)) {
561					ldb_msg_add_string(msg, "showInAdvancedViewOnly",
562							   "TRUE");
563				}
564
565				/* There are very special rules for systemFlags, see MS-ADTS 3.1.1.5.2.4 */
566				el = ldb_msg_find_element(msg, "systemFlags");
567
568				systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
569
570				if (el) {
571					/* Only these flags may be set by a client, but we can't tell between a client and our provision at this point */
572					/* systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_LIMITED_MOVE); */
573					ldb_msg_remove_element(msg, el);
574				}
575
576				/* This flag is only allowed on attributeSchema objects */
577				if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "attributeSchema") == 0) {
578					systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
579				}
580
581				if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "server") == 0) {
582					systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
583				} else if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "site") == 0
584					   || ldb_attr_cmp(current->objectclass->lDAPDisplayName, "serverContainer") == 0
585					   || ldb_attr_cmp(current->objectclass->lDAPDisplayName, "ntDSDSA") == 0) {
586					systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
587
588				} else if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "siteLink") == 0
589					   || ldb_attr_cmp(current->objectclass->lDAPDisplayName, "siteLinkBridge") == 0
590					   || ldb_attr_cmp(current->objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
591					systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
592				}
593
594				/* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
595
596				if (el || systemFlags != 0) {
597					samdb_msg_add_int(ldb, msg, msg, "systemFlags", systemFlags);
598				}
599			}
600		}
601	}
602
603	talloc_free(mem_ctx);
604	ret = ldb_msg_sanity_check(ldb, msg);
605
606
607	if (ret != LDB_SUCCESS) {
608		return ret;
609	}
610
611	ret = ldb_build_add_req(&add_req, ldb, ac,
612				msg,
613				ac->req->controls,
614				ac, oc_op_callback,
615				ac->req);
616	if (ret != LDB_SUCCESS) {
617		return ret;
618	}
619
620	/* perform the add */
621	return ldb_next_request(ac->module, add_req);
622}
623
624static int oc_modify_callback(struct ldb_request *req,
625				struct ldb_reply *ares);
626static int objectclass_do_mod(struct oc_context *ac);
627
628static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
629{
630	struct ldb_context *ldb = ldb_module_get_ctx(module);
631	struct ldb_message_element *objectclass_element;
632	struct ldb_message *msg;
633	const struct dsdb_schema *schema = dsdb_get_schema(ldb);
634	struct class_list *sorted, *current;
635	struct ldb_request *down_req;
636	struct oc_context *ac;
637	TALLOC_CTX *mem_ctx;
638	char *value;
639	int ret;
640
641	ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
642
643	/* do not manipulate our control entries */
644	if (ldb_dn_is_special(req->op.mod.message->dn)) {
645		return ldb_next_request(module, req);
646	}
647
648	/* Without schema, there isn't much to do here */
649	if (!schema) {
650		return ldb_next_request(module, req);
651	}
652	objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass");
653
654	ac = oc_init_context(module, req);
655	if (ac == NULL) {
656		return LDB_ERR_OPERATIONS_ERROR;
657	}
658
659	/* If no part of this touches the objectClass, then we don't
660	 * need to make any changes.  */
661
662	/* If the only operation is the deletion of the objectClass
663	 * then go on with just fixing the attribute case */
664	if (!objectclass_element) {
665		msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
666		if (msg == NULL) {
667			return LDB_ERR_OPERATIONS_ERROR;
668		}
669
670		ret = fix_attributes(ldb, schema, msg);
671		if (ret != LDB_SUCCESS) {
672			return ret;
673		}
674
675		ret = ldb_build_mod_req(&down_req, ldb, ac,
676					msg,
677					req->controls,
678					ac, oc_op_callback,
679					req);
680		if (ret != LDB_SUCCESS) {
681			return ret;
682		}
683
684		/* go on with the call chain */
685		return ldb_next_request(module, down_req);
686	}
687
688	switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
689	case LDB_FLAG_MOD_DELETE:
690		if (objectclass_element->num_values == 0) {
691			return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED;
692		}
693		break;
694
695	case LDB_FLAG_MOD_REPLACE:
696		mem_ctx = talloc_new(ac);
697		if (mem_ctx == NULL) {
698			return LDB_ERR_OPERATIONS_ERROR;
699		}
700
701		msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
702		if (msg == NULL) {
703			talloc_free(mem_ctx);
704			return LDB_ERR_OPERATIONS_ERROR;
705		}
706
707		ret = fix_attributes(ldb, schema, msg);
708		if (ret != LDB_SUCCESS) {
709			talloc_free(mem_ctx);
710			return ret;
711		}
712
713		ret = objectclass_sort(module, schema, mem_ctx, objectclass_element, &sorted);
714		if (ret != LDB_SUCCESS) {
715			talloc_free(mem_ctx);
716			return ret;
717		}
718
719		/* We must completely replace the existing objectClass entry,
720		 * because we need it sorted */
721
722		ldb_msg_remove_attr(msg, "objectClass");
723		ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
724
725		if (ret != LDB_SUCCESS) {
726			talloc_free(mem_ctx);
727			return ret;
728		}
729
730		/* Move from the linked list back into an ldb msg */
731		for (current = sorted; current; current = current->next) {
732			/* copy the value as this string is on the schema
733			 * context and we can't rely on it not changing
734			 * before the operation is over */
735			value = talloc_strdup(msg,
736					current->objectclass->lDAPDisplayName);
737			if (value == NULL) {
738				ldb_oom(ldb);
739				talloc_free(mem_ctx);
740				return LDB_ERR_OPERATIONS_ERROR;
741			}
742			ret = ldb_msg_add_string(msg, "objectClass", value);
743			if (ret != LDB_SUCCESS) {
744				ldb_set_errstring(ldb,
745					"objectclass: could not re-add sorted "
746					"objectclass to modify msg");
747				talloc_free(mem_ctx);
748				return ret;
749			}
750		}
751
752		talloc_free(mem_ctx);
753
754		ret = ldb_msg_sanity_check(ldb, msg);
755		if (ret != LDB_SUCCESS) {
756			return ret;
757		}
758
759		ret = ldb_build_mod_req(&down_req, ldb, ac,
760					msg,
761					req->controls,
762					ac, oc_op_callback,
763					req);
764		if (ret != LDB_SUCCESS) {
765			return ret;
766		}
767
768		/* go on with the call chain */
769		return ldb_next_request(module, down_req);
770	}
771
772	/* This isn't the default branch of the switch, but a 'in any
773	 * other case'.  When a delete isn't for all objectClasses for
774	 * example
775	 */
776
777	msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
778	if (msg == NULL) {
779		ldb_oom(ldb);
780		return LDB_ERR_OPERATIONS_ERROR;
781	}
782
783	ret = fix_attributes(ldb, schema, msg);
784	if (ret != LDB_SUCCESS) {
785		ldb_oom(ldb);
786		return ret;
787	}
788
789	ret = ldb_build_mod_req(&down_req, ldb, ac,
790				msg,
791				req->controls,
792				ac, oc_modify_callback,
793				req);
794	if (ret != LDB_SUCCESS) {
795		return ret;
796	}
797
798	return ldb_next_request(module, down_req);
799}
800
801static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
802{
803	struct ldb_context *ldb;
804	static const char * const attrs[] = { "objectClass", NULL };
805	struct ldb_request *search_req;
806	struct oc_context *ac;
807	int ret;
808
809	ac = talloc_get_type(req->context, struct oc_context);
810	ldb = ldb_module_get_ctx(ac->module);
811
812	if (!ares) {
813		return ldb_module_done(ac->req, NULL, NULL,
814					LDB_ERR_OPERATIONS_ERROR);
815	}
816	if (ares->error != LDB_SUCCESS) {
817		return ldb_module_done(ac->req, ares->controls,
818					ares->response, ares->error);
819	}
820
821	if (ares->type != LDB_REPLY_DONE) {
822		talloc_free(ares);
823		return ldb_module_done(ac->req, NULL, NULL,
824					LDB_ERR_OPERATIONS_ERROR);
825	}
826
827	ret = ldb_build_search_req(&search_req, ldb, ac,
828				   ac->req->op.mod.message->dn, LDB_SCOPE_BASE,
829				   "(objectClass=*)",
830				   attrs, NULL,
831				   ac, get_search_callback,
832				   ac->req);
833	if (ret != LDB_SUCCESS) {
834		return ldb_module_done(ac->req, NULL, NULL, ret);
835	}
836
837	ac->step_fn = objectclass_do_mod;
838
839	ret = ldb_next_request(ac->module, search_req);
840	if (ret != LDB_SUCCESS) {
841		return ldb_module_done(ac->req, NULL, NULL, ret);
842	}
843	return LDB_SUCCESS;
844}
845
846static int objectclass_do_mod(struct oc_context *ac)
847{
848	struct ldb_context *ldb;
849	const struct dsdb_schema *schema;
850	struct ldb_request *mod_req;
851	char *value;
852	struct ldb_message_element *objectclass_element;
853	struct ldb_message *msg;
854	TALLOC_CTX *mem_ctx;
855	struct class_list *sorted, *current;
856	int ret;
857
858	ldb = ldb_module_get_ctx(ac->module);
859
860	if (ac->search_res == NULL) {
861		return LDB_ERR_OPERATIONS_ERROR;
862	}
863	schema = dsdb_get_schema(ldb);
864
865	mem_ctx = talloc_new(ac);
866	if (mem_ctx == NULL) {
867		return LDB_ERR_OPERATIONS_ERROR;
868	}
869
870	/* use a new message structure */
871	msg = ldb_msg_new(ac);
872	if (msg == NULL) {
873		ldb_set_errstring(ldb,
874			"objectclass: could not create new modify msg");
875		talloc_free(mem_ctx);
876		return LDB_ERR_OPERATIONS_ERROR;
877	}
878
879	/* This is now the objectClass list from the database */
880	objectclass_element = ldb_msg_find_element(ac->search_res->message,
881						   "objectClass");
882	if (!objectclass_element) {
883		/* Where did it go?  bail now... */
884		talloc_free(mem_ctx);
885		return LDB_ERR_OPERATIONS_ERROR;
886	}
887
888	/* modify dn */
889	msg->dn = ac->req->op.mod.message->dn;
890
891	ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
892	if (ret != LDB_SUCCESS) {
893		return ret;
894	}
895
896	/* We must completely replace the existing objectClass entry.
897	 * We could do a constrained add/del, but we are meant to be
898	 * in a transaction... */
899
900	ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
901	if (ret != LDB_SUCCESS) {
902		ldb_set_errstring(ldb, "objectclass: could not clear objectclass in modify msg");
903		talloc_free(mem_ctx);
904		return ret;
905	}
906
907	/* Move from the linked list back into an ldb msg */
908	for (current = sorted; current; current = current->next) {
909		value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
910		if (value == NULL) {
911			ldb_oom(ldb);
912			return LDB_ERR_OPERATIONS_ERROR;
913		}
914		ret = ldb_msg_add_string(msg, "objectClass", value);
915		if (ret != LDB_SUCCESS) {
916			ldb_set_errstring(ldb, "objectclass: could not re-add sorted objectclass to modify msg");
917			talloc_free(mem_ctx);
918			return ret;
919		}
920	}
921
922	ret = ldb_msg_sanity_check(ldb, msg);
923	if (ret != LDB_SUCCESS) {
924		talloc_free(mem_ctx);
925		return ret;
926	}
927
928	ret = ldb_build_mod_req(&mod_req, ldb, ac,
929				msg,
930				ac->req->controls,
931				ac, oc_op_callback,
932				ac->req);
933	if (ret != LDB_SUCCESS) {
934		talloc_free(mem_ctx);
935		return ret;
936	}
937
938	talloc_free(mem_ctx);
939	/* perform the modify */
940	return ldb_next_request(ac->module, mod_req);
941}
942
943static int objectclass_do_rename(struct oc_context *ac);
944
945static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
946{
947	static const char * const attrs[] = { "objectGUID", NULL };
948	struct ldb_context *ldb;
949	struct ldb_request *search_req;
950	struct oc_context *ac;
951	struct ldb_dn *parent_dn;
952	int ret;
953
954	ldb = ldb_module_get_ctx(module);
955
956	ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
957
958	if (ldb_dn_is_special(req->op.rename.newdn)) { /* do not manipulate our control entries */
959		return ldb_next_request(module, req);
960	}
961
962	/* Firstly ensure we are not trying to rename it to be a child of itself */
963	if ((ldb_dn_compare_base(req->op.rename.olddn, req->op.rename.newdn) == 0)
964	    && (ldb_dn_compare(req->op.rename.olddn, req->op.rename.newdn) != 0)) {
965		ldb_asprintf_errstring(ldb, "Cannot rename %s to be a child of itself",
966				       ldb_dn_get_linearized(req->op.rename.olddn));
967		return LDB_ERR_UNWILLING_TO_PERFORM;
968	}
969
970	ac = oc_init_context(module, req);
971	if (ac == NULL) {
972		return LDB_ERR_OPERATIONS_ERROR;
973	}
974
975	parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
976	if (parent_dn == NULL) {
977		ldb_oom(ldb);
978		return LDB_ERR_OPERATIONS_ERROR;
979	}
980
981	/* note that the results of this search are kept and used to
982	   update the parentGUID in objectclass_rename_callback() */
983	ret = ldb_build_search_req(&search_req, ldb,
984				   ac, parent_dn, LDB_SCOPE_BASE,
985				   "(objectClass=*)",
986				   attrs, NULL,
987				   ac, get_search_callback,
988				   req);
989	if (ret != LDB_SUCCESS) {
990		return ret;
991	}
992
993	/* we have to add the show deleted control, as otherwise DRS
994	   deletes will be refused as we will think the target parent
995	   does not exist */
996	ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, false, NULL);
997
998	if (ret != LDB_SUCCESS) {
999		return ret;
1000	}
1001
1002	ac->step_fn = objectclass_do_rename;
1003
1004	return ldb_next_request(ac->module, search_req);
1005}
1006
1007/*
1008   called after the rename happens.
1009   We now need to fix the parentGUID of the object to be the objectGUID of
1010   the new parent
1011*/
1012static int objectclass_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
1013{
1014	struct ldb_context *ldb;
1015	struct oc_context *ac;
1016	const struct ldb_val *parent_guid;
1017	struct ldb_request *mod_req = NULL;
1018	int ret;
1019	struct ldb_message *msg;
1020	struct ldb_message_element *el = NULL;
1021
1022	ac = talloc_get_type(req->context, struct oc_context);
1023	ldb = ldb_module_get_ctx(ac->module);
1024
1025	/* make sure the rename succeeded */
1026	if (!ares) {
1027		return ldb_module_done(ac->req, NULL, NULL,
1028					LDB_ERR_OPERATIONS_ERROR);
1029	}
1030	if (ares->error != LDB_SUCCESS) {
1031		return ldb_module_done(ac->req, ares->controls,
1032					ares->response, ares->error);
1033	}
1034
1035
1036	/* the ac->search_res should contain the new parents objectGUID */
1037	parent_guid = ldb_msg_find_ldb_val(ac->search_res->message, "objectGUID");
1038	if (parent_guid == NULL) {
1039		ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, new parent does not have an objectGUID!",
1040				       ldb_dn_get_linearized(ac->req->op.rename.newdn));
1041		return LDB_ERR_UNWILLING_TO_PERFORM;
1042
1043	}
1044
1045	/* construct the modify message */
1046	msg = ldb_msg_new(ac);
1047	if (msg == NULL) {
1048		ldb_oom(ldb);
1049		return LDB_ERR_OPERATIONS_ERROR;
1050	}
1051
1052	msg->dn = ac->req->op.rename.newdn;
1053
1054	ret = ldb_msg_add_value(msg, "parentGUID", parent_guid, &el);
1055	if (ret != LDB_SUCCESS) {
1056		return ret;
1057	}
1058
1059	el->flags = LDB_FLAG_MOD_REPLACE;
1060
1061	ret = ldb_build_mod_req(&mod_req, ldb, ac, msg,
1062				NULL, ac, oc_op_callback, req);
1063
1064	return ldb_next_request(ac->module, mod_req);
1065}
1066
1067static int objectclass_do_rename(struct oc_context *ac)
1068{
1069	struct ldb_context *ldb;
1070	struct ldb_request *rename_req;
1071	struct ldb_dn *fixed_dn;
1072	int ret;
1073
1074	ldb = ldb_module_get_ctx(ac->module);
1075
1076	/* Check we have a valid parent */
1077	if (ac->search_res == NULL) {
1078		ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1079				       ldb_dn_get_linearized(ac->req->op.rename.newdn));
1080		return LDB_ERR_UNWILLING_TO_PERFORM;
1081	}
1082
1083	/* Fix up the DN to be in the standard form,
1084	 * taking particular care to match the parent DN */
1085	ret = fix_dn(ac,
1086		     ac->req->op.rename.newdn,
1087		     ac->search_res->message->dn,
1088		     &fixed_dn);
1089	if (ret != LDB_SUCCESS) {
1090		return ret;
1091	}
1092
1093	/* TODO: Check this is a valid child to this parent,
1094	 * by reading the allowedChildClasses and
1095	 * allowedChildClasssesEffective attributes */
1096
1097	ret = ldb_build_rename_req(&rename_req, ldb, ac,
1098				   ac->req->op.rename.olddn, fixed_dn,
1099				   ac->req->controls,
1100				   ac, objectclass_rename_callback,
1101				   ac->req);
1102	if (ret != LDB_SUCCESS) {
1103		return ret;
1104	}
1105
1106	/* perform the rename */
1107	return ldb_next_request(ac->module, rename_req);
1108}
1109
1110_PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = {
1111	.name		   = "objectclass",
1112	.add           = objectclass_add,
1113	.modify        = objectclass_modify,
1114	.rename        = objectclass_rename,
1115};
1116