4 Copyright (C) Simo Sorce 2006-2008
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
6 Copyright (C) Matthias Dieter Wallnöfer 2010-2011
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 * Component: objectClass sorting and constraint checking module
28 * - sort the objectClass attribute into the class
29 * hierarchy and perform constraint checks (correct RDN name,
31 * - fix DNs into 'standard' case
32 * - Add objectCategory and some other attribute defaults
34 * Author: Andrew Bartlett
39 #include "ldb_module.h"
40 #include "util/dlinklist.h"
41 #include "dsdb/samdb/samdb.h"
42 #include "librpc/ndr/libndr.h"
43 #include "librpc/gen_ndr/ndr_security.h"
44 #include "libcli/security/security.h"
45 #include "auth/auth.h"
46 #include "param/param.h"
47 #include "../libds/common/flags.h"
48 #include "dsdb/samdb/ldb_modules/schema.h"
49 #include "dsdb/samdb/ldb_modules/util.h"
53 struct ldb_module *module;
54 struct ldb_request *req;
55 const struct dsdb_schema *schema;
57 struct ldb_reply *search_res;
58 struct ldb_reply *search_res2;
60 int (*step_fn)(struct oc_context *);
64 struct class_list *prev, *next;
65 const struct dsdb_class *objectclass;
68 static struct oc_context *oc_init_context(struct ldb_module *module,
69 struct ldb_request *req)
71 struct ldb_context *ldb;
72 struct oc_context *ac;
74 ldb = ldb_module_get_ctx(module);
76 ac = talloc_zero(req, struct oc_context);
84 ac->schema = dsdb_get_schema(ldb, ac);
89 static int objectclass_do_add(struct oc_context *ac);
91 /* Sort objectClasses into correct order, and validate that all
92 * objectClasses specified actually exist in the schema
95 static int objectclass_sort(struct ldb_module *module,
96 const struct dsdb_schema *schema,
98 struct ldb_message_element *objectclass_element,
99 struct class_list **sorted_out)
101 struct ldb_context *ldb;
102 unsigned int i, lowest;
103 struct class_list *unsorted = NULL, *sorted = NULL, *current = NULL,
104 *poss_parent = NULL, *new_parent = NULL,
105 *current_lowest = NULL, *current_lowest_struct = NULL;
107 ldb = ldb_module_get_ctx(module);
111 * We work on 4 different 'bins' (implemented here as linked lists):
113 * * sorted: the eventual list, in the order we wish to push
114 * into the database. This is the only ordered list.
116 * * parent_class: The current parent class 'bin' we are
117 * trying to find subclasses for
119 * * subclass: The subclasses we have found so far
121 * * unsorted: The remaining objectClasses
123 * The process is a matter of filtering objectClasses up from
124 * unsorted into sorted. Order is irrelevent in the later 3 'bins'.
126 * We start with 'top' (found and promoted to parent_class
127 * initially). Then we find (in unsorted) all the direct
128 * subclasses of 'top'. parent_classes is concatenated onto
129 * the end of 'sorted', and subclass becomes the list in
132 * We then repeat, until we find no more subclasses. Any left
133 * over classes are added to the end.
137 /* Firstly, dump all the objectClass elements into the
138 * unsorted bin, except for 'top', which is special */
139 for (i=0; i < objectclass_element->num_values; i++) {
140 current = talloc(mem_ctx, struct class_list);
144 current->objectclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &objectclass_element->values[i]);
145 if (!current->objectclass) {
146 ldb_asprintf_errstring(ldb, "objectclass %.*s is not a valid objectClass in schema",
147 (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
148 /* This looks weird, but windows apparently returns this for invalid objectClass values */
149 return LDB_ERR_NO_SUCH_ATTRIBUTE;
150 } else if (current->objectclass->isDefunct) {
151 ldb_asprintf_errstring(ldb, "objectclass %.*s marked as isDefunct objectClass in schema - not valid for new objects",
152 (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
153 /* This looks weird, but windows apparently returns this for invalid objectClass values */
154 return LDB_ERR_NO_SUCH_ATTRIBUTE;
157 /* Don't add top to list, we will do that later */
158 if (ldb_attr_cmp("top", current->objectclass->lDAPDisplayName) != 0) {
159 DLIST_ADD_END(unsorted, current, struct class_list *);
163 /* Add top here, to prevent duplicates */
164 current = talloc(mem_ctx, struct class_list);
165 current->objectclass = dsdb_class_by_lDAPDisplayName(schema, "top");
166 DLIST_ADD_END(sorted, current, struct class_list *);
168 /* If we don't have a schema yet, then just merge the lists again */
170 DLIST_CONCATENATE(sorted, unsorted, struct class_list *);
171 *sorted_out = sorted;
175 /* For each object: find parent chain */
176 for (current = unsorted; current != NULL; current = current->next) {
177 for (poss_parent = unsorted; poss_parent; poss_parent = poss_parent->next) {
178 if (ldb_attr_cmp(poss_parent->objectclass->lDAPDisplayName, current->objectclass->subClassOf) == 0) {
182 /* If we didn't get to the end of the list, we need to add this parent */
183 if (poss_parent || (ldb_attr_cmp("top", current->objectclass->subClassOf) == 0)) {
187 new_parent = talloc(mem_ctx, struct class_list);
188 new_parent->objectclass = dsdb_class_by_lDAPDisplayName(schema, current->objectclass->subClassOf);
189 DLIST_ADD_END(unsorted, new_parent, struct class_list *);
192 /* For each object: order by hierarchy */
193 while (unsorted != NULL) {
195 current_lowest = current_lowest_struct = NULL;
196 for (current = unsorted; current != NULL; current = current->next) {
197 if (current->objectclass->subClass_order <= lowest) {
199 * According to MS-ADTS 3.1.1.1.4 structural
200 * and 88 object classes are always listed after
201 * the other class types in a subclass hierarchy
203 if (current->objectclass->objectClassCategory > 1) {
204 current_lowest = current;
206 current_lowest_struct = current;
208 lowest = current->objectclass->subClass_order;
211 if (current_lowest == NULL) {
212 current_lowest = current_lowest_struct;
215 if (current_lowest != NULL) {
216 DLIST_REMOVE(unsorted,current_lowest);
217 DLIST_ADD_END(sorted,current_lowest, struct class_list *);
221 *sorted_out = sorted;
226 * This checks if we have unrelated object classes in our entry's "objectClass"
227 * attribute. That means "unsatisfied" abstract classes (no concrete subclass)
228 * or two or more disjunct structural ones.
229 * If one of these conditions are true, blame.
231 static int check_unrelated_objectclasses(struct ldb_module *module,
232 const struct dsdb_schema *schema,
233 const struct dsdb_class *struct_objectclass,
234 struct ldb_message_element *objectclass_element)
236 struct ldb_context *ldb = ldb_module_get_ctx(module);
240 if (schema == NULL) {
244 for (i = 0; i < objectclass_element->num_values; i++) {
245 const struct dsdb_class *tmp_class = dsdb_class_by_lDAPDisplayName_ldb_val(schema,
246 &objectclass_element->values[i]);
247 const struct dsdb_class *tmp_class2 = struct_objectclass;
249 /* Pointer comparison can be used due to the same schema str. */
250 if (tmp_class == NULL ||
251 tmp_class == struct_objectclass ||
252 tmp_class->objectClassCategory > 2 ||
253 ldb_attr_cmp(tmp_class->lDAPDisplayName, "top") == 0) {
259 ldb_attr_cmp(tmp_class2->lDAPDisplayName, "top") != 0) {
260 tmp_class2 = dsdb_class_by_lDAPDisplayName(schema,
261 tmp_class2->subClassOf);
262 if (tmp_class2 == tmp_class) {
270 ldb_asprintf_errstring(ldb,
271 "objectclass: the objectclass '%s' seems to be unrelated to the entry!",
272 tmp_class->lDAPDisplayName);
273 return LDB_ERR_OBJECT_CLASS_VIOLATION;
279 static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
281 struct ldb_context *ldb;
282 struct oc_context *ac;
285 ac = talloc_get_type(req->context, struct oc_context);
286 ldb = ldb_module_get_ctx(ac->module);
289 return ldb_module_done(ac->req, NULL, NULL,
290 LDB_ERR_OPERATIONS_ERROR);
292 if (ares->error != LDB_SUCCESS &&
293 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
294 return ldb_module_done(ac->req, ares->controls,
295 ares->response, ares->error);
298 ldb_reset_err_string(ldb);
300 switch (ares->type) {
301 case LDB_REPLY_ENTRY:
302 if (ac->search_res != NULL) {
303 ldb_set_errstring(ldb, "Too many results");
305 return ldb_module_done(ac->req, NULL, NULL,
306 LDB_ERR_OPERATIONS_ERROR);
309 ac->search_res = talloc_steal(ac, ares);
312 case LDB_REPLY_REFERRAL:
319 ret = ac->step_fn(ac);
320 if (ret != LDB_SUCCESS) {
321 return ldb_module_done(ac->req, NULL, NULL, ret);
329 static int oc_op_callback(struct ldb_request *req, struct ldb_reply *ares)
331 struct oc_context *ac;
333 ac = talloc_get_type(req->context, struct oc_context);
336 return ldb_module_done(ac->req, NULL, NULL,
337 LDB_ERR_OPERATIONS_ERROR);
340 if (ares->type == LDB_REPLY_REFERRAL) {
341 return ldb_module_send_referral(ac->req, ares->referral);
344 if (ares->error != LDB_SUCCESS) {
345 return ldb_module_done(ac->req, ares->controls,
346 ares->response, ares->error);
349 if (ares->type != LDB_REPLY_DONE) {
351 return ldb_module_done(ac->req, NULL, NULL,
352 LDB_ERR_OPERATIONS_ERROR);
355 return ldb_module_done(ac->req, ares->controls,
356 ares->response, ares->error);
359 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
361 This should mean that if the parent is:
362 CN=Users,DC=samba,DC=example,DC=com
363 and a proposed child is
364 cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
366 The resulting DN should be:
368 CN=Admins,CN=Users,DC=samba,DC=example,DC=com
371 static int fix_dn(struct ldb_context *ldb,
373 struct ldb_dn *newdn, struct ldb_dn *parent_dn,
374 struct ldb_dn **fixed_dn)
376 char *upper_rdn_attr;
377 const struct ldb_val *rdn_val;
379 /* Fix up the DN to be in the standard form, taking particular care to
380 * match the parent DN */
381 *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
382 if (*fixed_dn == NULL) {
386 /* We need the attribute name in upper case */
387 upper_rdn_attr = strupper_talloc(*fixed_dn,
388 ldb_dn_get_rdn_name(newdn));
389 if (upper_rdn_attr == NULL) {
393 /* Create a new child */
394 if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
395 return ldb_operr(ldb);
398 rdn_val = ldb_dn_get_rdn_val(newdn);
399 if (rdn_val == NULL) {
400 return ldb_operr(ldb);
404 /* the rules for rDN length constraints are more complex than
405 this. Until we understand them we need to leave this
406 constraint out. Otherwise we break replication, as windows
407 does sometimes send us rDNs longer than 64 */
408 if (!rdn_val || rdn_val->length > 64) {
409 DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
414 /* And replace it with CN=foo (we need the attribute in upper case) */
415 return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
419 static int objectclass_do_add(struct oc_context *ac);
421 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
423 struct ldb_context *ldb;
424 struct ldb_request *search_req;
425 struct oc_context *ac;
426 struct ldb_dn *parent_dn;
427 const struct ldb_val *val;
429 static const char * const parent_attrs[] = { "objectClass", NULL };
431 ldb = ldb_module_get_ctx(module);
433 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
435 /* do not manipulate our control entries */
436 if (ldb_dn_is_special(req->op.add.message->dn)) {
437 return ldb_next_request(module, req);
440 /* An add operation on the basedn without "NC-add" operation isn't
442 if (ldb_dn_compare(ldb_get_default_basedn(ldb), req->op.add.message->dn) == 0) {
443 unsigned int instanceType;
445 instanceType = ldb_msg_find_attr_as_uint(req->op.add.message,
447 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
449 /* When we are trying to readd the root basedn then
450 * this is denied, but with an interesting mechanism:
451 * there is generated a referral with the last
452 * component value as hostname. */
453 val = ldb_dn_get_component_val(req->op.add.message->dn,
454 ldb_dn_get_comp_num(req->op.add.message->dn) - 1);
456 return ldb_operr(ldb);
458 referral_uri = talloc_asprintf(req, "ldap://%s/%s", val->data,
459 ldb_dn_get_linearized(req->op.add.message->dn));
460 if (referral_uri == NULL) {
461 return ldb_module_oom(module);
464 return ldb_module_send_referral(req, referral_uri);
468 ac = oc_init_context(module, req);
470 return ldb_operr(ldb);
473 /* If there isn't a parent, just go on to the add processing */
474 if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
475 return objectclass_do_add(ac);
478 /* get copy of parent DN */
479 parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
480 if (parent_dn == NULL) {
481 return ldb_operr(ldb);
484 ret = ldb_build_search_req(&search_req, ldb,
485 ac, parent_dn, LDB_SCOPE_BASE,
486 "(objectClass=*)", parent_attrs,
488 ac, get_search_callback,
490 LDB_REQ_SET_LOCATION(search_req);
491 if (ret != LDB_SUCCESS) {
495 ac->step_fn = objectclass_do_add;
497 return ldb_next_request(ac->module, search_req);
502 check if this is a special RODC nTDSDSA add
504 static bool check_rodc_ntdsdsa_add(struct oc_context *ac,
505 const struct dsdb_class *objectclass)
507 struct ldb_control *rodc_control;
509 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") != 0) {
512 rodc_control = ldb_request_get_control(ac->req, LDB_CONTROL_RODC_DCPROMO_OID);
517 rodc_control->critical = false;
521 static int objectclass_do_add(struct oc_context *ac)
523 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
524 struct ldb_request *add_req;
525 struct ldb_message_element *objectclass_element, *el;
526 struct ldb_message *msg;
528 struct class_list *sorted, *current;
529 const char *rdn_name = NULL;
531 const struct dsdb_class *objectclass;
532 struct ldb_dn *objectcategory;
533 int32_t systemFlags = 0;
538 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
540 return ldb_module_oom(ac->module);
543 /* Check if we have a valid parent - this check is needed since
544 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
545 if (ac->search_res == NULL) {
546 unsigned int instanceType;
548 /* An add operation on partition DNs without "NC-add" operation
550 instanceType = ldb_msg_find_attr_as_uint(msg, "instanceType",
552 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
553 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!",
554 ldb_dn_get_linearized(msg->dn));
555 return LDB_ERR_NO_SUCH_OBJECT;
558 /* Don't keep any error messages - we've to add a partition */
559 ldb_set_errstring(ldb, NULL);
561 /* Fix up the DN to be in the standard form, taking
562 * particular care to match the parent DN */
563 ret = fix_dn(ldb, msg,
564 ac->req->op.add.message->dn,
565 ac->search_res->message->dn,
567 if (ret != LDB_SUCCESS) {
568 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
569 ldb_dn_get_linearized(ac->req->op.add.message->dn));
574 if (ac->schema != NULL) {
575 objectclass_element = ldb_msg_find_element(msg, "objectClass");
576 if (!objectclass_element) {
577 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, no objectclass specified!",
578 ldb_dn_get_linearized(msg->dn));
579 return LDB_ERR_OBJECT_CLASS_VIOLATION;
581 if (objectclass_element->num_values == 0) {
582 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, at least one (structural) objectclass has to be specified!",
583 ldb_dn_get_linearized(msg->dn));
584 return LDB_ERR_CONSTRAINT_VIOLATION;
587 mem_ctx = talloc_new(ac);
588 if (mem_ctx == NULL) {
589 return ldb_module_oom(ac->module);
592 /* Here we do now get the "objectClass" list from the
594 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
595 objectclass_element, &sorted);
596 if (ret != LDB_SUCCESS) {
597 talloc_free(mem_ctx);
601 ldb_msg_remove_element(msg, objectclass_element);
603 /* Well, now we shouldn't find any additional "objectClass"
604 * message element (required by the AD specification). */
605 objectclass_element = ldb_msg_find_element(msg, "objectClass");
606 if (objectclass_element != NULL) {
607 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, only one 'objectclass' attribute specification is allowed!",
608 ldb_dn_get_linearized(msg->dn));
609 talloc_free(mem_ctx);
610 return LDB_ERR_OBJECT_CLASS_VIOLATION;
613 /* We must completely replace the existing objectClass entry,
614 * because we need it sorted. */
615 ret = ldb_msg_add_empty(msg, "objectClass", 0,
616 &objectclass_element);
617 if (ret != LDB_SUCCESS) {
618 talloc_free(mem_ctx);
622 /* Move from the linked list back into an ldb msg */
623 for (current = sorted; current; current = current->next) {
624 const char *objectclass_name = current->objectclass->lDAPDisplayName;
626 ret = ldb_msg_add_string(msg, "objectClass", objectclass_name);
627 if (ret != LDB_SUCCESS) {
628 ldb_set_errstring(ldb,
629 "objectclass: could not re-add sorted "
630 "objectclass to modify msg");
631 talloc_free(mem_ctx);
636 talloc_free(mem_ctx);
638 /* Make sure its valid to add an object of this type */
639 objectclass = get_last_structural_class(ac->schema,
642 if(objectclass == NULL) {
643 ldb_asprintf_errstring(ldb,
644 "Failed to find a structural class for %s",
645 ldb_dn_get_linearized(msg->dn));
646 return LDB_ERR_UNWILLING_TO_PERFORM;
649 ret = check_unrelated_objectclasses(ac->module, ac->schema,
651 objectclass_element);
652 if (ret != LDB_SUCCESS) {
656 rdn_name = ldb_dn_get_rdn_name(msg->dn);
657 if (rdn_name == NULL) {
658 return ldb_operr(ldb);
661 for (i = 0; (!found) && (i < objectclass_element->num_values);
663 const struct dsdb_class *tmp_class =
664 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
665 &objectclass_element->values[i]);
667 if (tmp_class == NULL) continue;
669 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
673 ldb_asprintf_errstring(ldb,
674 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
675 rdn_name, objectclass->lDAPDisplayName);
676 return LDB_ERR_NAMING_VIOLATION;
679 if (objectclass->systemOnly &&
680 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) &&
681 !check_rodc_ntdsdsa_add(ac, objectclass)) {
682 ldb_asprintf_errstring(ldb,
683 "objectclass: object class '%s' is system-only, rejecting creation of '%s'!",
684 objectclass->lDAPDisplayName,
685 ldb_dn_get_linearized(msg->dn));
686 return LDB_ERR_UNWILLING_TO_PERFORM;
689 if (ac->search_res && ac->search_res->message) {
690 struct ldb_message_element *oc_el
691 = ldb_msg_find_element(ac->search_res->message, "objectClass");
693 bool allowed_class = false;
694 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
695 const struct dsdb_class *sclass;
697 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
700 /* We don't know this class? what is going on? */
703 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
704 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
705 allowed_class = true;
711 if (!allowed_class) {
712 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
713 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
714 return LDB_ERR_NAMING_VIOLATION;
718 objectcategory = ldb_msg_find_attr_as_dn(ldb, ac, msg,
720 if (objectcategory == NULL) {
721 struct dsdb_extended_dn_store_format *dn_format =
722 talloc_get_type(ldb_module_get_private(ac->module),
723 struct dsdb_extended_dn_store_format);
724 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
725 /* Strip off extended components */
726 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
727 objectclass->defaultObjectCategory);
728 value = ldb_dn_alloc_linearized(msg, dn);
731 value = talloc_strdup(msg,
732 objectclass->defaultObjectCategory);
735 return ldb_module_oom(ac->module);
738 ret = ldb_msg_add_string(msg, "objectCategory", value);
739 if (ret != LDB_SUCCESS) {
743 const struct dsdb_class *ocClass =
744 dsdb_class_by_cn_ldb_val(ac->schema,
745 ldb_dn_get_rdn_val(objectcategory));
746 if (ocClass != NULL) {
747 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
748 ocClass->defaultObjectCategory);
749 if (ldb_dn_compare(objectcategory, dn) != 0) {
753 talloc_free(objectcategory);
754 if (ocClass == NULL) {
755 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'objectCategory' attribute invalid!",
756 ldb_dn_get_linearized(msg->dn));
757 return LDB_ERR_OBJECT_CLASS_VIOLATION;
761 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
762 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
766 /* There are very special rules for systemFlags, see MS-ADTS
767 * MS-ADTS 3.1.1.5.2.4 */
769 el = ldb_msg_find_element(msg, "systemFlags");
770 if ((el != NULL) && (el->num_values > 1)) {
771 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'systemFlags' attribute multivalued!",
772 ldb_dn_get_linearized(msg->dn));
773 return LDB_ERR_CONSTRAINT_VIOLATION;
776 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
778 ldb_msg_remove_attr(msg, "systemFlags");
780 /* Only the following flags may be set by a client */
781 if (ldb_request_get_control(ac->req,
782 LDB_CONTROL_RELAX_OID) == NULL) {
783 systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME
784 | SYSTEM_FLAG_CONFIG_ALLOW_MOVE
785 | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE
786 | SYSTEM_FLAG_ATTR_IS_RDN );
789 /* But the last one ("ATTR_IS_RDN") is only allowed on
790 * "attributeSchema" objects. So truncate if it does not fit. */
791 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") != 0) {
792 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
795 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
796 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
797 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
798 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serversContainer") == 0
799 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") == 0) {
800 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0)
801 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
802 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
803 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
804 || ldb_attr_cmp(objectclass->lDAPDisplayName, "subnet") == 0
805 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
806 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
807 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
809 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
811 if (el || systemFlags != 0) {
812 ret = samdb_msg_add_int(ldb, msg, msg, "systemFlags",
814 if (ret != LDB_SUCCESS) {
819 /* make sure that "isCriticalSystemObject" is not specified! */
820 el = ldb_msg_find_element(msg, "isCriticalSystemObject");
822 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
823 ldb_set_errstring(ldb,
824 "objectclass: 'isCriticalSystemObject' must not be specified!");
825 return LDB_ERR_UNWILLING_TO_PERFORM;
829 ret = ldb_build_add_req(&add_req, ldb, ac,
834 LDB_REQ_SET_LOCATION(add_req);
835 if (ret != LDB_SUCCESS) {
839 /* perform the add */
840 return ldb_next_request(ac->module, add_req);
843 static int oc_modify_callback(struct ldb_request *req,
844 struct ldb_reply *ares);
845 static int objectclass_do_mod(struct oc_context *ac);
847 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
849 struct ldb_context *ldb = ldb_module_get_ctx(module);
850 struct ldb_message_element *objectclass_element;
851 struct ldb_message *msg;
852 struct ldb_request *down_req;
853 struct oc_context *ac;
854 bool oc_changes = false;
857 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
859 /* do not manipulate our control entries */
860 if (ldb_dn_is_special(req->op.mod.message->dn)) {
861 return ldb_next_request(module, req);
864 /* As with the "real" AD we don't accept empty messages */
865 if (req->op.mod.message->num_elements == 0) {
866 ldb_set_errstring(ldb, "objectclass: modify message must have "
867 "elements/attributes!");
868 return LDB_ERR_UNWILLING_TO_PERFORM;
871 ac = oc_init_context(module, req);
873 return ldb_operr(ldb);
876 /* Without schema, there isn't much to do here */
877 if (ac->schema == NULL) {
879 return ldb_next_request(module, req);
882 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
884 return ldb_module_oom(ac->module);
887 /* For now change everything except the objectclasses */
889 objectclass_element = ldb_msg_find_element(msg, "objectClass");
890 if (objectclass_element != NULL) {
891 ldb_msg_remove_attr(msg, "objectClass");
895 /* MS-ADTS 3.1.1.5.3.5 - on a forest level < 2003 we do allow updates
896 * only on application NCs - not on the default ones */
898 (dsdb_forest_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
899 struct ldb_dn *nc_root;
901 ret = dsdb_find_nc_root(ldb, ac, req->op.mod.message->dn,
903 if (ret != LDB_SUCCESS) {
907 if ((ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) == 0) ||
908 (ldb_dn_compare(nc_root, ldb_get_config_basedn(ldb)) == 0) ||
909 (ldb_dn_compare(nc_root, ldb_get_schema_basedn(ldb)) == 0)) {
910 ldb_set_errstring(ldb,
911 "objectclass: object class changes on objects under the standard name contexts not allowed!");
912 return LDB_ERR_UNWILLING_TO_PERFORM;
915 talloc_free(nc_root);
918 ret = ldb_build_mod_req(&down_req, ldb, ac,
921 oc_changes ? oc_modify_callback : oc_op_callback,
923 LDB_REQ_SET_LOCATION(down_req);
924 if (ret != LDB_SUCCESS) {
928 return ldb_next_request(module, down_req);
931 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
933 static const char * const attrs[] = { "objectClass", NULL };
934 struct ldb_context *ldb;
935 struct ldb_request *search_req;
936 struct oc_context *ac;
939 ac = talloc_get_type(req->context, struct oc_context);
940 ldb = ldb_module_get_ctx(ac->module);
943 return ldb_module_done(ac->req, NULL, NULL,
944 LDB_ERR_OPERATIONS_ERROR);
947 if (ares->type == LDB_REPLY_REFERRAL) {
948 return ldb_module_send_referral(ac->req, ares->referral);
951 if (ares->error != LDB_SUCCESS) {
952 return ldb_module_done(ac->req, ares->controls,
953 ares->response, ares->error);
956 if (ares->type != LDB_REPLY_DONE) {
958 return ldb_module_done(ac->req, NULL, NULL,
959 LDB_ERR_OPERATIONS_ERROR);
964 /* this looks up the real existing object for fetching some important
965 * information (objectclasses) */
966 ret = ldb_build_search_req(&search_req, ldb,
967 ac, ac->req->op.mod.message->dn,
971 ac, get_search_callback,
973 LDB_REQ_SET_LOCATION(search_req);
974 if (ret != LDB_SUCCESS) {
975 return ldb_module_done(ac->req, NULL, NULL, ret);
978 ac->step_fn = objectclass_do_mod;
980 ret = ldb_next_request(ac->module, search_req);
981 if (ret != LDB_SUCCESS) {
982 return ldb_module_done(ac->req, NULL, NULL, ret);
988 static int objectclass_do_mod(struct oc_context *ac)
990 struct ldb_context *ldb;
991 struct ldb_request *mod_req;
992 struct ldb_message_element *oc_el_entry, *oc_el_change;
993 struct ldb_val *vals;
994 struct ldb_message *msg;
996 struct class_list *sorted, *current;
997 const struct dsdb_class *objectclass;
998 unsigned int i, j, k;
1002 ldb = ldb_module_get_ctx(ac->module);
1004 /* we should always have a valid entry when we enter here */
1005 if (ac->search_res == NULL) {
1006 return ldb_operr(ldb);
1009 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1011 if (oc_el_entry == NULL) {
1012 /* existing entry without a valid object class? */
1013 return ldb_operr(ldb);
1016 /* use a new message structure */
1017 msg = ldb_msg_new(ac);
1019 return ldb_module_oom(ac->module);
1022 msg->dn = ac->req->op.mod.message->dn;
1024 mem_ctx = talloc_new(ac);
1025 if (mem_ctx == NULL) {
1026 return ldb_module_oom(ac->module);
1029 /* We've to walk over all "objectClass" message elements */
1030 for (k = 0; k < ac->req->op.mod.message->num_elements; k++) {
1031 if (ldb_attr_cmp(ac->req->op.mod.message->elements[k].name,
1032 "objectClass") != 0) {
1036 oc_el_change = &ac->req->op.mod.message->elements[k];
1038 switch (oc_el_change->flags & LDB_FLAG_MOD_MASK) {
1039 case LDB_FLAG_MOD_ADD:
1040 /* Merge the two message elements */
1041 for (i = 0; i < oc_el_change->num_values; i++) {
1042 for (j = 0; j < oc_el_entry->num_values; j++) {
1043 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
1044 (char *)oc_el_entry->values[j].data) == 0) {
1045 ldb_asprintf_errstring(ldb,
1046 "objectclass: cannot re-add an existing objectclass: '%.*s'!",
1047 (int)oc_el_change->values[i].length,
1048 (const char *)oc_el_change->values[i].data);
1049 talloc_free(mem_ctx);
1050 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1053 /* append the new object class value - code was
1054 * copied from "ldb_msg_add_value" */
1055 vals = talloc_realloc(oc_el_entry, oc_el_entry->values,
1057 oc_el_entry->num_values + 1);
1059 talloc_free(mem_ctx);
1060 return ldb_module_oom(ac->module);
1062 oc_el_entry->values = vals;
1063 oc_el_entry->values[oc_el_entry->num_values] =
1064 oc_el_change->values[i];
1065 ++(oc_el_entry->num_values);
1070 case LDB_FLAG_MOD_REPLACE:
1072 * In this case the new "oc_el_entry" is simply
1075 oc_el_entry = oc_el_change;
1079 case LDB_FLAG_MOD_DELETE:
1080 /* Merge the two message elements */
1081 for (i = 0; i < oc_el_change->num_values; i++) {
1083 for (j = 0; j < oc_el_entry->num_values; j++) {
1084 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
1085 (char *)oc_el_entry->values[j].data) == 0) {
1087 /* delete the object class value
1088 * - code was copied from
1089 * "ldb_msg_remove_element" */
1090 if (j != oc_el_entry->num_values - 1) {
1091 memmove(&oc_el_entry->values[j],
1092 &oc_el_entry->values[j+1],
1093 ((oc_el_entry->num_values-1) - j)*sizeof(struct ldb_val));
1095 --(oc_el_entry->num_values);
1100 /* we cannot delete a not existing
1102 ldb_asprintf_errstring(ldb,
1103 "objectclass: cannot delete this objectclass: '%.*s'!",
1104 (int)oc_el_change->values[i].length,
1105 (const char *)oc_el_change->values[i].data);
1106 talloc_free(mem_ctx);
1107 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1114 /* Get the new top-most structural object class */
1115 objectclass = get_last_structural_class(ac->schema, oc_el_entry,
1117 if (objectclass == NULL) {
1118 ldb_set_errstring(ldb,
1119 "objectclass: cannot delete all structural objectclasses!");
1120 talloc_free(mem_ctx);
1121 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1124 ret = check_unrelated_objectclasses(ac->module, ac->schema,
1127 if (ret != LDB_SUCCESS) {
1128 talloc_free(mem_ctx);
1132 /* Now do the sorting */
1133 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1134 oc_el_entry, &sorted);
1135 if (ret != LDB_SUCCESS) {
1136 talloc_free(mem_ctx);
1140 /* (Re)-add an empty "objectClass" attribute on the object
1141 * classes change message "msg". */
1142 ldb_msg_remove_attr(msg, "objectClass");
1143 ret = ldb_msg_add_empty(msg, "objectClass",
1144 LDB_FLAG_MOD_REPLACE, &oc_el_entry);
1145 if (ret != LDB_SUCCESS) {
1146 talloc_free(mem_ctx);
1150 /* Move from the linked list back into an ldb msg */
1151 for (current = sorted; current; current = current->next) {
1152 const char *objectclass_name = current->objectclass->lDAPDisplayName;
1154 ret = ldb_msg_add_string(msg, "objectClass",
1156 if (ret != LDB_SUCCESS) {
1157 ldb_set_errstring(ldb,
1158 "objectclass: could not re-add sorted objectclasses!");
1159 talloc_free(mem_ctx);
1165 talloc_free(mem_ctx);
1167 /* Now we have the real and definitive change left to do */
1169 ret = ldb_build_mod_req(&mod_req, ldb, ac,
1174 LDB_REQ_SET_LOCATION(mod_req);
1175 if (ret != LDB_SUCCESS) {
1179 return ldb_next_request(ac->module, mod_req);
1182 static int objectclass_do_rename(struct oc_context *ac);
1184 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1186 static const char * const attrs[] = { "objectClass", NULL };
1187 struct ldb_context *ldb;
1188 struct ldb_request *search_req;
1189 struct oc_context *ac;
1190 struct ldb_dn *parent_dn;
1193 ldb = ldb_module_get_ctx(module);
1195 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1197 /* do not manipulate our control entries */
1198 if (ldb_dn_is_special(req->op.rename.olddn)) {
1199 return ldb_next_request(module, req);
1202 ac = oc_init_context(module, req);
1204 return ldb_operr(ldb);
1207 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1208 if (parent_dn == NULL) {
1209 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, the parent DN does not exist!",
1210 ldb_dn_get_linearized(req->op.rename.olddn));
1211 return LDB_ERR_NO_SUCH_OBJECT;
1214 /* this looks up the parent object for fetching some important
1215 * information (objectclasses, DN normalisation...) */
1216 ret = ldb_build_search_req(&search_req, ldb,
1217 ac, parent_dn, LDB_SCOPE_BASE,
1220 ac, get_search_callback,
1222 LDB_REQ_SET_LOCATION(search_req);
1223 if (ret != LDB_SUCCESS) {
1227 /* we have to add the show recycled control, as otherwise DRS
1228 deletes will be refused as we will think the target parent
1230 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
1233 if (ret != LDB_SUCCESS) {
1237 ac->step_fn = objectclass_do_rename;
1239 return ldb_next_request(ac->module, search_req);
1242 static int objectclass_do_rename2(struct oc_context *ac);
1244 static int objectclass_do_rename(struct oc_context *ac)
1246 static const char * const attrs[] = { "objectClass", NULL };
1247 struct ldb_context *ldb;
1248 struct ldb_request *search_req;
1251 ldb = ldb_module_get_ctx(ac->module);
1253 /* Check if we have a valid parent - this check is needed since
1254 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1255 if (ac->search_res == NULL) {
1256 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1257 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1258 return LDB_ERR_OTHER;
1261 /* now assign "search_res2" to the parent entry to have "search_res"
1262 * free for another lookup */
1263 ac->search_res2 = ac->search_res;
1264 ac->search_res = NULL;
1266 /* this looks up the real existing object for fetching some important
1267 * information (objectclasses) */
1268 ret = ldb_build_search_req(&search_req, ldb,
1269 ac, ac->req->op.rename.olddn,
1273 ac, get_search_callback,
1275 LDB_REQ_SET_LOCATION(search_req);
1276 if (ret != LDB_SUCCESS) {
1280 ac->step_fn = objectclass_do_rename2;
1282 return ldb_next_request(ac->module, search_req);
1285 static int objectclass_do_rename2(struct oc_context *ac)
1287 struct ldb_context *ldb;
1288 struct ldb_request *rename_req;
1289 struct ldb_dn *fixed_dn;
1292 ldb = ldb_module_get_ctx(ac->module);
1294 /* Check if we have a valid entry - this check is needed since
1295 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1296 if (ac->search_res == NULL) {
1297 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, entry does not exist!",
1298 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1299 return LDB_ERR_NO_SUCH_OBJECT;
1302 if (ac->schema != NULL) {
1303 struct ldb_message_element *oc_el_entry, *oc_el_parent;
1304 const struct dsdb_class *objectclass;
1305 const char *rdn_name;
1306 bool allowed_class = false;
1310 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1312 if (oc_el_entry == NULL) {
1313 /* existing entry without a valid object class? */
1314 return ldb_operr(ldb);
1316 objectclass = get_last_structural_class(ac->schema, oc_el_entry,
1318 if (objectclass == NULL) {
1319 /* existing entry without a valid object class? */
1320 return ldb_operr(ldb);
1323 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
1324 if (rdn_name == NULL) {
1325 return ldb_operr(ldb);
1328 for (i = 0; (!found) && (i < oc_el_entry->num_values); i++) {
1329 const struct dsdb_class *tmp_class =
1330 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1331 &oc_el_entry->values[i]);
1333 if (tmp_class == NULL) continue;
1335 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
1339 ldb_asprintf_errstring(ldb,
1340 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
1341 rdn_name, objectclass->lDAPDisplayName);
1342 return LDB_ERR_UNWILLING_TO_PERFORM;
1345 oc_el_parent = ldb_msg_find_element(ac->search_res2->message,
1347 if (oc_el_parent == NULL) {
1348 /* existing entry without a valid object class? */
1349 return ldb_operr(ldb);
1352 for (i=0; allowed_class == false && i < oc_el_parent->num_values; i++) {
1353 const struct dsdb_class *sclass;
1355 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1356 &oc_el_parent->values[i]);
1358 /* We don't know this class? what is going on? */
1361 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
1362 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
1363 allowed_class = true;
1369 if (!allowed_class) {
1370 ldb_asprintf_errstring(ldb,
1371 "objectclass: structural objectClass %s is not a valid child class for %s",
1372 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res2->message->dn));
1373 return LDB_ERR_NAMING_VIOLATION;
1377 /* Ensure we are not trying to rename it to be a child of itself */
1378 if ((ldb_dn_compare_base(ac->req->op.rename.olddn,
1379 ac->req->op.rename.newdn) == 0) &&
1380 (ldb_dn_compare(ac->req->op.rename.olddn,
1381 ac->req->op.rename.newdn) != 0)) {
1382 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s to be a child of itself",
1383 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1384 return LDB_ERR_UNWILLING_TO_PERFORM;
1387 /* Fix up the DN to be in the standard form, taking
1388 * particular care to match the parent DN */
1389 ret = fix_dn(ldb, ac,
1390 ac->req->op.rename.newdn,
1391 ac->search_res2->message->dn,
1393 if (ret != LDB_SUCCESS) {
1394 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
1395 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1400 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1401 ac->req->op.rename.olddn, fixed_dn,
1405 LDB_REQ_SET_LOCATION(rename_req);
1406 if (ret != LDB_SUCCESS) {
1410 /* perform the rename */
1411 return ldb_next_request(ac->module, rename_req);
1414 static int objectclass_do_delete(struct oc_context *ac);
1416 static int objectclass_delete(struct ldb_module *module, struct ldb_request *req)
1418 static const char * const attrs[] = { "nCName", "objectClass",
1421 "isCriticalSystemObject", NULL };
1422 struct ldb_context *ldb;
1423 struct ldb_request *search_req;
1424 struct oc_context *ac;
1427 ldb = ldb_module_get_ctx(module);
1429 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_delete\n");
1431 /* do not manipulate our control entries */
1432 if (ldb_dn_is_special(req->op.del.dn)) {
1433 return ldb_next_request(module, req);
1436 /* Bypass the constraint checks when we do have the "RELAX" control
1438 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) != NULL) {
1439 return ldb_next_request(module, req);
1442 ac = oc_init_context(module, req);
1444 return ldb_operr(ldb);
1447 /* this looks up the entry object for fetching some important
1448 * information (object classes, system flags...) */
1449 ret = ldb_build_search_req(&search_req, ldb,
1450 ac, req->op.del.dn, LDB_SCOPE_BASE,
1452 attrs, req->controls,
1453 ac, get_search_callback,
1455 LDB_REQ_SET_LOCATION(search_req);
1456 if (ret != LDB_SUCCESS) {
1460 ac->step_fn = objectclass_do_delete;
1462 return ldb_next_request(ac->module, search_req);
1465 static int objectclass_do_delete(struct oc_context *ac)
1467 struct ldb_context *ldb;
1469 int32_t systemFlags;
1470 bool isCriticalSystemObject;
1473 ldb = ldb_module_get_ctx(ac->module);
1475 /* Check if we have a valid entry - this check is needed since
1476 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1477 if (ac->search_res == NULL) {
1478 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, entry does not exist!",
1479 ldb_dn_get_linearized(ac->req->op.del.dn));
1480 return LDB_ERR_NO_SUCH_OBJECT;
1483 /* DC's ntDSDSA object */
1484 if (ldb_dn_compare(ac->req->op.del.dn, samdb_ntds_settings_dn(ldb)) == 0) {
1485 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's ntDSDSA object!",
1486 ldb_dn_get_linearized(ac->req->op.del.dn));
1487 return LDB_ERR_UNWILLING_TO_PERFORM;
1490 /* DC's rIDSet object */
1491 /* Perform this check only when it does exist - this is needed in order
1492 * to don't let existing provisions break. */
1493 ret = samdb_rid_set_dn(ldb, ac, &dn);
1494 if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
1497 if (ret == LDB_SUCCESS) {
1498 if (ldb_dn_compare(ac->req->op.del.dn, dn) == 0) {
1500 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's rIDSet object!",
1501 ldb_dn_get_linearized(ac->req->op.del.dn));
1502 return LDB_ERR_UNWILLING_TO_PERFORM;
1507 /* Only trusted request from system account are allowed to delete
1510 if (ldb_msg_check_string_attribute(ac->search_res->message, "isDeleted", "TRUE") &&
1511 (ldb_req_is_untrusted(ac->req) ||
1512 !dsdb_module_am_system(ac->module))) {
1513 ldb_asprintf_errstring(ldb, "Delete of '%s' failed",
1514 ldb_dn_get_linearized(ac->req->op.del.dn));
1515 return LDB_ERR_UNWILLING_TO_PERFORM;
1518 /* crossRef objects regarding config, schema and default domain NCs */
1519 if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass",
1520 "crossRef") != NULL) {
1521 dn = ldb_msg_find_attr_as_dn(ldb, ac, ac->search_res->message,
1523 if ((ldb_dn_compare(dn, ldb_get_default_basedn(ldb)) == 0) ||
1524 (ldb_dn_compare(dn, ldb_get_config_basedn(ldb)) == 0)) {
1527 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the main or configuration partition!",
1528 ldb_dn_get_linearized(ac->req->op.del.dn));
1529 return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF;
1531 if (ldb_dn_compare(dn, ldb_get_schema_basedn(ldb)) == 0) {
1534 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the schema partition!",
1535 ldb_dn_get_linearized(ac->req->op.del.dn));
1536 return LDB_ERR_UNWILLING_TO_PERFORM;
1543 systemFlags = ldb_msg_find_attr_as_int(ac->search_res->message,
1545 if ((systemFlags & SYSTEM_FLAG_DISALLOW_DELETE) != 0) {
1546 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it isn't permitted!",
1547 ldb_dn_get_linearized(ac->req->op.del.dn));
1548 return LDB_ERR_UNWILLING_TO_PERFORM;
1551 /* isCriticalSystemObject - but this only applies on tree delete
1552 * operations - MS-ADTS 3.1.1.5.5.7.2 */
1553 if (ldb_request_get_control(ac->req, LDB_CONTROL_TREE_DELETE_OID) != NULL) {
1554 isCriticalSystemObject = ldb_msg_find_attr_as_bool(ac->search_res->message,
1555 "isCriticalSystemObject", false);
1556 if (isCriticalSystemObject) {
1558 * Following the explaination from Microsoft
1559 * https://lists.samba.org/archive/cifs-protocol/2011-August/002046.html
1560 * "I finished the investigation on this behavior.
1561 * As per MS-ADTS 3.1.5.5.7.2 , when a tree deletion is performed ,
1562 * every object in the tree will be checked to see if it has isCriticalSystemObject
1563 * set to TRUE, including the root node on which the delete operation is performed
1564 * But there is an exception if the root object is a SAM specific objects(3.1.1.5.2.3 MS-ADTS)
1565 * Its deletion is done through SAM manger and isCriticalSystemObject attribute is not checked
1566 * The root node of the tree delete in your case is CN=ARES,OU=Domain Controllers,DC=w2k8r2,DC=home,DC=matws,DC=net
1567 * which is a SAM object with user class. Therefore the tree deletion is performed without any error
1570 if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "group") == NULL &&
1571 samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "samDomain") == NULL &&
1572 samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "samServer") == NULL &&
1573 samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "user") == NULL) {
1574 ldb_asprintf_errstring(ldb,
1575 "objectclass: Cannot tree-delete %s, it's a critical system object!",
1576 ldb_dn_get_linearized(ac->req->op.del.dn));
1577 return LDB_ERR_UNWILLING_TO_PERFORM;
1582 return ldb_next_request(ac->module, ac->req);
1585 static int objectclass_init(struct ldb_module *module)
1587 struct ldb_context *ldb = ldb_module_get_ctx(module);
1590 /* Init everything else */
1591 ret = ldb_next_init(module);
1592 if (ret != LDB_SUCCESS) {
1596 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1597 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1599 ret = ldb_mod_register_control(module, LDB_CONTROL_RODC_DCPROMO_OID);
1600 if (ret != LDB_SUCCESS) {
1601 ldb_debug(ldb, LDB_DEBUG_ERROR,
1602 "objectclass_init: Unable to register control DCPROMO with rootdse\n");
1603 return ldb_operr(ldb);
1609 static const struct ldb_module_ops ldb_objectclass_module_ops = {
1610 .name = "objectclass",
1611 .add = objectclass_add,
1612 .modify = objectclass_modify,
1613 .rename = objectclass_rename,
1614 .del = objectclass_delete,
1615 .init_context = objectclass_init
1618 int ldb_objectclass_module_init(const char *version)
1620 LDB_MODULE_CHECK_VERSION(version);
1621 return ldb_register_module(&ldb_objectclass_module_ops);