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;
373 static const char * const parent_attrs[] = { "objectClass", NULL };
375 ldb = ldb_module_get_ctx(module);
377 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
379 /* do not manipulate our control entries */
380 if (ldb_dn_is_special(req->op.add.message->dn)) {
381 return ldb_next_request(module, req);
384 /* An add operation on the basedn without "NC-add" operation isn't
386 if (ldb_dn_compare(ldb_get_default_basedn(ldb), req->op.add.message->dn) == 0) {
387 unsigned int instanceType;
389 instanceType = ldb_msg_find_attr_as_uint(req->op.add.message,
391 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
393 /* When we are trying to readd the root basedn then
394 * this is denied, but with an interesting mechanism:
395 * there is generated a referral with the last
396 * component value as hostname. */
397 val = ldb_dn_get_component_val(req->op.add.message->dn,
398 ldb_dn_get_comp_num(req->op.add.message->dn) - 1);
400 return ldb_operr(ldb);
402 referral_uri = talloc_asprintf(req, "ldap://%s/%s", val->data,
403 ldb_dn_get_linearized(req->op.add.message->dn));
404 if (referral_uri == NULL) {
405 return ldb_module_oom(module);
408 return ldb_module_send_referral(req, referral_uri);
412 ac = oc_init_context(module, req);
414 return ldb_operr(ldb);
417 /* If there isn't a parent, just go on to the add processing */
418 if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
419 return objectclass_do_add(ac);
422 /* get copy of parent DN */
423 parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
424 if (parent_dn == NULL) {
425 return ldb_operr(ldb);
428 ret = ldb_build_search_req(&search_req, ldb,
429 ac, parent_dn, LDB_SCOPE_BASE,
430 "(objectClass=*)", parent_attrs,
432 ac, get_search_callback,
434 LDB_REQ_SET_LOCATION(search_req);
435 if (ret != LDB_SUCCESS) {
439 ac->step_fn = objectclass_do_add;
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(ac->req->op.add.message,
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 mem_ctx = talloc_new(ac);
519 if (mem_ctx == NULL) {
520 return ldb_module_oom(ac->module);
523 if (ac->schema != NULL) {
524 objectclass_element = ldb_msg_find_element(msg, "objectClass");
525 if (!objectclass_element) {
526 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, no objectclass specified!",
527 ldb_dn_get_linearized(msg->dn));
528 talloc_free(mem_ctx);
529 return LDB_ERR_OBJECT_CLASS_VIOLATION;
531 if (objectclass_element->num_values == 0) {
532 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, at least one (structural) objectclass has to be specified!",
533 ldb_dn_get_linearized(msg->dn));
534 talloc_free(mem_ctx);
535 return LDB_ERR_CONSTRAINT_VIOLATION;
538 /* Here we do now get the "objectClass" list from the
540 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
541 objectclass_element, &sorted);
542 if (ret != LDB_SUCCESS) {
543 talloc_free(mem_ctx);
547 ldb_msg_remove_element(msg, objectclass_element);
549 /* Well, now we shouldn't find any additional "objectClass"
550 * message element (required by the AD specification). */
551 objectclass_element = ldb_msg_find_element(msg, "objectClass");
552 if (objectclass_element != NULL) {
553 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, only one 'objectclass' attribute specification is allowed!",
554 ldb_dn_get_linearized(msg->dn));
555 talloc_free(mem_ctx);
556 return LDB_ERR_OBJECT_CLASS_VIOLATION;
559 /* We must completely replace the existing objectClass entry,
560 * because we need it sorted. */
561 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
562 if (ret != LDB_SUCCESS) {
563 talloc_free(mem_ctx);
567 /* Move from the linked list back into an ldb msg */
568 for (current = sorted; current; current = current->next) {
569 value = talloc_strdup(msg,
570 current->objectclass->lDAPDisplayName);
572 talloc_free(mem_ctx);
573 return ldb_module_oom(ac->module);
576 /* LSA-specific objectclasses per default not allowed */
577 if (((strcmp(value, "secret") == 0) ||
578 (strcmp(value, "trustedDomain") == 0)) &&
579 ldb_req_is_untrusted(ac->req)) {
580 ldb_asprintf_errstring(ldb,
581 "objectclass: object class '%s' is LSA-specific, rejecting creation of '%s'!",
583 ldb_dn_get_linearized(msg->dn));
584 return LDB_ERR_UNWILLING_TO_PERFORM;
587 ret = ldb_msg_add_string(msg, "objectClass", value);
588 if (ret != LDB_SUCCESS) {
589 ldb_set_errstring(ldb,
590 "objectclass: could not re-add sorted "
591 "objectclass to modify msg");
592 talloc_free(mem_ctx);
597 talloc_free(mem_ctx);
599 /* Retrive the message again so get_last_structural_class works */
600 objectclass_element = ldb_msg_find_element(msg, "objectClass");
602 /* Make sure its valid to add an object of this type */
603 objectclass = get_last_structural_class(ac->schema,
604 objectclass_element);
605 if(objectclass == NULL) {
606 ldb_asprintf_errstring(ldb,
607 "Failed to find a structural class for %s",
608 ldb_dn_get_linearized(msg->dn));
609 return LDB_ERR_UNWILLING_TO_PERFORM;
612 rdn_name = ldb_dn_get_rdn_name(msg->dn);
613 if (rdn_name == NULL) {
614 return ldb_operr(ldb);
617 for (i = 0; (!found) && (i < objectclass_element->num_values);
619 const struct dsdb_class *tmp_class =
620 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
621 &objectclass_element->values[i]);
623 if (tmp_class == NULL) continue;
625 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
629 ldb_asprintf_errstring(ldb,
630 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
631 rdn_name, objectclass->lDAPDisplayName);
632 return LDB_ERR_NAMING_VIOLATION;
635 if (objectclass->systemOnly &&
636 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) &&
637 !check_rodc_ntdsdsa_add(ac, objectclass)) {
638 ldb_asprintf_errstring(ldb,
639 "objectclass: object class '%s' is system-only, rejecting creation of '%s'!",
640 objectclass->lDAPDisplayName,
641 ldb_dn_get_linearized(msg->dn));
642 return LDB_ERR_UNWILLING_TO_PERFORM;
645 if (ac->search_res && ac->search_res->message) {
646 struct ldb_message_element *oc_el
647 = ldb_msg_find_element(ac->search_res->message, "objectClass");
649 bool allowed_class = false;
650 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
651 const struct dsdb_class *sclass;
653 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
656 /* We don't know this class? what is going on? */
659 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
660 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
661 allowed_class = true;
667 if (!allowed_class) {
668 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
669 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
670 return LDB_ERR_NAMING_VIOLATION;
674 objectcategory = ldb_msg_find_attr_as_dn(ldb, ac, msg,
676 if (objectcategory == NULL) {
677 struct dsdb_extended_dn_store_format *dn_format =
678 talloc_get_type(ldb_module_get_private(ac->module),
679 struct dsdb_extended_dn_store_format);
680 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
681 /* Strip off extended components */
682 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
683 objectclass->defaultObjectCategory);
684 value = ldb_dn_alloc_linearized(msg, dn);
687 value = talloc_strdup(msg,
688 objectclass->defaultObjectCategory);
691 return ldb_module_oom(ac->module);
694 ret = ldb_msg_add_string(msg, "objectCategory", value);
695 if (ret != LDB_SUCCESS) {
699 const struct dsdb_class *ocClass =
700 dsdb_class_by_cn_ldb_val(ac->schema,
701 ldb_dn_get_rdn_val(objectcategory));
702 if (ocClass != NULL) {
703 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
704 ocClass->defaultObjectCategory);
705 if (ldb_dn_compare(objectcategory, dn) != 0) {
709 talloc_free(objectcategory);
710 if (ocClass == NULL) {
711 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'objectCategory' attribute invalid!",
712 ldb_dn_get_linearized(msg->dn));
713 return LDB_ERR_OBJECT_CLASS_VIOLATION;
717 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
718 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
722 /* There are very special rules for systemFlags, see MS-ADTS
723 * MS-ADTS 3.1.1.5.2.4 */
725 el = ldb_msg_find_element(msg, "systemFlags");
726 if ((el != NULL) && (el->num_values > 1)) {
727 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'systemFlags' attribute multivalued!",
728 ldb_dn_get_linearized(msg->dn));
729 return LDB_ERR_CONSTRAINT_VIOLATION;
732 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
734 ldb_msg_remove_attr(msg, "systemFlags");
736 /* Only the following flags may be set by a client */
737 if (ldb_request_get_control(ac->req,
738 LDB_CONTROL_RELAX_OID) == NULL) {
739 systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME
740 | SYSTEM_FLAG_CONFIG_ALLOW_MOVE
741 | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE
742 | SYSTEM_FLAG_ATTR_IS_RDN );
745 /* But the last one ("ATTR_IS_RDN") is only allowed on
746 * "attributeSchema" objects. So truncate if it does not fit. */
747 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") != 0) {
748 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
751 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
752 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
753 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
754 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serversContainer") == 0
755 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") == 0) {
756 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
758 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
759 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
760 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
761 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
764 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
766 if (el || systemFlags != 0) {
767 ret = samdb_msg_add_int(ldb, msg, msg, "systemFlags",
769 if (ret != LDB_SUCCESS) {
774 /* make sure that "isCriticalSystemObject" is not specified! */
775 el = ldb_msg_find_element(msg, "isCriticalSystemObject");
777 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
778 ldb_set_errstring(ldb,
779 "objectclass: 'isCriticalSystemObject' must not be specified!");
780 return LDB_ERR_UNWILLING_TO_PERFORM;
784 ret = ldb_msg_sanity_check(ldb, msg);
785 if (ret != LDB_SUCCESS) {
789 ret = ldb_build_add_req(&add_req, ldb, ac,
794 LDB_REQ_SET_LOCATION(add_req);
795 if (ret != LDB_SUCCESS) {
799 /* perform the add */
800 return ldb_next_request(ac->module, add_req);
803 static int oc_modify_callback(struct ldb_request *req,
804 struct ldb_reply *ares);
805 static int objectclass_do_mod(struct oc_context *ac);
807 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
809 struct ldb_context *ldb = ldb_module_get_ctx(module);
810 struct ldb_message_element *objectclass_element;
811 struct ldb_message *msg;
812 struct ldb_request *down_req;
813 struct oc_context *ac;
814 bool oc_changes = false;
817 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
819 /* do not manipulate our control entries */
820 if (ldb_dn_is_special(req->op.mod.message->dn)) {
821 return ldb_next_request(module, req);
824 /* As with the "real" AD we don't accept empty messages */
825 if (req->op.mod.message->num_elements == 0) {
826 ldb_set_errstring(ldb, "objectclass: modify message must have "
827 "elements/attributes!");
828 return LDB_ERR_UNWILLING_TO_PERFORM;
831 ac = oc_init_context(module, req);
833 return ldb_operr(ldb);
836 /* Without schema, there isn't much to do here */
837 if (ac->schema == NULL) {
839 return ldb_next_request(module, req);
842 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
844 return ldb_module_oom(ac->module);
847 /* For now change everything except the objectclasses */
849 objectclass_element = ldb_msg_find_element(msg, "objectClass");
850 if (objectclass_element != NULL) {
851 ldb_msg_remove_attr(msg, "objectClass");
855 /* MS-ADTS 3.1.1.5.3.5 - on a forest level < 2003 we do allow updates
856 * only on application NCs - not on the standard DCs */
858 (dsdb_forest_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
859 struct ldb_dn *nc_root;
861 ret = dsdb_find_nc_root(ldb, ac, req->op.mod.message->dn,
863 if (ret != LDB_SUCCESS) {
867 if ((ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) == 0) ||
868 (ldb_dn_compare(nc_root, ldb_get_config_basedn(ldb)) == 0) ||
869 (ldb_dn_compare(nc_root, ldb_get_schema_basedn(ldb)) == 0)) {
870 ldb_set_errstring(ldb,
871 "objectclass: object class changes on objects under the standard name contexts not allowed!");
872 return LDB_ERR_UNWILLING_TO_PERFORM;
875 talloc_free(nc_root);
878 ret = ldb_build_mod_req(&down_req, ldb, ac,
881 oc_changes ? oc_modify_callback : oc_op_callback,
883 LDB_REQ_SET_LOCATION(down_req);
884 if (ret != LDB_SUCCESS) {
888 return ldb_next_request(module, down_req);
891 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
893 static const char * const attrs[] = { "objectClass", NULL };
894 struct ldb_context *ldb;
895 struct ldb_request *search_req;
896 struct oc_context *ac;
899 ac = talloc_get_type(req->context, struct oc_context);
900 ldb = ldb_module_get_ctx(ac->module);
903 return ldb_module_done(ac->req, NULL, NULL,
904 LDB_ERR_OPERATIONS_ERROR);
907 if (ares->type == LDB_REPLY_REFERRAL) {
908 return ldb_module_send_referral(ac->req, ares->referral);
911 if (ares->error != LDB_SUCCESS) {
912 return ldb_module_done(ac->req, ares->controls,
913 ares->response, ares->error);
916 if (ares->type != LDB_REPLY_DONE) {
918 return ldb_module_done(ac->req, NULL, NULL,
919 LDB_ERR_OPERATIONS_ERROR);
924 /* this looks up the real existing object for fetching some important
925 * informations (objectclasses) */
926 ret = ldb_build_search_req(&search_req, ldb,
927 ac, ac->req->op.mod.message->dn,
931 ac, get_search_callback,
933 LDB_REQ_SET_LOCATION(search_req);
934 if (ret != LDB_SUCCESS) {
935 return ldb_module_done(ac->req, NULL, NULL, ret);
938 ac->step_fn = objectclass_do_mod;
940 ret = ldb_next_request(ac->module, search_req);
941 if (ret != LDB_SUCCESS) {
942 return ldb_module_done(ac->req, NULL, NULL, ret);
948 static int objectclass_do_mod(struct oc_context *ac)
950 struct ldb_context *ldb;
951 struct ldb_request *mod_req;
953 struct ldb_message_element *oc_el_entry, *oc_el_change;
954 struct ldb_val *vals;
955 struct ldb_message *msg;
957 struct class_list *sorted, *current;
958 const struct dsdb_class *objectclass;
959 unsigned int i, j, k;
960 bool found, replace = false;
963 ldb = ldb_module_get_ctx(ac->module);
965 /* we should always have a valid entry when we enter here */
966 if (ac->search_res == NULL) {
967 return ldb_operr(ldb);
970 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
972 if (oc_el_entry == NULL) {
973 /* existing entry without a valid object class? */
974 return ldb_operr(ldb);
977 /* use a new message structure */
978 msg = ldb_msg_new(ac);
980 return ldb_module_oom(ac->module);
983 msg->dn = ac->req->op.mod.message->dn;
985 mem_ctx = talloc_new(ac);
986 if (mem_ctx == NULL) {
987 return ldb_module_oom(ac->module);
990 /* We've to walk over all "objectClass" message elements */
991 for (k = 0; k < ac->req->op.mod.message->num_elements; k++) {
992 if (ldb_attr_cmp(ac->req->op.mod.message->elements[k].name,
993 "objectClass") != 0) {
997 oc_el_change = &ac->req->op.mod.message->elements[k];
999 switch (oc_el_change->flags & LDB_FLAG_MOD_MASK) {
1000 case LDB_FLAG_MOD_ADD:
1001 /* Merge the two message elements */
1002 for (i = 0; i < oc_el_change->num_values; i++) {
1003 for (j = 0; j < oc_el_entry->num_values; j++) {
1004 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
1005 (char *)oc_el_entry->values[j].data) == 0) {
1006 ldb_asprintf_errstring(ldb,
1007 "objectclass: cannot re-add an existing objectclass: '%.*s'!",
1008 (int)oc_el_change->values[i].length,
1009 (const char *)oc_el_change->values[i].data);
1010 talloc_free(mem_ctx);
1011 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1014 /* append the new object class value - code was
1015 * copied from "ldb_msg_add_value" */
1016 vals = talloc_realloc(oc_el_entry, oc_el_entry->values,
1018 oc_el_entry->num_values + 1);
1020 talloc_free(mem_ctx);
1021 return ldb_module_oom(ac->module);
1023 oc_el_entry->values = vals;
1024 oc_el_entry->values[oc_el_entry->num_values] =
1025 oc_el_change->values[i];
1026 ++(oc_el_entry->num_values);
1029 objectclass = get_last_structural_class(ac->schema,
1031 if (objectclass != NULL) {
1032 ldb_asprintf_errstring(ldb,
1033 "objectclass: cannot add a new top-most structural objectclass '%s'!",
1034 objectclass->lDAPDisplayName);
1035 talloc_free(mem_ctx);
1036 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1039 /* Now do the sorting */
1040 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1041 oc_el_entry, &sorted);
1042 if (ret != LDB_SUCCESS) {
1043 talloc_free(mem_ctx);
1049 case LDB_FLAG_MOD_REPLACE:
1050 /* Do the sorting for the change message element */
1051 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1052 oc_el_change, &sorted);
1053 if (ret != LDB_SUCCESS) {
1054 talloc_free(mem_ctx);
1058 /* this is a replace */
1063 case LDB_FLAG_MOD_DELETE:
1064 /* get the actual top-most structural objectclass */
1065 objectclass = get_last_structural_class(ac->schema,
1067 if (objectclass == NULL) {
1068 /* no structural objectclass? */
1069 talloc_free(mem_ctx);
1070 return ldb_operr(ldb);
1073 /* Merge the two message elements */
1074 for (i = 0; i < oc_el_change->num_values; i++) {
1076 for (j = 0; j < oc_el_entry->num_values; j++) {
1077 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
1078 (char *)oc_el_entry->values[j].data) == 0) {
1080 /* delete the object class value
1081 * - code was copied from
1082 * "ldb_msg_remove_element" */
1083 if (j != oc_el_entry->num_values - 1) {
1084 memmove(&oc_el_entry->values[j],
1085 &oc_el_entry->values[j+1],
1086 ((oc_el_entry->num_values-1) - j)*sizeof(struct ldb_val));
1088 --(oc_el_entry->num_values);
1093 /* we cannot delete a not existing
1095 ldb_asprintf_errstring(ldb,
1096 "objectclass: cannot delete this objectclass: '%.*s'!",
1097 (int)oc_el_change->values[i].length,
1098 (const char *)oc_el_change->values[i].data);
1099 talloc_free(mem_ctx);
1100 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1104 /* Make sure that the top-most structural object class
1105 * hasn't been deleted */
1107 for (i = 0; i < oc_el_entry->num_values; i++) {
1108 if (ldb_attr_cmp(objectclass->lDAPDisplayName,
1109 (char *)oc_el_entry->values[i].data) == 0) {
1115 ldb_asprintf_errstring(ldb,
1116 "objectclass: cannot delete the top-most structural objectclass '%s'!",
1117 objectclass->lDAPDisplayName);
1118 talloc_free(mem_ctx);
1119 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1122 /* Now do the sorting */
1123 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1124 oc_el_entry, &sorted);
1125 if (ret != LDB_SUCCESS) {
1126 talloc_free(mem_ctx);
1133 /* (Re)-add an empty "objectClass" attribute on the object
1134 * classes change message "msg". */
1135 ldb_msg_remove_attr(msg, "objectClass");
1136 ret = ldb_msg_add_empty(msg, "objectClass",
1137 LDB_FLAG_MOD_REPLACE, &oc_el_change);
1138 if (ret != LDB_SUCCESS) {
1139 talloc_free(mem_ctx);
1143 /* Move from the linked list back into an ldb msg */
1144 for (current = sorted; current; current = current->next) {
1145 value = talloc_strdup(msg,
1146 current->objectclass->lDAPDisplayName);
1147 if (value == NULL) {
1148 talloc_free(mem_ctx);
1149 return ldb_module_oom(ac->module);
1151 ret = ldb_msg_add_string(msg, "objectClass", value);
1152 if (ret != LDB_SUCCESS) {
1153 ldb_set_errstring(ldb,
1154 "objectclass: could not re-add sorted objectclasses!");
1155 talloc_free(mem_ctx);
1161 /* Well, on replace we are nearly done: we have to test
1162 * if the change and entry message element are identical
1163 * ly. We can use "ldb_msg_element_compare" since now
1164 * the specified objectclasses match for sure in case.
1166 ret = ldb_msg_element_compare(oc_el_entry,
1169 ret = ldb_msg_element_compare(oc_el_change,
1173 /* they are the same so we are done in this
1175 talloc_free(mem_ctx);
1176 return ldb_module_done(ac->req, NULL, NULL,
1179 ldb_set_errstring(ldb,
1180 "objectclass: the specified objectclasses are not exactly the same as on the entry!");
1181 talloc_free(mem_ctx);
1182 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1186 /* Now we've applied all changes from "oc_el_change" to
1187 * "oc_el_entry" therefore the new "oc_el_entry" will be
1188 * "oc_el_change". */
1189 oc_el_entry = oc_el_change;
1192 talloc_free(mem_ctx);
1194 /* Now we have the real and definitive change left to do */
1196 ret = ldb_build_mod_req(&mod_req, ldb, ac,
1201 LDB_REQ_SET_LOCATION(mod_req);
1202 if (ret != LDB_SUCCESS) {
1206 return ldb_next_request(ac->module, mod_req);
1209 static int objectclass_do_rename(struct oc_context *ac);
1211 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1213 static const char * const attrs[] = { "objectClass", NULL };
1214 struct ldb_context *ldb;
1215 struct ldb_request *search_req;
1216 struct oc_context *ac;
1217 struct ldb_dn *parent_dn;
1220 ldb = ldb_module_get_ctx(module);
1222 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1224 /* do not manipulate our control entries */
1225 if (ldb_dn_is_special(req->op.rename.olddn)) {
1226 return ldb_next_request(module, req);
1229 ac = oc_init_context(module, req);
1231 return ldb_operr(ldb);
1234 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1235 if (parent_dn == NULL) {
1236 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, the parent DN does not exist!",
1237 ldb_dn_get_linearized(req->op.rename.olddn));
1238 return LDB_ERR_NO_SUCH_OBJECT;
1241 /* this looks up the parent object for fetching some important
1242 * informations (objectclasses, DN normalisation...) */
1243 ret = ldb_build_search_req(&search_req, ldb,
1244 ac, parent_dn, LDB_SCOPE_BASE,
1247 ac, get_search_callback,
1249 LDB_REQ_SET_LOCATION(search_req);
1250 if (ret != LDB_SUCCESS) {
1254 /* we have to add the show recycled control, as otherwise DRS
1255 deletes will be refused as we will think the target parent
1257 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
1260 if (ret != LDB_SUCCESS) {
1264 ac->step_fn = objectclass_do_rename;
1266 return ldb_next_request(ac->module, search_req);
1269 static int objectclass_do_rename2(struct oc_context *ac);
1271 static int objectclass_do_rename(struct oc_context *ac)
1273 static const char * const attrs[] = { "objectClass", NULL };
1274 struct ldb_context *ldb;
1275 struct ldb_request *search_req;
1278 ldb = ldb_module_get_ctx(ac->module);
1280 /* Check if we have a valid parent - this check is needed since
1281 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1282 if (ac->search_res == NULL) {
1283 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1284 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1285 return LDB_ERR_OTHER;
1288 /* now assign "search_res2" to the parent entry to have "search_res"
1289 * free for another lookup */
1290 ac->search_res2 = ac->search_res;
1291 ac->search_res = NULL;
1293 /* this looks up the real existing object for fetching some important
1294 * informations (objectclasses) */
1295 ret = ldb_build_search_req(&search_req, ldb,
1296 ac, ac->req->op.rename.olddn,
1300 ac, get_search_callback,
1302 LDB_REQ_SET_LOCATION(search_req);
1303 if (ret != LDB_SUCCESS) {
1307 ac->step_fn = objectclass_do_rename2;
1309 return ldb_next_request(ac->module, search_req);
1312 static int objectclass_do_rename2(struct oc_context *ac)
1314 struct ldb_context *ldb;
1315 struct ldb_request *rename_req;
1316 struct ldb_dn *fixed_dn;
1319 ldb = ldb_module_get_ctx(ac->module);
1321 /* Check if we have a valid entry - this check is needed since
1322 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1323 if (ac->search_res == NULL) {
1324 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, entry does not exist!",
1325 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1326 return LDB_ERR_NO_SUCH_OBJECT;
1329 if (ac->schema != NULL) {
1330 struct ldb_message_element *oc_el_entry, *oc_el_parent;
1331 const struct dsdb_class *objectclass;
1332 const char *rdn_name;
1333 bool allowed_class = false;
1337 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1339 if (oc_el_entry == NULL) {
1340 /* existing entry without a valid object class? */
1341 return ldb_operr(ldb);
1343 objectclass = get_last_structural_class(ac->schema, oc_el_entry);
1344 if (objectclass == NULL) {
1345 /* existing entry without a valid object class? */
1346 return ldb_operr(ldb);
1349 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
1350 if (rdn_name == NULL) {
1351 return ldb_operr(ldb);
1354 for (i = 0; (!found) && (i < oc_el_entry->num_values); i++) {
1355 const struct dsdb_class *tmp_class =
1356 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1357 &oc_el_entry->values[i]);
1359 if (tmp_class == NULL) continue;
1361 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
1365 ldb_asprintf_errstring(ldb,
1366 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
1367 rdn_name, objectclass->lDAPDisplayName);
1368 return LDB_ERR_UNWILLING_TO_PERFORM;
1371 oc_el_parent = ldb_msg_find_element(ac->search_res2->message,
1373 if (oc_el_parent == NULL) {
1374 /* existing entry without a valid object class? */
1375 return ldb_operr(ldb);
1378 for (i=0; allowed_class == false && i < oc_el_parent->num_values; i++) {
1379 const struct dsdb_class *sclass;
1381 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1382 &oc_el_parent->values[i]);
1384 /* We don't know this class? what is going on? */
1387 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
1388 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
1389 allowed_class = true;
1395 if (!allowed_class) {
1396 ldb_asprintf_errstring(ldb,
1397 "objectclass: structural objectClass %s is not a valid child class for %s",
1398 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res2->message->dn));
1399 return LDB_ERR_NAMING_VIOLATION;
1403 /* Ensure we are not trying to rename it to be a child of itself */
1404 if ((ldb_dn_compare_base(ac->req->op.rename.olddn,
1405 ac->req->op.rename.newdn) == 0) &&
1406 (ldb_dn_compare(ac->req->op.rename.olddn,
1407 ac->req->op.rename.newdn) != 0)) {
1408 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s to be a child of itself",
1409 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1410 return LDB_ERR_UNWILLING_TO_PERFORM;
1413 /* Fix up the DN to be in the standard form, taking
1414 * particular care to match the parent DN */
1415 ret = fix_dn(ldb, ac,
1416 ac->req->op.rename.newdn,
1417 ac->search_res2->message->dn,
1419 if (ret != LDB_SUCCESS) {
1420 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
1421 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1426 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1427 ac->req->op.rename.olddn, fixed_dn,
1431 LDB_REQ_SET_LOCATION(rename_req);
1432 if (ret != LDB_SUCCESS) {
1436 /* perform the rename */
1437 return ldb_next_request(ac->module, rename_req);
1440 static int objectclass_do_delete(struct oc_context *ac);
1442 static int objectclass_delete(struct ldb_module *module, struct ldb_request *req)
1444 static const char * const attrs[] = { "nCName", "objectClass",
1446 "isCriticalSystemObject", NULL };
1447 struct ldb_context *ldb;
1448 struct ldb_request *search_req;
1449 struct oc_context *ac;
1452 ldb = ldb_module_get_ctx(module);
1454 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_delete\n");
1456 /* do not manipulate our control entries */
1457 if (ldb_dn_is_special(req->op.del.dn)) {
1458 return ldb_next_request(module, req);
1461 /* Bypass the constraint checks when we do have the "RELAX" control
1463 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) != NULL) {
1464 return ldb_next_request(module, req);
1467 ac = oc_init_context(module, req);
1469 return ldb_operr(ldb);
1472 /* this looks up the entry object for fetching some important
1473 * informations (object classes, system flags...) */
1474 ret = ldb_build_search_req(&search_req, ldb,
1475 ac, req->op.del.dn, LDB_SCOPE_BASE,
1478 ac, get_search_callback,
1480 LDB_REQ_SET_LOCATION(search_req);
1481 if (ret != LDB_SUCCESS) {
1485 ac->step_fn = objectclass_do_delete;
1487 return ldb_next_request(ac->module, search_req);
1490 static int objectclass_do_delete(struct oc_context *ac)
1492 struct ldb_context *ldb;
1494 int32_t systemFlags;
1495 bool isCriticalSystemObject;
1498 ldb = ldb_module_get_ctx(ac->module);
1500 /* Check if we have a valid entry - this check is needed since
1501 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1502 if (ac->search_res == NULL) {
1503 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, entry does not exist!",
1504 ldb_dn_get_linearized(ac->req->op.del.dn));
1505 return LDB_ERR_NO_SUCH_OBJECT;
1508 /* DC's ntDSDSA object */
1509 if (ldb_dn_compare(ac->req->op.del.dn, samdb_ntds_settings_dn(ldb)) == 0) {
1510 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's ntDSDSA object!",
1511 ldb_dn_get_linearized(ac->req->op.del.dn));
1512 return LDB_ERR_UNWILLING_TO_PERFORM;
1515 /* DC's rIDSet object */
1516 /* Perform this check only when it does exist - this is needed in order
1517 * to don't let existing provisions break. */
1518 ret = samdb_rid_set_dn(ldb, ac, &dn);
1519 if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
1522 if (ret == LDB_SUCCESS) {
1523 if (ldb_dn_compare(ac->req->op.del.dn, dn) == 0) {
1525 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's rIDSet object!",
1526 ldb_dn_get_linearized(ac->req->op.del.dn));
1527 return LDB_ERR_UNWILLING_TO_PERFORM;
1532 /* crossRef objects regarding config, schema and default domain NCs */
1533 if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass",
1534 "crossRef") != NULL) {
1535 dn = ldb_msg_find_attr_as_dn(ldb, ac, ac->search_res->message,
1537 if ((ldb_dn_compare(dn, ldb_get_default_basedn(ldb)) == 0) ||
1538 (ldb_dn_compare(dn, ldb_get_config_basedn(ldb)) == 0)) {
1541 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the main or configuration partition!",
1542 ldb_dn_get_linearized(ac->req->op.del.dn));
1543 return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF;
1545 if (ldb_dn_compare(dn, ldb_get_schema_basedn(ldb)) == 0) {
1548 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the schema partition!",
1549 ldb_dn_get_linearized(ac->req->op.del.dn));
1550 return LDB_ERR_UNWILLING_TO_PERFORM;
1557 systemFlags = ldb_msg_find_attr_as_int(ac->search_res->message,
1559 if ((systemFlags & SYSTEM_FLAG_DISALLOW_DELETE) != 0) {
1560 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it isn't permitted!",
1561 ldb_dn_get_linearized(ac->req->op.del.dn));
1562 return LDB_ERR_UNWILLING_TO_PERFORM;
1565 /* isCriticalSystemObject - but this only applies on tree delete
1566 * operations - MS-ADTS 3.1.1.5.5.7.2 */
1567 if (ldb_request_get_control(ac->req, LDB_CONTROL_TREE_DELETE_OID) != NULL) {
1568 isCriticalSystemObject = ldb_msg_find_attr_as_bool(ac->search_res->message,
1569 "isCriticalSystemObject", false);
1570 if (isCriticalSystemObject) {
1571 ldb_asprintf_errstring(ldb,
1572 "objectclass: Cannot tree-delete %s, it's a critical system object!",
1573 ldb_dn_get_linearized(ac->req->op.del.dn));
1574 return LDB_ERR_UNWILLING_TO_PERFORM;
1578 return ldb_next_request(ac->module, ac->req);
1581 static int objectclass_init(struct ldb_module *module)
1583 struct ldb_context *ldb = ldb_module_get_ctx(module);
1586 /* Init everything else */
1587 ret = ldb_next_init(module);
1588 if (ret != LDB_SUCCESS) {
1592 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1593 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1595 ret = ldb_mod_register_control(module, LDB_CONTROL_RODC_DCPROMO_OID);
1596 if (ret != LDB_SUCCESS) {
1597 ldb_debug(ldb, LDB_DEBUG_ERROR,
1598 "objectclass_init: Unable to register control DCPROMO with rootdse\n");
1599 return ldb_operr(ldb);
1605 static const struct ldb_module_ops ldb_objectclass_module_ops = {
1606 .name = "objectclass",
1607 .add = objectclass_add,
1608 .modify = objectclass_modify,
1609 .rename = objectclass_rename,
1610 .del = objectclass_delete,
1611 .init_context = objectclass_init
1614 int ldb_objectclass_module_init(const char *version)
1616 LDB_MODULE_CHECK_VERSION(version);
1617 return ldb_register_module(&ldb_objectclass_module_ops);