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
323 * match the parent DN */
324 *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
325 if (*fixed_dn == NULL) {
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 == NULL) {
336 /* Create a new child */
337 if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
338 return ldb_operr(ldb);
341 rdn_val = ldb_dn_get_rdn_val(newdn);
342 if (rdn_val == NULL) {
343 return ldb_operr(ldb);
347 /* the rules for rDN length constraints are more complex than
348 this. Until we understand them we need to leave this
349 constraint out. Otherwise we break replication, as windows
350 does sometimes send us rDNs longer than 64 */
351 if (!rdn_val || rdn_val->length > 64) {
352 DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
357 /* And replace it with CN=foo (we need the attribute in upper case */
358 return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
362 static int objectclass_do_add(struct oc_context *ac);
364 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
366 struct ldb_context *ldb;
367 struct ldb_request *search_req;
368 struct oc_context *ac;
369 struct ldb_dn *parent_dn;
370 const struct ldb_val *val;
372 static const char * const parent_attrs[] = { "objectClass", NULL };
374 ldb = ldb_module_get_ctx(module);
376 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
378 /* do not manipulate our control entries */
379 if (ldb_dn_is_special(req->op.add.message->dn)) {
380 return ldb_next_request(module, req);
383 /* An add operation on the basedn without "NC-add" operation isn't
385 if (ldb_dn_compare(ldb_get_default_basedn(ldb), req->op.add.message->dn) == 0) {
386 unsigned int instanceType;
388 instanceType = ldb_msg_find_attr_as_uint(req->op.add.message,
390 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
392 /* When we are trying to readd the root basedn then
393 * this is denied, but with an interesting mechanism:
394 * there is generated a referral with the last
395 * component value as hostname. */
396 val = ldb_dn_get_component_val(req->op.add.message->dn,
397 ldb_dn_get_comp_num(req->op.add.message->dn) - 1);
399 return ldb_operr(ldb);
401 referral_uri = talloc_asprintf(req, "ldap://%s/%s", val->data,
402 ldb_dn_get_linearized(req->op.add.message->dn));
403 if (referral_uri == NULL) {
404 return ldb_module_oom(module);
407 return ldb_module_send_referral(req, referral_uri);
411 ac = oc_init_context(module, req);
413 return ldb_operr(ldb);
416 /* If there isn't a parent, just go on to the add processing */
417 if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
418 return objectclass_do_add(ac);
421 /* get copy of parent DN */
422 parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
423 if (parent_dn == NULL) {
424 return ldb_operr(ldb);
427 ret = ldb_build_search_req(&search_req, ldb,
428 ac, parent_dn, LDB_SCOPE_BASE,
429 "(objectClass=*)", parent_attrs,
431 ac, get_search_callback,
433 LDB_REQ_SET_LOCATION(search_req);
434 if (ret != LDB_SUCCESS) {
438 ac->step_fn = objectclass_do_add;
439 ldb_req_mark_trusted(search_req);
441 return ldb_next_request(ac->module, search_req);
446 check if this is a special RODC nTDSDSA add
448 static bool check_rodc_ntdsdsa_add(struct oc_context *ac,
449 const struct dsdb_class *objectclass)
451 struct ldb_control *rodc_control;
453 if (strcasecmp(objectclass->lDAPDisplayName, "nTDSDSA") != 0) {
456 rodc_control = ldb_request_get_control(ac->req, LDB_CONTROL_RODC_DCPROMO_OID);
461 rodc_control->critical = false;
465 static int objectclass_do_add(struct oc_context *ac)
467 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
468 struct ldb_request *add_req;
469 struct ldb_message_element *objectclass_element, *el;
470 struct ldb_message *msg;
472 struct class_list *sorted, *current;
473 const char *rdn_name = NULL;
475 const struct dsdb_class *objectclass;
476 struct ldb_dn *objectcategory;
477 int32_t systemFlags = 0;
482 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
484 return ldb_module_oom(ac->module);
487 /* Check if we have a valid parent - this check is needed since
488 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
489 if (ac->search_res == NULL) {
490 unsigned int instanceType;
492 /* An add operation on partition DNs without "NC-add" operation
494 instanceType = ldb_msg_find_attr_as_uint(msg, "instanceType",
496 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
497 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!",
498 ldb_dn_get_linearized(msg->dn));
499 return LDB_ERR_NO_SUCH_OBJECT;
502 /* Don't keep any error messages - we've to add a partition */
503 ldb_set_errstring(ldb, NULL);
505 /* Fix up the DN to be in the standard form, taking
506 * particular care to match the parent DN */
507 ret = fix_dn(ldb, msg,
508 ac->req->op.add.message->dn,
509 ac->search_res->message->dn,
511 if (ret != LDB_SUCCESS) {
512 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
513 ldb_dn_get_linearized(ac->req->op.add.message->dn));
518 if (ac->schema != NULL) {
519 objectclass_element = ldb_msg_find_element(msg, "objectClass");
520 if (!objectclass_element) {
521 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, no objectclass specified!",
522 ldb_dn_get_linearized(msg->dn));
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 return LDB_ERR_CONSTRAINT_VIOLATION;
531 mem_ctx = talloc_new(ac);
532 if (mem_ctx == NULL) {
533 return ldb_module_oom(ac->module);
536 /* Here we do now get the "objectClass" list from the
538 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
539 objectclass_element, &sorted);
540 if (ret != LDB_SUCCESS) {
541 talloc_free(mem_ctx);
545 ldb_msg_remove_element(msg, objectclass_element);
547 /* Well, now we shouldn't find any additional "objectClass"
548 * message element (required by the AD specification). */
549 objectclass_element = ldb_msg_find_element(msg, "objectClass");
550 if (objectclass_element != NULL) {
551 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, only one 'objectclass' attribute specification is allowed!",
552 ldb_dn_get_linearized(msg->dn));
553 talloc_free(mem_ctx);
554 return LDB_ERR_OBJECT_CLASS_VIOLATION;
557 /* We must completely replace the existing objectClass entry,
558 * because we need it sorted. */
559 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
560 if (ret != LDB_SUCCESS) {
561 talloc_free(mem_ctx);
565 /* Move from the linked list back into an ldb msg */
566 for (current = sorted; current; current = current->next) {
567 const char *objectclass_name = current->objectclass->lDAPDisplayName;
569 ret = ldb_msg_add_string(msg, "objectClass", objectclass_name);
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, ac->req);
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,
621 "objectclass: object class '%s' is system-only, rejecting creation of '%s'!",
622 objectclass->lDAPDisplayName,
623 ldb_dn_get_linearized(msg->dn));
624 return LDB_ERR_UNWILLING_TO_PERFORM;
627 if (ac->search_res && ac->search_res->message) {
628 struct ldb_message_element *oc_el
629 = ldb_msg_find_element(ac->search_res->message, "objectClass");
631 bool allowed_class = false;
632 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
633 const struct dsdb_class *sclass;
635 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
638 /* We don't know this class? what is going on? */
641 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
642 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
643 allowed_class = true;
649 if (!allowed_class) {
650 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
651 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
652 return LDB_ERR_NAMING_VIOLATION;
656 objectcategory = ldb_msg_find_attr_as_dn(ldb, ac, msg,
658 if (objectcategory == NULL) {
659 struct dsdb_extended_dn_store_format *dn_format =
660 talloc_get_type(ldb_module_get_private(ac->module),
661 struct dsdb_extended_dn_store_format);
662 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
663 /* Strip off extended components */
664 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
665 objectclass->defaultObjectCategory);
666 value = ldb_dn_alloc_linearized(msg, dn);
669 value = talloc_strdup(msg,
670 objectclass->defaultObjectCategory);
673 return ldb_module_oom(ac->module);
676 ret = ldb_msg_add_string(msg, "objectCategory", value);
677 if (ret != LDB_SUCCESS) {
681 const struct dsdb_class *ocClass =
682 dsdb_class_by_cn_ldb_val(ac->schema,
683 ldb_dn_get_rdn_val(objectcategory));
684 if (ocClass != NULL) {
685 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
686 ocClass->defaultObjectCategory);
687 if (ldb_dn_compare(objectcategory, dn) != 0) {
691 talloc_free(objectcategory);
692 if (ocClass == NULL) {
693 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'objectCategory' attribute invalid!",
694 ldb_dn_get_linearized(msg->dn));
695 return LDB_ERR_OBJECT_CLASS_VIOLATION;
699 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
700 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
704 /* There are very special rules for systemFlags, see MS-ADTS
705 * MS-ADTS 3.1.1.5.2.4 */
707 el = ldb_msg_find_element(msg, "systemFlags");
708 if ((el != NULL) && (el->num_values > 1)) {
709 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'systemFlags' attribute multivalued!",
710 ldb_dn_get_linearized(msg->dn));
711 return LDB_ERR_CONSTRAINT_VIOLATION;
714 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
716 ldb_msg_remove_attr(msg, "systemFlags");
718 /* Only the following flags may be set by a client */
719 if (ldb_request_get_control(ac->req,
720 LDB_CONTROL_RELAX_OID) == NULL) {
721 systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME
722 | SYSTEM_FLAG_CONFIG_ALLOW_MOVE
723 | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE
724 | SYSTEM_FLAG_ATTR_IS_RDN );
727 /* But the last one ("ATTR_IS_RDN") is only allowed on
728 * "attributeSchema" objects. So truncate if it does not fit. */
729 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") != 0) {
730 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
733 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
734 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
735 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
736 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serversContainer") == 0
737 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") == 0) {
738 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
740 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
741 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
742 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
743 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
746 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
748 if (el || systemFlags != 0) {
749 ret = samdb_msg_add_int(ldb, msg, msg, "systemFlags",
751 if (ret != LDB_SUCCESS) {
756 /* make sure that "isCriticalSystemObject" is not specified! */
757 el = ldb_msg_find_element(msg, "isCriticalSystemObject");
759 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
760 ldb_set_errstring(ldb,
761 "objectclass: 'isCriticalSystemObject' must not be specified!");
762 return LDB_ERR_UNWILLING_TO_PERFORM;
766 ret = ldb_msg_sanity_check(ldb, msg);
767 if (ret != LDB_SUCCESS) {
771 ret = ldb_build_add_req(&add_req, ldb, ac,
776 LDB_REQ_SET_LOCATION(add_req);
777 if (ret != LDB_SUCCESS) {
781 /* perform the add */
782 return ldb_next_request(ac->module, add_req);
785 static int oc_modify_callback(struct ldb_request *req,
786 struct ldb_reply *ares);
787 static int objectclass_do_mod(struct oc_context *ac);
789 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
791 struct ldb_context *ldb = ldb_module_get_ctx(module);
792 struct ldb_message_element *objectclass_element;
793 struct ldb_message *msg;
794 struct ldb_request *down_req;
795 struct oc_context *ac;
796 bool oc_changes = false;
799 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
801 /* do not manipulate our control entries */
802 if (ldb_dn_is_special(req->op.mod.message->dn)) {
803 return ldb_next_request(module, req);
806 /* As with the "real" AD we don't accept empty messages */
807 if (req->op.mod.message->num_elements == 0) {
808 ldb_set_errstring(ldb, "objectclass: modify message must have "
809 "elements/attributes!");
810 return LDB_ERR_UNWILLING_TO_PERFORM;
813 ac = oc_init_context(module, req);
815 return ldb_operr(ldb);
818 /* Without schema, there isn't much to do here */
819 if (ac->schema == NULL) {
821 return ldb_next_request(module, req);
824 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
826 return ldb_module_oom(ac->module);
829 /* For now change everything except the objectclasses */
831 objectclass_element = ldb_msg_find_element(msg, "objectClass");
832 if (objectclass_element != NULL) {
833 ldb_msg_remove_attr(msg, "objectClass");
837 /* MS-ADTS 3.1.1.5.3.5 - on a forest level < 2003 we do allow updates
838 * only on application NCs - not on the standard DCs */
840 (dsdb_forest_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
841 struct ldb_dn *nc_root;
843 ret = dsdb_find_nc_root(ldb, ac, req->op.mod.message->dn,
845 if (ret != LDB_SUCCESS) {
849 if ((ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) == 0) ||
850 (ldb_dn_compare(nc_root, ldb_get_config_basedn(ldb)) == 0) ||
851 (ldb_dn_compare(nc_root, ldb_get_schema_basedn(ldb)) == 0)) {
852 ldb_set_errstring(ldb,
853 "objectclass: object class changes on objects under the standard name contexts not allowed!");
854 return LDB_ERR_UNWILLING_TO_PERFORM;
857 talloc_free(nc_root);
860 ret = ldb_build_mod_req(&down_req, ldb, ac,
863 oc_changes ? oc_modify_callback : oc_op_callback,
865 LDB_REQ_SET_LOCATION(down_req);
866 if (ret != LDB_SUCCESS) {
870 return ldb_next_request(module, down_req);
873 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
875 static const char * const attrs[] = { "objectClass", NULL };
876 struct ldb_context *ldb;
877 struct ldb_request *search_req;
878 struct oc_context *ac;
881 ac = talloc_get_type(req->context, struct oc_context);
882 ldb = ldb_module_get_ctx(ac->module);
885 return ldb_module_done(ac->req, NULL, NULL,
886 LDB_ERR_OPERATIONS_ERROR);
889 if (ares->type == LDB_REPLY_REFERRAL) {
890 return ldb_module_send_referral(ac->req, ares->referral);
893 if (ares->error != LDB_SUCCESS) {
894 return ldb_module_done(ac->req, ares->controls,
895 ares->response, ares->error);
898 if (ares->type != LDB_REPLY_DONE) {
900 return ldb_module_done(ac->req, NULL, NULL,
901 LDB_ERR_OPERATIONS_ERROR);
906 /* this looks up the real existing object for fetching some important
907 * informations (objectclasses) */
908 ret = ldb_build_search_req(&search_req, ldb,
909 ac, ac->req->op.mod.message->dn,
913 ac, get_search_callback,
915 LDB_REQ_SET_LOCATION(search_req);
916 if (ret != LDB_SUCCESS) {
917 return ldb_module_done(ac->req, NULL, NULL, ret);
920 ac->step_fn = objectclass_do_mod;
922 ret = ldb_next_request(ac->module, search_req);
923 if (ret != LDB_SUCCESS) {
924 return ldb_module_done(ac->req, NULL, NULL, ret);
930 static int objectclass_do_mod(struct oc_context *ac)
932 struct ldb_context *ldb;
933 struct ldb_request *mod_req;
935 struct ldb_message_element *oc_el_entry, *oc_el_change;
936 struct ldb_val *vals;
937 struct ldb_message *msg;
939 struct class_list *sorted, *current;
940 const struct dsdb_class *objectclass;
941 unsigned int i, j, k;
942 bool found, replace = false;
945 ldb = ldb_module_get_ctx(ac->module);
947 /* we should always have a valid entry when we enter here */
948 if (ac->search_res == NULL) {
949 return ldb_operr(ldb);
952 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
954 if (oc_el_entry == NULL) {
955 /* existing entry without a valid object class? */
956 return ldb_operr(ldb);
959 /* use a new message structure */
960 msg = ldb_msg_new(ac);
962 return ldb_module_oom(ac->module);
965 msg->dn = ac->req->op.mod.message->dn;
967 mem_ctx = talloc_new(ac);
968 if (mem_ctx == NULL) {
969 return ldb_module_oom(ac->module);
972 /* We've to walk over all "objectClass" message elements */
973 for (k = 0; k < ac->req->op.mod.message->num_elements; k++) {
974 if (ldb_attr_cmp(ac->req->op.mod.message->elements[k].name,
975 "objectClass") != 0) {
979 oc_el_change = &ac->req->op.mod.message->elements[k];
981 switch (oc_el_change->flags & LDB_FLAG_MOD_MASK) {
982 case LDB_FLAG_MOD_ADD:
983 /* Merge the two message elements */
984 for (i = 0; i < oc_el_change->num_values; i++) {
985 for (j = 0; j < oc_el_entry->num_values; j++) {
986 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
987 (char *)oc_el_entry->values[j].data) == 0) {
988 ldb_asprintf_errstring(ldb,
989 "objectclass: cannot re-add an existing objectclass: '%.*s'!",
990 (int)oc_el_change->values[i].length,
991 (const char *)oc_el_change->values[i].data);
992 talloc_free(mem_ctx);
993 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
996 /* append the new object class value - code was
997 * copied from "ldb_msg_add_value" */
998 vals = talloc_realloc(oc_el_entry, oc_el_entry->values,
1000 oc_el_entry->num_values + 1);
1002 talloc_free(mem_ctx);
1003 return ldb_module_oom(ac->module);
1005 oc_el_entry->values = vals;
1006 oc_el_entry->values[oc_el_entry->num_values] =
1007 oc_el_change->values[i];
1008 ++(oc_el_entry->num_values);
1011 objectclass = get_last_structural_class(ac->schema,
1012 oc_el_change, ac->req);
1013 if (objectclass != NULL) {
1014 ldb_asprintf_errstring(ldb,
1015 "objectclass: cannot add a new top-most structural objectclass '%s'!",
1016 objectclass->lDAPDisplayName);
1017 talloc_free(mem_ctx);
1018 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1021 /* Now do the sorting */
1022 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1023 oc_el_entry, &sorted);
1024 if (ret != LDB_SUCCESS) {
1025 talloc_free(mem_ctx);
1031 case LDB_FLAG_MOD_REPLACE:
1032 /* Do the sorting for the change message element */
1033 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1034 oc_el_change, &sorted);
1035 if (ret != LDB_SUCCESS) {
1036 talloc_free(mem_ctx);
1040 /* this is a replace */
1045 case LDB_FLAG_MOD_DELETE:
1046 /* get the actual top-most structural objectclass */
1047 objectclass = get_last_structural_class(ac->schema,
1048 oc_el_entry, ac->req);
1049 if (objectclass == NULL) {
1050 /* no structural objectclass? */
1051 talloc_free(mem_ctx);
1052 return ldb_operr(ldb);
1055 /* Merge the two message elements */
1056 for (i = 0; i < oc_el_change->num_values; i++) {
1058 for (j = 0; j < oc_el_entry->num_values; j++) {
1059 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
1060 (char *)oc_el_entry->values[j].data) == 0) {
1062 /* delete the object class value
1063 * - code was copied from
1064 * "ldb_msg_remove_element" */
1065 if (j != oc_el_entry->num_values - 1) {
1066 memmove(&oc_el_entry->values[j],
1067 &oc_el_entry->values[j+1],
1068 ((oc_el_entry->num_values-1) - j)*sizeof(struct ldb_val));
1070 --(oc_el_entry->num_values);
1075 /* we cannot delete a not existing
1077 ldb_asprintf_errstring(ldb,
1078 "objectclass: cannot delete this objectclass: '%.*s'!",
1079 (int)oc_el_change->values[i].length,
1080 (const char *)oc_el_change->values[i].data);
1081 talloc_free(mem_ctx);
1082 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1086 /* Make sure that the top-most structural object class
1087 * hasn't been deleted */
1089 for (i = 0; i < oc_el_entry->num_values; i++) {
1090 if (ldb_attr_cmp(objectclass->lDAPDisplayName,
1091 (char *)oc_el_entry->values[i].data) == 0) {
1097 ldb_asprintf_errstring(ldb,
1098 "objectclass: cannot delete the top-most structural objectclass '%s'!",
1099 objectclass->lDAPDisplayName);
1100 talloc_free(mem_ctx);
1101 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1104 /* Now do the sorting */
1105 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1106 oc_el_entry, &sorted);
1107 if (ret != LDB_SUCCESS) {
1108 talloc_free(mem_ctx);
1115 /* (Re)-add an empty "objectClass" attribute on the object
1116 * classes change message "msg". */
1117 ldb_msg_remove_attr(msg, "objectClass");
1118 ret = ldb_msg_add_empty(msg, "objectClass",
1119 LDB_FLAG_MOD_REPLACE, &oc_el_change);
1120 if (ret != LDB_SUCCESS) {
1121 talloc_free(mem_ctx);
1125 /* Move from the linked list back into an ldb msg */
1126 for (current = sorted; current; current = current->next) {
1127 value = talloc_strdup(msg,
1128 current->objectclass->lDAPDisplayName);
1129 if (value == NULL) {
1130 talloc_free(mem_ctx);
1131 return ldb_module_oom(ac->module);
1133 ret = ldb_msg_add_string(msg, "objectClass", value);
1134 if (ret != LDB_SUCCESS) {
1135 ldb_set_errstring(ldb,
1136 "objectclass: could not re-add sorted objectclasses!");
1137 talloc_free(mem_ctx);
1143 /* Well, on replace we are nearly done: we have to test
1144 * if the change and entry message element are identical
1145 * ly. We can use "ldb_msg_element_compare" since now
1146 * the specified objectclasses match for sure in case.
1148 ret = ldb_msg_element_compare(oc_el_entry,
1151 ret = ldb_msg_element_compare(oc_el_change,
1155 /* they are the same so we are done in this
1157 talloc_free(mem_ctx);
1158 return ldb_module_done(ac->req, NULL, NULL,
1161 ldb_set_errstring(ldb,
1162 "objectclass: the specified objectclasses are not exactly the same as on the entry!");
1163 talloc_free(mem_ctx);
1164 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1168 /* Now we've applied all changes from "oc_el_change" to
1169 * "oc_el_entry" therefore the new "oc_el_entry" will be
1170 * "oc_el_change". */
1171 oc_el_entry = oc_el_change;
1174 talloc_free(mem_ctx);
1176 /* Now we have the real and definitive change left to do */
1178 ret = ldb_build_mod_req(&mod_req, ldb, ac,
1183 LDB_REQ_SET_LOCATION(mod_req);
1184 if (ret != LDB_SUCCESS) {
1188 return ldb_next_request(ac->module, mod_req);
1191 static int objectclass_do_rename(struct oc_context *ac);
1193 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1195 static const char * const attrs[] = { "objectClass", NULL };
1196 struct ldb_context *ldb;
1197 struct ldb_request *search_req;
1198 struct oc_context *ac;
1199 struct ldb_dn *parent_dn;
1202 ldb = ldb_module_get_ctx(module);
1204 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1206 /* do not manipulate our control entries */
1207 if (ldb_dn_is_special(req->op.rename.olddn)) {
1208 return ldb_next_request(module, req);
1211 ac = oc_init_context(module, req);
1213 return ldb_operr(ldb);
1216 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1217 if (parent_dn == NULL) {
1218 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, the parent DN does not exist!",
1219 ldb_dn_get_linearized(req->op.rename.olddn));
1220 return LDB_ERR_NO_SUCH_OBJECT;
1223 /* this looks up the parent object for fetching some important
1224 * informations (objectclasses, DN normalisation...) */
1225 ret = ldb_build_search_req(&search_req, ldb,
1226 ac, parent_dn, LDB_SCOPE_BASE,
1229 ac, get_search_callback,
1231 LDB_REQ_SET_LOCATION(search_req);
1232 if (ret != LDB_SUCCESS) {
1236 /* we have to add the show recycled control, as otherwise DRS
1237 deletes will be refused as we will think the target parent
1239 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
1242 if (ret != LDB_SUCCESS) {
1246 ac->step_fn = objectclass_do_rename;
1248 return ldb_next_request(ac->module, search_req);
1251 static int objectclass_do_rename2(struct oc_context *ac);
1253 static int objectclass_do_rename(struct oc_context *ac)
1255 static const char * const attrs[] = { "objectClass", NULL };
1256 struct ldb_context *ldb;
1257 struct ldb_request *search_req;
1260 ldb = ldb_module_get_ctx(ac->module);
1262 /* Check if we have a valid parent - this check is needed since
1263 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1264 if (ac->search_res == NULL) {
1265 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1266 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1267 return LDB_ERR_OTHER;
1270 /* now assign "search_res2" to the parent entry to have "search_res"
1271 * free for another lookup */
1272 ac->search_res2 = ac->search_res;
1273 ac->search_res = NULL;
1275 /* this looks up the real existing object for fetching some important
1276 * informations (objectclasses) */
1277 ret = ldb_build_search_req(&search_req, ldb,
1278 ac, ac->req->op.rename.olddn,
1282 ac, get_search_callback,
1284 LDB_REQ_SET_LOCATION(search_req);
1285 if (ret != LDB_SUCCESS) {
1289 ac->step_fn = objectclass_do_rename2;
1291 return ldb_next_request(ac->module, search_req);
1294 static int objectclass_do_rename2(struct oc_context *ac)
1296 struct ldb_context *ldb;
1297 struct ldb_request *rename_req;
1298 struct ldb_dn *fixed_dn;
1301 ldb = ldb_module_get_ctx(ac->module);
1303 /* Check if we have a valid entry - this check is needed since
1304 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1305 if (ac->search_res == NULL) {
1306 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, entry does not exist!",
1307 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1308 return LDB_ERR_NO_SUCH_OBJECT;
1311 if (ac->schema != NULL) {
1312 struct ldb_message_element *oc_el_entry, *oc_el_parent;
1313 const struct dsdb_class *objectclass;
1314 const char *rdn_name;
1315 bool allowed_class = false;
1319 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1321 if (oc_el_entry == NULL) {
1322 /* existing entry without a valid object class? */
1323 return ldb_operr(ldb);
1325 objectclass = get_last_structural_class(ac->schema, oc_el_entry, ac->req);
1326 if (objectclass == NULL) {
1327 /* existing entry without a valid object class? */
1328 return ldb_operr(ldb);
1331 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
1332 if (rdn_name == NULL) {
1333 return ldb_operr(ldb);
1336 for (i = 0; (!found) && (i < oc_el_entry->num_values); i++) {
1337 const struct dsdb_class *tmp_class =
1338 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1339 &oc_el_entry->values[i]);
1341 if (tmp_class == NULL) continue;
1343 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
1347 ldb_asprintf_errstring(ldb,
1348 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
1349 rdn_name, objectclass->lDAPDisplayName);
1350 return LDB_ERR_UNWILLING_TO_PERFORM;
1353 oc_el_parent = ldb_msg_find_element(ac->search_res2->message,
1355 if (oc_el_parent == NULL) {
1356 /* existing entry without a valid object class? */
1357 return ldb_operr(ldb);
1360 for (i=0; allowed_class == false && i < oc_el_parent->num_values; i++) {
1361 const struct dsdb_class *sclass;
1363 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1364 &oc_el_parent->values[i]);
1366 /* We don't know this class? what is going on? */
1369 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
1370 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
1371 allowed_class = true;
1377 if (!allowed_class) {
1378 ldb_asprintf_errstring(ldb,
1379 "objectclass: structural objectClass %s is not a valid child class for %s",
1380 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res2->message->dn));
1381 return LDB_ERR_NAMING_VIOLATION;
1385 /* Ensure we are not trying to rename it to be a child of itself */
1386 if ((ldb_dn_compare_base(ac->req->op.rename.olddn,
1387 ac->req->op.rename.newdn) == 0) &&
1388 (ldb_dn_compare(ac->req->op.rename.olddn,
1389 ac->req->op.rename.newdn) != 0)) {
1390 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s to be a child of itself",
1391 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1392 return LDB_ERR_UNWILLING_TO_PERFORM;
1395 /* Fix up the DN to be in the standard form, taking
1396 * particular care to match the parent DN */
1397 ret = fix_dn(ldb, ac,
1398 ac->req->op.rename.newdn,
1399 ac->search_res2->message->dn,
1401 if (ret != LDB_SUCCESS) {
1402 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
1403 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1408 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1409 ac->req->op.rename.olddn, fixed_dn,
1413 LDB_REQ_SET_LOCATION(rename_req);
1414 if (ret != LDB_SUCCESS) {
1418 /* perform the rename */
1419 return ldb_next_request(ac->module, rename_req);
1422 static int objectclass_do_delete(struct oc_context *ac);
1424 static int objectclass_delete(struct ldb_module *module, struct ldb_request *req)
1426 static const char * const attrs[] = { "nCName", "objectClass",
1428 "isCriticalSystemObject", NULL };
1429 struct ldb_context *ldb;
1430 struct ldb_request *search_req;
1431 struct oc_context *ac;
1434 ldb = ldb_module_get_ctx(module);
1436 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_delete\n");
1438 /* do not manipulate our control entries */
1439 if (ldb_dn_is_special(req->op.del.dn)) {
1440 return ldb_next_request(module, req);
1443 /* Bypass the constraint checks when we do have the "RELAX" control
1445 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) != NULL) {
1446 return ldb_next_request(module, req);
1449 ac = oc_init_context(module, req);
1451 return ldb_operr(ldb);
1454 /* this looks up the entry object for fetching some important
1455 * informations (object classes, system flags...) */
1456 ret = ldb_build_search_req(&search_req, ldb,
1457 ac, req->op.del.dn, LDB_SCOPE_BASE,
1460 ac, get_search_callback,
1462 LDB_REQ_SET_LOCATION(search_req);
1463 if (ret != LDB_SUCCESS) {
1467 ac->step_fn = objectclass_do_delete;
1469 return ldb_next_request(ac->module, search_req);
1472 static int objectclass_do_delete(struct oc_context *ac)
1474 struct ldb_context *ldb;
1476 int32_t systemFlags;
1477 bool isCriticalSystemObject;
1480 ldb = ldb_module_get_ctx(ac->module);
1482 /* Check if we have a valid entry - this check is needed since
1483 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1484 if (ac->search_res == NULL) {
1485 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, entry does not exist!",
1486 ldb_dn_get_linearized(ac->req->op.del.dn));
1487 return LDB_ERR_NO_SUCH_OBJECT;
1490 /* DC's ntDSDSA object */
1491 if (ldb_dn_compare(ac->req->op.del.dn, samdb_ntds_settings_dn(ldb)) == 0) {
1492 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's ntDSDSA object!",
1493 ldb_dn_get_linearized(ac->req->op.del.dn));
1494 return LDB_ERR_UNWILLING_TO_PERFORM;
1497 /* DC's rIDSet object */
1498 /* Perform this check only when it does exist - this is needed in order
1499 * to don't let existing provisions break. */
1500 ret = samdb_rid_set_dn(ldb, ac, &dn);
1501 if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
1504 if (ret == LDB_SUCCESS) {
1505 if (ldb_dn_compare(ac->req->op.del.dn, dn) == 0) {
1507 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's rIDSet object!",
1508 ldb_dn_get_linearized(ac->req->op.del.dn));
1509 return LDB_ERR_UNWILLING_TO_PERFORM;
1514 /* crossRef objects regarding config, schema and default domain NCs */
1515 if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass",
1516 "crossRef") != NULL) {
1517 dn = ldb_msg_find_attr_as_dn(ldb, ac, ac->search_res->message,
1519 if ((ldb_dn_compare(dn, ldb_get_default_basedn(ldb)) == 0) ||
1520 (ldb_dn_compare(dn, ldb_get_config_basedn(ldb)) == 0)) {
1523 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the main or configuration partition!",
1524 ldb_dn_get_linearized(ac->req->op.del.dn));
1525 return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF;
1527 if (ldb_dn_compare(dn, ldb_get_schema_basedn(ldb)) == 0) {
1530 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the schema partition!",
1531 ldb_dn_get_linearized(ac->req->op.del.dn));
1532 return LDB_ERR_UNWILLING_TO_PERFORM;
1539 systemFlags = ldb_msg_find_attr_as_int(ac->search_res->message,
1541 if ((systemFlags & SYSTEM_FLAG_DISALLOW_DELETE) != 0) {
1542 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it isn't permitted!",
1543 ldb_dn_get_linearized(ac->req->op.del.dn));
1544 return LDB_ERR_UNWILLING_TO_PERFORM;
1547 /* isCriticalSystemObject - but this only applies on tree delete
1548 * operations - MS-ADTS 3.1.1.5.5.7.2 */
1549 if (ldb_request_get_control(ac->req, LDB_CONTROL_TREE_DELETE_OID) != NULL) {
1550 isCriticalSystemObject = ldb_msg_find_attr_as_bool(ac->search_res->message,
1551 "isCriticalSystemObject", false);
1552 if (isCriticalSystemObject) {
1553 ldb_asprintf_errstring(ldb,
1554 "objectclass: Cannot tree-delete %s, it's a critical system object!",
1555 ldb_dn_get_linearized(ac->req->op.del.dn));
1556 return LDB_ERR_UNWILLING_TO_PERFORM;
1560 return ldb_next_request(ac->module, ac->req);
1563 static int objectclass_init(struct ldb_module *module)
1565 struct ldb_context *ldb = ldb_module_get_ctx(module);
1568 /* Init everything else */
1569 ret = ldb_next_init(module);
1570 if (ret != LDB_SUCCESS) {
1574 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1575 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1577 ret = ldb_mod_register_control(module, LDB_CONTROL_RODC_DCPROMO_OID);
1578 if (ret != LDB_SUCCESS) {
1579 ldb_debug(ldb, LDB_DEBUG_ERROR,
1580 "objectclass_init: Unable to register control DCPROMO with rootdse\n");
1581 return ldb_operr(ldb);
1587 static const struct ldb_module_ops ldb_objectclass_module_ops = {
1588 .name = "objectclass",
1589 .add = objectclass_add,
1590 .modify = objectclass_modify,
1591 .rename = objectclass_rename,
1592 .del = objectclass_delete,
1593 .init_context = objectclass_init
1596 int ldb_objectclass_module_init(const char *version)
1598 LDB_MODULE_CHECK_VERSION(version);
1599 return ldb_register_module(&ldb_objectclass_module_ops);