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
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"
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, *poss_parent = NULL, *new_parent = NULL, *current_lowest = NULL;
105 ldb = ldb_module_get_ctx(module);
109 * We work on 4 different 'bins' (implemented here as linked lists):
111 * * sorted: the eventual list, in the order we wish to push
112 * into the database. This is the only ordered list.
114 * * parent_class: The current parent class 'bin' we are
115 * trying to find subclasses for
117 * * subclass: The subclasses we have found so far
119 * * unsorted: The remaining objectClasses
121 * The process is a matter of filtering objectClasses up from
122 * unsorted into sorted. Order is irrelevent in the later 3 'bins'.
124 * We start with 'top' (found and promoted to parent_class
125 * initially). Then we find (in unsorted) all the direct
126 * subclasses of 'top'. parent_classes is concatenated onto
127 * the end of 'sorted', and subclass becomes the list in
130 * We then repeat, until we find no more subclasses. Any left
131 * over classes are added to the end.
135 /* Firstly, dump all the objectClass elements into the
136 * unsorted bin, except for 'top', which is special */
137 for (i=0; i < objectclass_element->num_values; i++) {
138 current = talloc(mem_ctx, struct class_list);
142 current->objectclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &objectclass_element->values[i]);
143 if (!current->objectclass) {
144 ldb_asprintf_errstring(ldb, "objectclass %.*s is not a valid objectClass in schema",
145 (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
146 /* This looks weird, but windows apparently returns this for invalid objectClass values */
147 return LDB_ERR_NO_SUCH_ATTRIBUTE;
148 } else if (current->objectclass->isDefunct) {
149 ldb_asprintf_errstring(ldb, "objectclass %.*s marked as isDefunct objectClass in schema - not valid for new objects",
150 (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
151 /* This looks weird, but windows apparently returns this for invalid objectClass values */
152 return LDB_ERR_NO_SUCH_ATTRIBUTE;
155 /* Don't add top to list, we will do that later */
156 if (ldb_attr_cmp("top", current->objectclass->lDAPDisplayName) != 0) {
157 DLIST_ADD_END(unsorted, current, struct class_list *);
161 /* Add top here, to prevent duplicates */
162 current = talloc(mem_ctx, struct class_list);
163 current->objectclass = dsdb_class_by_lDAPDisplayName(schema, "top");
164 DLIST_ADD_END(sorted, current, struct class_list *);
167 /* For each object: find parent chain */
168 for (current = unsorted; schema && current; current = current->next) {
169 for (poss_parent = unsorted; poss_parent; poss_parent = poss_parent->next) {
170 if (ldb_attr_cmp(poss_parent->objectclass->lDAPDisplayName, current->objectclass->subClassOf) == 0) {
174 /* If we didn't get to the end of the list, we need to add this parent */
175 if (poss_parent || (ldb_attr_cmp("top", current->objectclass->subClassOf) == 0)) {
179 new_parent = talloc(mem_ctx, struct class_list);
180 new_parent->objectclass = dsdb_class_by_lDAPDisplayName(schema, current->objectclass->subClassOf);
181 DLIST_ADD_END(unsorted, new_parent, struct class_list *);
187 current_lowest = NULL;
188 for (current = unsorted; schema && current; current = current->next) {
189 if(current->objectclass->subClass_order < lowest) {
190 current_lowest = current;
191 lowest = current->objectclass->subClass_order;
195 if(current_lowest != NULL) {
196 DLIST_REMOVE(unsorted,current_lowest);
197 DLIST_ADD_END(sorted,current_lowest, struct class_list *);
203 *sorted_out = sorted;
208 /* If we don't have schema yet, then just merge the lists again */
209 DLIST_CONCATENATE(sorted, unsorted, struct class_list *);
210 *sorted_out = sorted;
214 /* This shouldn't happen, and would break MMC, perhaps there
215 * was no 'top', a conflict in the objectClasses or some other
218 ldb_asprintf_errstring(ldb, "objectclass %s is not a valid objectClass in objectClass chain", unsorted->objectclass->lDAPDisplayName);
219 return LDB_ERR_OBJECT_CLASS_VIOLATION;
222 static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
224 struct ldb_context *ldb;
225 struct oc_context *ac;
228 ac = talloc_get_type(req->context, struct oc_context);
229 ldb = ldb_module_get_ctx(ac->module);
232 return ldb_module_done(ac->req, NULL, NULL,
233 LDB_ERR_OPERATIONS_ERROR);
235 if (ares->error != LDB_SUCCESS &&
236 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
237 return ldb_module_done(ac->req, ares->controls,
238 ares->response, ares->error);
241 ldb_reset_err_string(ldb);
243 switch (ares->type) {
244 case LDB_REPLY_ENTRY:
245 if (ac->search_res != NULL) {
246 ldb_set_errstring(ldb, "Too many results");
248 return ldb_module_done(ac->req, NULL, NULL,
249 LDB_ERR_OPERATIONS_ERROR);
252 ac->search_res = talloc_steal(ac, ares);
255 case LDB_REPLY_REFERRAL:
262 ret = ac->step_fn(ac);
263 if (ret != LDB_SUCCESS) {
264 return ldb_module_done(ac->req, NULL, NULL, ret);
272 static int oc_op_callback(struct ldb_request *req, struct ldb_reply *ares)
274 struct oc_context *ac;
276 ac = talloc_get_type(req->context, struct oc_context);
279 return ldb_module_done(ac->req, NULL, NULL,
280 LDB_ERR_OPERATIONS_ERROR);
283 if (ares->type == LDB_REPLY_REFERRAL) {
284 return ldb_module_send_referral(ac->req, ares->referral);
287 if (ares->error != LDB_SUCCESS) {
288 return ldb_module_done(ac->req, ares->controls,
289 ares->response, ares->error);
292 if (ares->type != LDB_REPLY_DONE) {
294 return ldb_module_done(ac->req, NULL, NULL,
295 LDB_ERR_OPERATIONS_ERROR);
298 return ldb_module_done(ac->req, ares->controls,
299 ares->response, ares->error);
302 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
304 This should mean that if the parent is:
305 CN=Users,DC=samba,DC=example,DC=com
306 and a proposed child is
307 cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
309 The resulting DN should be:
311 CN=Admins,CN=Users,DC=samba,DC=example,DC=com
314 static int fix_dn(struct ldb_context *ldb,
316 struct ldb_dn *newdn, struct ldb_dn *parent_dn,
317 struct ldb_dn **fixed_dn)
319 char *upper_rdn_attr;
320 const struct ldb_val *rdn_val;
322 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
323 *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
325 /* We need the attribute name in upper case */
326 upper_rdn_attr = strupper_talloc(*fixed_dn,
327 ldb_dn_get_rdn_name(newdn));
328 if (!upper_rdn_attr) {
329 return ldb_operr(ldb);
332 /* Create a new child */
333 if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
334 return ldb_operr(ldb);
337 rdn_val = ldb_dn_get_rdn_val(newdn);
338 if (rdn_val == NULL) {
339 return ldb_operr(ldb);
343 /* the rules for rDN length constraints are more complex than
344 this. Until we understand them we need to leave this
345 constraint out. Otherwise we break replication, as windows
346 does sometimes send us rDNs longer than 64 */
347 if (!rdn_val || rdn_val->length > 64) {
348 DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
353 /* And replace it with CN=foo (we need the attribute in upper case */
354 return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
358 static int objectclass_do_add(struct oc_context *ac);
360 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
362 struct ldb_context *ldb;
363 struct ldb_request *search_req;
364 struct oc_context *ac;
365 struct ldb_dn *parent_dn;
366 const struct ldb_val *val;
369 static const char * const parent_attrs[] = { "objectClass", NULL };
371 ldb = ldb_module_get_ctx(module);
373 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
375 /* do not manipulate our control entries */
376 if (ldb_dn_is_special(req->op.add.message->dn)) {
377 return ldb_next_request(module, req);
380 /* An add operation on the basedn without "NC-add" operation isn't
382 if (ldb_dn_compare(ldb_get_default_basedn(ldb), req->op.add.message->dn) == 0) {
383 unsigned int instanceType;
385 instanceType = ldb_msg_find_attr_as_uint(req->op.add.message,
387 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
388 /* When we are trying to readd the root basedn then
389 * this is denied, but with an interesting mechanism:
390 * there is generated a referral with the last
391 * component value as hostname. */
392 val = ldb_dn_get_component_val(req->op.add.message->dn,
393 ldb_dn_get_comp_num(req->op.add.message->dn) - 1);
395 return ldb_operr(ldb);
397 value = talloc_asprintf(req, "ldap://%s/%s", val->data,
398 ldb_dn_get_linearized(req->op.add.message->dn));
403 return ldb_module_send_referral(req, value);
407 ac = oc_init_context(module, req);
409 return ldb_operr(ldb);
412 /* If there isn't a parent, just go on to the add processing */
413 if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
414 return objectclass_do_add(ac);
417 /* get copy of parent DN */
418 parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
419 if (parent_dn == NULL) {
423 ret = ldb_build_search_req(&search_req, ldb,
424 ac, parent_dn, LDB_SCOPE_BASE,
425 "(objectClass=*)", parent_attrs,
427 ac, get_search_callback,
429 LDB_REQ_SET_LOCATION(search_req);
430 if (ret != LDB_SUCCESS) {
434 ac->step_fn = objectclass_do_add;
436 return ldb_next_request(ac->module, search_req);
441 check if this is a special RODC nTDSDSA add
443 static bool check_rodc_ntdsdsa_add(struct oc_context *ac,
444 const struct dsdb_class *objectclass)
446 struct ldb_control *rodc_control;
448 if (strcasecmp(objectclass->lDAPDisplayName, "nTDSDSA") != 0) {
451 rodc_control = ldb_request_get_control(ac->req, LDB_CONTROL_RODC_DCPROMO_OID);
456 rodc_control->critical = false;
460 static int objectclass_do_add(struct oc_context *ac)
462 struct ldb_context *ldb;
463 struct ldb_request *add_req;
464 struct ldb_message_element *objectclass_element, *el;
465 struct ldb_message *msg;
467 struct class_list *sorted, *current;
468 const char *rdn_name = NULL;
470 const struct dsdb_class *objectclass;
471 struct ldb_dn *objectcategory;
472 int32_t systemFlags = 0;
477 ldb = ldb_module_get_ctx(ac->module);
479 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
481 /* Check if we have a valid parent - this check is needed since
482 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
483 if (ac->search_res == NULL) {
484 unsigned int instanceType;
486 /* An add operation on partition DNs without "NC-add" operation
488 instanceType = ldb_msg_find_attr_as_uint(ac->req->op.add.message,
490 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
491 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!",
492 ldb_dn_get_linearized(msg->dn));
493 return LDB_ERR_NO_SUCH_OBJECT;
496 /* Don't keep any error messages - we've to add a partition */
497 ldb_set_errstring(ldb, NULL);
499 /* Fix up the DN to be in the standard form, taking
500 * particular care to match the parent DN */
501 ret = fix_dn(ldb, msg,
502 ac->req->op.add.message->dn,
503 ac->search_res->message->dn,
505 if (ret != LDB_SUCCESS) {
506 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
507 ldb_dn_get_linearized(ac->req->op.add.message->dn));
512 mem_ctx = talloc_new(ac);
513 if (mem_ctx == NULL) {
517 if (ac->schema != NULL) {
518 objectclass_element = ldb_msg_find_element(msg, "objectClass");
519 if (!objectclass_element) {
520 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, no objectclass specified!",
521 ldb_dn_get_linearized(msg->dn));
522 talloc_free(mem_ctx);
523 return LDB_ERR_OBJECT_CLASS_VIOLATION;
525 if (objectclass_element->num_values == 0) {
526 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, at least one (structural) objectclass has to be specified!",
527 ldb_dn_get_linearized(msg->dn));
528 talloc_free(mem_ctx);
529 return LDB_ERR_CONSTRAINT_VIOLATION;
532 /* Here we do now get the "objectClass" list from the
534 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
535 objectclass_element, &sorted);
536 if (ret != LDB_SUCCESS) {
537 talloc_free(mem_ctx);
541 ldb_msg_remove_element(msg, objectclass_element);
543 /* Well, now we shouldn't find any additional "objectClass"
544 * message element (required by the AD specification). */
545 objectclass_element = ldb_msg_find_element(msg, "objectClass");
546 if (objectclass_element != NULL) {
547 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, only one 'objectclass' attribute specification is allowed!",
548 ldb_dn_get_linearized(msg->dn));
549 talloc_free(mem_ctx);
550 return LDB_ERR_OBJECT_CLASS_VIOLATION;
553 /* We must completely replace the existing objectClass entry,
554 * because we need it sorted. */
555 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
556 if (ret != LDB_SUCCESS) {
557 talloc_free(mem_ctx);
561 /* Move from the linked list back into an ldb msg */
562 for (current = sorted; current; current = current->next) {
563 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
565 talloc_free(mem_ctx);
569 ret = ldb_msg_add_string(msg, "objectClass", value);
570 if (ret != LDB_SUCCESS) {
571 ldb_set_errstring(ldb,
572 "objectclass: could not re-add sorted "
573 "objectclass to modify msg");
574 talloc_free(mem_ctx);
579 talloc_free(mem_ctx);
581 /* Retrive the message again so get_last_structural_class works */
582 objectclass_element = ldb_msg_find_element(msg, "objectClass");
584 /* Make sure its valid to add an object of this type */
585 objectclass = get_last_structural_class(ac->schema,
586 objectclass_element);
587 if(objectclass == NULL) {
588 ldb_asprintf_errstring(ldb,
589 "Failed to find a structural class for %s",
590 ldb_dn_get_linearized(msg->dn));
591 return LDB_ERR_UNWILLING_TO_PERFORM;
594 rdn_name = ldb_dn_get_rdn_name(msg->dn);
595 if (rdn_name == NULL) {
596 return ldb_operr(ldb);
599 for (i = 0; (!found) && (i < objectclass_element->num_values);
601 const struct dsdb_class *tmp_class =
602 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
603 &objectclass_element->values[i]);
605 if (tmp_class == NULL) continue;
607 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
611 ldb_asprintf_errstring(ldb,
612 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
613 rdn_name, objectclass->lDAPDisplayName);
614 return LDB_ERR_NAMING_VIOLATION;
617 if (objectclass->systemOnly &&
618 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) &&
619 !check_rodc_ntdsdsa_add(ac, objectclass)) {
620 ldb_asprintf_errstring(ldb, "objectClass %s is systemOnly, rejecting creation of %s",
621 objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
622 return LDB_ERR_UNWILLING_TO_PERFORM;
625 if (((strcmp(objectclass->lDAPDisplayName, "secret") == 0) ||
626 (strcmp(objectclass->lDAPDisplayName, "trustedDomain") == 0)) &&
627 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
628 ldb_asprintf_errstring(ldb, "objectClass %s is LSA-specific, rejecting creation of %s",
629 objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
630 return LDB_ERR_UNWILLING_TO_PERFORM;
633 if (ac->search_res && ac->search_res->message) {
634 struct ldb_message_element *oc_el
635 = ldb_msg_find_element(ac->search_res->message, "objectClass");
637 bool allowed_class = false;
638 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
639 const struct dsdb_class *sclass;
641 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
644 /* We don't know this class? what is going on? */
647 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
648 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
649 allowed_class = true;
655 if (!allowed_class) {
656 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
657 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
658 return LDB_ERR_NAMING_VIOLATION;
662 objectcategory = ldb_msg_find_attr_as_dn(ldb, ac, msg,
664 if (objectcategory == NULL) {
665 struct dsdb_extended_dn_store_format *dn_format =
666 talloc_get_type(ldb_module_get_private(ac->module),
667 struct dsdb_extended_dn_store_format);
668 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
669 /* Strip off extended components */
670 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
671 objectclass->defaultObjectCategory);
672 value = ldb_dn_alloc_linearized(msg, dn);
675 value = talloc_strdup(msg,
676 objectclass->defaultObjectCategory);
682 ret = ldb_msg_add_string(msg, "objectCategory", value);
683 if (ret != LDB_SUCCESS) {
687 const struct dsdb_class *ocClass =
688 dsdb_class_by_cn_ldb_val(ac->schema,
689 ldb_dn_get_rdn_val(objectcategory));
690 if (ocClass != NULL) {
691 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
692 ocClass->defaultObjectCategory);
693 if (ldb_dn_compare(objectcategory, dn) != 0) {
697 talloc_free(objectcategory);
698 if (ocClass == NULL) {
699 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'objectCategory' attribute invalid!",
700 ldb_dn_get_linearized(msg->dn));
701 return LDB_ERR_OBJECT_CLASS_VIOLATION;
705 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
706 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
710 /* There are very special rules for systemFlags, see MS-ADTS
711 * MS-ADTS 3.1.1.5.2.4 */
713 el = ldb_msg_find_element(msg, "systemFlags");
714 if ((el != NULL) && (el->num_values > 1)) {
715 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'systemFlags' attribute multivalued!",
716 ldb_dn_get_linearized(msg->dn));
717 return LDB_ERR_CONSTRAINT_VIOLATION;
720 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
722 ldb_msg_remove_attr(msg, "systemFlags");
724 /* Only the following flags may be set by a client */
725 if (ldb_request_get_control(ac->req,
726 LDB_CONTROL_RELAX_OID) == NULL) {
727 systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME
728 | SYSTEM_FLAG_CONFIG_ALLOW_MOVE
729 | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE
730 | SYSTEM_FLAG_ATTR_IS_RDN );
733 /* But the last one ("ATTR_IS_RDN") is only allowed on
734 * "attributeSchema" objects. So truncate if it does not fit. */
735 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") != 0) {
736 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
739 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
740 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
741 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
742 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serversContainer") == 0
743 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") == 0) {
744 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
746 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
747 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
748 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
749 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
752 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
754 if (el || systemFlags != 0) {
755 ret = samdb_msg_add_int(ldb, msg, msg, "systemFlags",
757 if (ret != LDB_SUCCESS) {
762 /* make sure that "isCriticalSystemObject" is not specified! */
763 el = ldb_msg_find_element(msg, "isCriticalSystemObject");
765 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
766 ldb_set_errstring(ldb,
767 "objectclass: 'isCriticalSystemObject' must not be specified!");
768 return LDB_ERR_UNWILLING_TO_PERFORM;
772 ret = ldb_msg_sanity_check(ldb, msg);
773 if (ret != LDB_SUCCESS) {
777 ret = ldb_build_add_req(&add_req, ldb, ac,
782 LDB_REQ_SET_LOCATION(add_req);
783 if (ret != LDB_SUCCESS) {
787 /* perform the add */
788 return ldb_next_request(ac->module, add_req);
791 static int oc_modify_callback(struct ldb_request *req,
792 struct ldb_reply *ares);
793 static int objectclass_do_mod(struct oc_context *ac);
795 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
797 struct ldb_context *ldb = ldb_module_get_ctx(module);
798 struct ldb_message_element *objectclass_element;
799 struct ldb_message *msg;
800 struct ldb_request *down_req;
801 struct oc_context *ac;
802 bool oc_changes = false;
805 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
807 /* do not manipulate our control entries */
808 if (ldb_dn_is_special(req->op.mod.message->dn)) {
809 return ldb_next_request(module, req);
812 /* As with the "real" AD we don't accept empty messages */
813 if (req->op.mod.message->num_elements == 0) {
814 ldb_set_errstring(ldb, "objectclass: modify message must have "
815 "elements/attributes!");
816 return LDB_ERR_UNWILLING_TO_PERFORM;
819 ac = oc_init_context(module, req);
821 return ldb_operr(ldb);
824 /* Without schema, there isn't much to do here */
825 if (ac->schema == NULL) {
827 return ldb_next_request(module, req);
830 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
832 return ldb_operr(ldb);
835 /* For now change everything except the objectclasses */
837 objectclass_element = ldb_msg_find_element(msg, "objectClass");
838 if (objectclass_element != NULL) {
839 ldb_msg_remove_attr(msg, "objectClass");
843 /* MS-ADTS 3.1.1.5.3.5 - on a forest level < 2003 we do allow updates
844 * only on application NCs - not on the standard DCs */
846 (dsdb_forest_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
847 int cnt = samdb_search_count(ldb, ac,
848 ldb_get_default_basedn(ldb),
849 "(distinguishedName=%s)",
850 ldb_dn_get_linearized(req->op.mod.message->dn));
852 cnt = samdb_search_count(ldb, ac,
853 ldb_get_config_basedn(ldb),
854 "(distinguishedName=%s)",
855 ldb_dn_get_linearized(req->op.mod.message->dn));
858 cnt = samdb_search_count(ldb, ac,
859 ldb_get_schema_basedn(ldb),
860 "(distinguishedName=%s)",
861 ldb_dn_get_linearized(req->op.mod.message->dn));
864 return LDB_ERR_UNWILLING_TO_PERFORM;
868 ret = ldb_build_mod_req(&down_req, ldb, ac,
871 oc_changes ? oc_modify_callback : oc_op_callback,
873 LDB_REQ_SET_LOCATION(down_req);
874 if (ret != LDB_SUCCESS) {
878 return ldb_next_request(module, down_req);
881 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
883 static const char * const attrs[] = { "objectClass", NULL };
884 struct ldb_context *ldb;
885 struct ldb_request *search_req;
886 struct oc_context *ac;
889 ac = talloc_get_type(req->context, struct oc_context);
890 ldb = ldb_module_get_ctx(ac->module);
893 return ldb_module_done(ac->req, NULL, NULL,
894 LDB_ERR_OPERATIONS_ERROR);
897 if (ares->type == LDB_REPLY_REFERRAL) {
898 return ldb_module_send_referral(ac->req, ares->referral);
901 if (ares->error != LDB_SUCCESS) {
902 return ldb_module_done(ac->req, ares->controls,
903 ares->response, ares->error);
906 if (ares->type != LDB_REPLY_DONE) {
908 return ldb_module_done(ac->req, NULL, NULL,
909 LDB_ERR_OPERATIONS_ERROR);
914 /* this looks up the real existing object for fetching some important
915 * informations (objectclasses) */
916 ret = ldb_build_search_req(&search_req, ldb,
917 ac, ac->req->op.mod.message->dn,
921 ac, get_search_callback,
923 LDB_REQ_SET_LOCATION(search_req);
924 if (ret != LDB_SUCCESS) {
925 return ldb_module_done(ac->req, NULL, NULL, ret);
928 ac->step_fn = objectclass_do_mod;
930 ret = ldb_next_request(ac->module, search_req);
931 if (ret != LDB_SUCCESS) {
932 return ldb_module_done(ac->req, NULL, NULL, ret);
938 static int objectclass_do_mod(struct oc_context *ac)
940 struct ldb_context *ldb;
941 struct ldb_request *mod_req;
943 struct ldb_message_element *oc_el_entry, *oc_el_change;
944 struct ldb_val *vals;
945 struct ldb_message *msg;
947 struct class_list *sorted, *current;
948 const struct dsdb_class *objectclass;
949 unsigned int i, j, k;
950 bool found, replace = false;
953 ldb = ldb_module_get_ctx(ac->module);
955 /* we should always have a valid entry when we enter here */
956 if (ac->search_res == NULL) {
957 return ldb_operr(ldb);
960 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
962 if (oc_el_entry == NULL) {
963 /* existing entry without a valid object class? */
964 return ldb_operr(ldb);
967 /* use a new message structure */
968 msg = ldb_msg_new(ac);
973 msg->dn = ac->req->op.mod.message->dn;
975 mem_ctx = talloc_new(ac);
976 if (mem_ctx == NULL) {
980 /* We've to walk over all "objectClass" message elements */
981 for (k = 0; k < ac->req->op.mod.message->num_elements; k++) {
982 if (ldb_attr_cmp(ac->req->op.mod.message->elements[k].name,
983 "objectClass") != 0) {
987 oc_el_change = &ac->req->op.mod.message->elements[k];
989 switch (oc_el_change->flags & LDB_FLAG_MOD_MASK) {
990 case LDB_FLAG_MOD_ADD:
991 /* Merge the two message elements */
992 for (i = 0; i < oc_el_change->num_values; i++) {
993 for (j = 0; j < oc_el_entry->num_values; j++) {
994 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
995 (char *)oc_el_entry->values[j].data) == 0) {
996 ldb_asprintf_errstring(ldb,
997 "objectclass: cannot re-add an existing objectclass: '%.*s'!",
998 (int)oc_el_change->values[i].length,
999 (const char *)oc_el_change->values[i].data);
1000 talloc_free(mem_ctx);
1001 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1004 /* append the new object class value - code was
1005 * copied from "ldb_msg_add_value" */
1006 vals = talloc_realloc(oc_el_entry, oc_el_entry->values,
1008 oc_el_entry->num_values + 1);
1010 talloc_free(mem_ctx);
1011 return ldb_oom(ldb);
1013 oc_el_entry->values = vals;
1014 oc_el_entry->values[oc_el_entry->num_values] =
1015 oc_el_change->values[i];
1016 ++(oc_el_entry->num_values);
1019 objectclass = get_last_structural_class(ac->schema,
1021 if (objectclass != NULL) {
1022 ldb_asprintf_errstring(ldb,
1023 "objectclass: cannot add a new top-most structural objectclass '%s'!",
1024 objectclass->lDAPDisplayName);
1025 talloc_free(mem_ctx);
1026 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1029 /* Now do the sorting */
1030 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1031 oc_el_entry, &sorted);
1032 if (ret != LDB_SUCCESS) {
1033 talloc_free(mem_ctx);
1039 case LDB_FLAG_MOD_REPLACE:
1040 /* Do the sorting for the change message element */
1041 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1042 oc_el_change, &sorted);
1043 if (ret != LDB_SUCCESS) {
1044 talloc_free(mem_ctx);
1048 /* this is a replace */
1053 case LDB_FLAG_MOD_DELETE:
1054 /* get the actual top-most structural objectclass */
1055 objectclass = get_last_structural_class(ac->schema,
1057 if (objectclass == NULL) {
1058 talloc_free(mem_ctx);
1059 return ldb_operr(ldb);
1062 /* Merge the two message elements */
1063 for (i = 0; i < oc_el_change->num_values; i++) {
1065 for (j = 0; j < oc_el_entry->num_values; j++) {
1066 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
1067 (char *)oc_el_entry->values[j].data) == 0) {
1069 /* delete the object class value
1070 * - code was copied from
1071 * "ldb_msg_remove_element" */
1072 if (j != oc_el_entry->num_values - 1) {
1073 memmove(&oc_el_entry->values[j],
1074 &oc_el_entry->values[j+1],
1075 ((oc_el_entry->num_values-1) - j)*sizeof(struct ldb_val));
1077 --(oc_el_entry->num_values);
1082 /* we cannot delete a not existing
1084 ldb_asprintf_errstring(ldb,
1085 "objectclass: cannot delete this objectclass: '%.*s'!",
1086 (int)oc_el_change->values[i].length,
1087 (const char *)oc_el_change->values[i].data);
1088 talloc_free(mem_ctx);
1089 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1093 /* Make sure that the top-most structural object class
1094 * hasn't been deleted */
1096 for (i = 0; i < oc_el_entry->num_values; i++) {
1097 if (ldb_attr_cmp(objectclass->lDAPDisplayName,
1098 (char *)oc_el_entry->values[i].data) == 0) {
1104 ldb_asprintf_errstring(ldb,
1105 "objectclass: cannot delete the top-most structural objectclass '%s'!",
1106 objectclass->lDAPDisplayName);
1107 talloc_free(mem_ctx);
1108 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1111 /* Now do the sorting */
1112 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1113 oc_el_entry, &sorted);
1114 if (ret != LDB_SUCCESS) {
1115 talloc_free(mem_ctx);
1122 /* (Re)-add an empty "objectClass" attribute on the object
1123 * classes change message "msg". */
1124 ldb_msg_remove_attr(msg, "objectClass");
1125 ret = ldb_msg_add_empty(msg, "objectClass",
1126 LDB_FLAG_MOD_REPLACE, &oc_el_change);
1127 if (ret != LDB_SUCCESS) {
1128 talloc_free(mem_ctx);
1129 return ldb_oom(ldb);
1132 /* Move from the linked list back into an ldb msg */
1133 for (current = sorted; current; current = current->next) {
1134 value = talloc_strdup(msg,
1135 current->objectclass->lDAPDisplayName);
1136 if (value == NULL) {
1137 talloc_free(mem_ctx);
1138 return ldb_oom(ldb);
1140 ret = ldb_msg_add_string(msg, "objectClass", value);
1141 if (ret != LDB_SUCCESS) {
1142 ldb_set_errstring(ldb,
1143 "objectclass: could not re-add sorted objectclasses!");
1144 talloc_free(mem_ctx);
1150 /* Well, on replace we are nearly done: we have to test
1151 * if the change and entry message element are identical
1152 * ly. We can use "ldb_msg_element_compare" since now
1153 * the specified objectclasses match for sure in case.
1155 ret = ldb_msg_element_compare(oc_el_entry,
1158 ret = ldb_msg_element_compare(oc_el_change,
1162 /* they are the same so we are done in this
1164 talloc_free(mem_ctx);
1165 return ldb_module_done(ac->req, NULL, NULL,
1168 ldb_set_errstring(ldb,
1169 "objectclass: the specified objectclasses are not exactly the same as on the entry!");
1170 talloc_free(mem_ctx);
1171 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1175 /* Now we've applied all changes from "oc_el_change" to
1176 * "oc_el_entry" therefore the new "oc_el_entry" will be
1177 * "oc_el_change". */
1178 oc_el_entry = oc_el_change;
1181 talloc_free(mem_ctx);
1183 /* Now we have the real and definitive change left to do */
1185 ret = ldb_build_mod_req(&mod_req, ldb, ac,
1190 LDB_REQ_SET_LOCATION(mod_req);
1191 if (ret != LDB_SUCCESS) {
1195 return ldb_next_request(ac->module, mod_req);
1198 static int objectclass_do_rename(struct oc_context *ac);
1200 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1202 static const char * const attrs[] = { "objectClass", NULL };
1203 struct ldb_context *ldb;
1204 struct ldb_request *search_req;
1205 struct oc_context *ac;
1206 struct ldb_dn *parent_dn;
1209 ldb = ldb_module_get_ctx(module);
1211 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1213 /* do not manipulate our control entries */
1214 if (ldb_dn_is_special(req->op.rename.newdn)) {
1215 return ldb_next_request(module, req);
1218 ac = oc_init_context(module, req);
1220 return ldb_operr(ldb);
1223 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1224 if (parent_dn == NULL) {
1225 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, the parent DN does not exist!",
1226 ldb_dn_get_linearized(req->op.rename.olddn));
1227 return LDB_ERR_NO_SUCH_OBJECT;
1230 /* this looks up the parent object for fetching some important
1231 * informations (objectclasses, DN normalisation...) */
1232 ret = ldb_build_search_req(&search_req, ldb,
1233 ac, parent_dn, LDB_SCOPE_BASE,
1236 ac, get_search_callback,
1238 LDB_REQ_SET_LOCATION(search_req);
1239 if (ret != LDB_SUCCESS) {
1243 /* we have to add the show recycled control, as otherwise DRS
1244 deletes will be refused as we will think the target parent
1246 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
1249 if (ret != LDB_SUCCESS) {
1253 ac->step_fn = objectclass_do_rename;
1255 return ldb_next_request(ac->module, search_req);
1258 static int objectclass_do_rename2(struct oc_context *ac);
1260 static int objectclass_do_rename(struct oc_context *ac)
1262 static const char * const attrs[] = { "objectClass", NULL };
1263 struct ldb_context *ldb;
1264 struct ldb_request *search_req;
1267 ldb = ldb_module_get_ctx(ac->module);
1269 /* Check if we have a valid parent - this check is needed since
1270 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1271 if (ac->search_res == NULL) {
1272 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1273 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1274 return LDB_ERR_OTHER;
1277 /* now assign "search_res2" to the parent entry to have "search_res"
1278 * free for another lookup */
1279 ac->search_res2 = ac->search_res;
1280 ac->search_res = NULL;
1282 /* this looks up the real existing object for fetching some important
1283 * informations (objectclasses) */
1284 ret = ldb_build_search_req(&search_req, ldb,
1285 ac, ac->req->op.rename.olddn,
1289 ac, get_search_callback,
1291 LDB_REQ_SET_LOCATION(search_req);
1292 if (ret != LDB_SUCCESS) {
1296 ac->step_fn = objectclass_do_rename2;
1298 return ldb_next_request(ac->module, search_req);
1301 static int objectclass_do_rename2(struct oc_context *ac)
1303 struct ldb_context *ldb;
1304 struct ldb_request *rename_req;
1305 struct ldb_dn *fixed_dn;
1308 ldb = ldb_module_get_ctx(ac->module);
1310 /* Check if we have a valid entry - this check is needed since
1311 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1312 if (ac->search_res == NULL) {
1313 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, entry does not exist!",
1314 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1315 return LDB_ERR_NO_SUCH_OBJECT;
1318 if (ac->schema != NULL) {
1319 struct ldb_message_element *oc_el_entry, *oc_el_parent;
1320 const struct dsdb_class *objectclass;
1321 const char *rdn_name;
1322 bool allowed_class = false;
1326 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1328 if (oc_el_entry == NULL) {
1329 /* existing entry without a valid object class? */
1330 return ldb_operr(ldb);
1332 objectclass = get_last_structural_class(ac->schema, oc_el_entry);
1333 if (objectclass == NULL) {
1334 /* existing entry without a valid object class? */
1335 return ldb_operr(ldb);
1338 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
1339 if (rdn_name == NULL) {
1340 return ldb_operr(ldb);
1343 for (i = 0; (!found) && (i < oc_el_entry->num_values); i++) {
1344 const struct dsdb_class *tmp_class =
1345 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1346 &oc_el_entry->values[i]);
1348 if (tmp_class == NULL) continue;
1350 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
1354 ldb_asprintf_errstring(ldb,
1355 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
1356 rdn_name, objectclass->lDAPDisplayName);
1357 return LDB_ERR_UNWILLING_TO_PERFORM;
1360 oc_el_parent = ldb_msg_find_element(ac->search_res2->message,
1362 if (oc_el_parent == NULL) {
1363 /* existing entry without a valid object class? */
1364 return ldb_operr(ldb);
1367 for (i=0; allowed_class == false && i < oc_el_parent->num_values; i++) {
1368 const struct dsdb_class *sclass;
1370 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1371 &oc_el_parent->values[i]);
1373 /* We don't know this class? what is going on? */
1376 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
1377 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
1378 allowed_class = true;
1384 if (!allowed_class) {
1385 ldb_asprintf_errstring(ldb,
1386 "objectclass: structural objectClass %s is not a valid child class for %s",
1387 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res2->message->dn));
1388 return LDB_ERR_NAMING_VIOLATION;
1392 /* Ensure we are not trying to rename it to be a child of itself */
1393 if ((ldb_dn_compare_base(ac->req->op.rename.olddn,
1394 ac->req->op.rename.newdn) == 0) &&
1395 (ldb_dn_compare(ac->req->op.rename.olddn,
1396 ac->req->op.rename.newdn) != 0)) {
1397 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s to be a child of itself",
1398 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1399 return LDB_ERR_UNWILLING_TO_PERFORM;
1402 /* Fix up the DN to be in the standard form, taking
1403 * particular care to match the parent DN */
1404 ret = fix_dn(ldb, ac,
1405 ac->req->op.rename.newdn,
1406 ac->search_res2->message->dn,
1408 if (ret != LDB_SUCCESS) {
1409 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
1410 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1415 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1416 ac->req->op.rename.olddn, fixed_dn,
1420 LDB_REQ_SET_LOCATION(rename_req);
1421 if (ret != LDB_SUCCESS) {
1425 /* perform the rename */
1426 return ldb_next_request(ac->module, rename_req);
1429 static int objectclass_do_delete(struct oc_context *ac);
1431 static int objectclass_delete(struct ldb_module *module, struct ldb_request *req)
1433 static const char * const attrs[] = { "nCName", "objectClass",
1435 "isCriticalSystemObject", NULL };
1436 struct ldb_context *ldb;
1437 struct ldb_request *search_req;
1438 struct oc_context *ac;
1441 ldb = ldb_module_get_ctx(module);
1443 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_delete\n");
1445 /* do not manipulate our control entries */
1446 if (ldb_dn_is_special(req->op.del.dn)) {
1447 return ldb_next_request(module, req);
1450 /* Bypass the constraint checks when we do have the "RELAX" control
1452 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) != NULL) {
1453 return ldb_next_request(module, req);
1456 ac = oc_init_context(module, req);
1458 return ldb_operr(ldb);
1461 /* this looks up the entry object for fetching some important
1462 * informations (object classes, system flags...) */
1463 ret = ldb_build_search_req(&search_req, ldb,
1464 ac, req->op.del.dn, LDB_SCOPE_BASE,
1467 ac, get_search_callback,
1469 LDB_REQ_SET_LOCATION(search_req);
1470 if (ret != LDB_SUCCESS) {
1474 ac->step_fn = objectclass_do_delete;
1476 return ldb_next_request(ac->module, search_req);
1479 static int objectclass_do_delete(struct oc_context *ac)
1481 struct ldb_context *ldb;
1483 int32_t systemFlags;
1484 bool isCriticalSystemObject;
1487 ldb = ldb_module_get_ctx(ac->module);
1489 /* Check if we have a valid entry - this check is needed since
1490 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1491 if (ac->search_res == NULL) {
1492 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, entry does not exist!",
1493 ldb_dn_get_linearized(ac->req->op.del.dn));
1494 return LDB_ERR_NO_SUCH_OBJECT;
1497 /* DC's ntDSDSA object */
1498 if (ldb_dn_compare(ac->req->op.del.dn, samdb_ntds_settings_dn(ldb)) == 0) {
1499 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's ntDSDSA object!",
1500 ldb_dn_get_linearized(ac->req->op.del.dn));
1501 return LDB_ERR_UNWILLING_TO_PERFORM;
1504 /* DC's rIDSet object */
1505 /* Perform this check only when it does exist - this is needed in order
1506 * to don't let existing provisions break. */
1507 ret = samdb_rid_set_dn(ldb, ac, &dn);
1508 if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
1511 if (ret == LDB_SUCCESS) {
1512 if (ldb_dn_compare(ac->req->op.del.dn, dn) == 0) {
1514 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's rIDSet object!",
1515 ldb_dn_get_linearized(ac->req->op.del.dn));
1516 return LDB_ERR_UNWILLING_TO_PERFORM;
1521 /* crossRef objects regarding config, schema and default domain NCs */
1522 if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass",
1523 "crossRef") != NULL) {
1524 dn = ldb_msg_find_attr_as_dn(ldb, ac, ac->search_res->message,
1526 if ((ldb_dn_compare(dn, ldb_get_default_basedn(ldb)) == 0) ||
1527 (ldb_dn_compare(dn, ldb_get_config_basedn(ldb)) == 0)) {
1530 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the main or configuration partition!",
1531 ldb_dn_get_linearized(ac->req->op.del.dn));
1532 return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF;
1534 if (ldb_dn_compare(dn, ldb_get_schema_basedn(ldb)) == 0) {
1537 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the schema partition!",
1538 ldb_dn_get_linearized(ac->req->op.del.dn));
1539 return LDB_ERR_UNWILLING_TO_PERFORM;
1546 systemFlags = ldb_msg_find_attr_as_int(ac->search_res->message,
1548 if ((systemFlags & SYSTEM_FLAG_DISALLOW_DELETE) != 0) {
1549 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it isn't permitted!",
1550 ldb_dn_get_linearized(ac->req->op.del.dn));
1551 return LDB_ERR_UNWILLING_TO_PERFORM;
1554 /* isCriticalSystemObject - but this only applies on tree delete
1555 * operations - MS-ADTS 3.1.1.5.5.7.2 */
1556 if (ldb_request_get_control(ac->req, LDB_CONTROL_TREE_DELETE_OID) != NULL) {
1557 isCriticalSystemObject = ldb_msg_find_attr_as_bool(ac->search_res->message,
1558 "isCriticalSystemObject", false);
1559 if (isCriticalSystemObject) {
1560 ldb_asprintf_errstring(ldb,
1561 "objectclass: Cannot tree-delete %s, it's a critical system object!",
1562 ldb_dn_get_linearized(ac->req->op.del.dn));
1563 return LDB_ERR_UNWILLING_TO_PERFORM;
1567 return ldb_next_request(ac->module, ac->req);
1570 static int objectclass_init(struct ldb_module *module)
1572 struct ldb_context *ldb = ldb_module_get_ctx(module);
1575 /* Init everything else */
1576 ret = ldb_next_init(module);
1577 if (ret != LDB_SUCCESS) {
1581 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1582 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1584 ret = ldb_mod_register_control(module, LDB_CONTROL_RODC_DCPROMO_OID);
1585 if (ret != LDB_SUCCESS) {
1586 ldb_debug(ldb, LDB_DEBUG_ERROR,
1587 "objectclass_init: Unable to register control DCPROMO with rootdse\n");
1588 return ldb_operr(ldb);
1594 static const struct ldb_module_ops ldb_objectclass_module_ops = {
1595 .name = "objectclass",
1596 .add = objectclass_add,
1597 .modify = objectclass_modify,
1598 .rename = objectclass_rename,
1599 .del = objectclass_delete,
1600 .init_context = objectclass_init
1603 int ldb_objectclass_module_init(const char *version)
1605 LDB_MODULE_CHECK_VERSION(version);
1606 return ldb_register_module(&ldb_objectclass_module_ops);