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)) {
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 value = talloc_asprintf(req, "ldap://%s/%s", val->data,
402 ldb_dn_get_linearized(req->op.add.message->dn));
404 return ldb_module_oom(module);
407 return ldb_module_send_referral(req, value);
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;
440 return ldb_next_request(ac->module, search_req);
445 check if this is a special RODC nTDSDSA add
447 static bool check_rodc_ntdsdsa_add(struct oc_context *ac,
448 const struct dsdb_class *objectclass)
450 struct ldb_control *rodc_control;
452 if (strcasecmp(objectclass->lDAPDisplayName, "nTDSDSA") != 0) {
455 rodc_control = ldb_request_get_control(ac->req, LDB_CONTROL_RODC_DCPROMO_OID);
460 rodc_control->critical = false;
464 static int objectclass_do_add(struct oc_context *ac)
466 struct ldb_context *ldb;
467 struct ldb_request *add_req;
468 struct ldb_message_element *objectclass_element, *el;
469 struct ldb_message *msg;
471 struct class_list *sorted, *current;
472 const char *rdn_name = NULL;
474 const struct dsdb_class *objectclass;
475 struct ldb_dn *objectcategory;
476 int32_t systemFlags = 0;
481 ldb = ldb_module_get_ctx(ac->module);
483 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
485 return ldb_module_oom(ac->module);
488 /* Check if we have a valid parent - this check is needed since
489 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
490 if (ac->search_res == NULL) {
491 unsigned int instanceType;
493 /* An add operation on partition DNs without "NC-add" operation
495 instanceType = ldb_msg_find_attr_as_uint(ac->req->op.add.message,
497 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
498 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!",
499 ldb_dn_get_linearized(msg->dn));
500 return LDB_ERR_NO_SUCH_OBJECT;
503 /* Don't keep any error messages - we've to add a partition */
504 ldb_set_errstring(ldb, NULL);
506 /* Fix up the DN to be in the standard form, taking
507 * particular care to match the parent DN */
508 ret = fix_dn(ldb, msg,
509 ac->req->op.add.message->dn,
510 ac->search_res->message->dn,
512 if (ret != LDB_SUCCESS) {
513 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
514 ldb_dn_get_linearized(ac->req->op.add.message->dn));
519 mem_ctx = talloc_new(ac);
520 if (mem_ctx == NULL) {
521 return ldb_module_oom(ac->module);
524 if (ac->schema != NULL) {
525 objectclass_element = ldb_msg_find_element(msg, "objectClass");
526 if (!objectclass_element) {
527 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, no objectclass specified!",
528 ldb_dn_get_linearized(msg->dn));
529 talloc_free(mem_ctx);
530 return LDB_ERR_OBJECT_CLASS_VIOLATION;
532 if (objectclass_element->num_values == 0) {
533 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, at least one (structural) objectclass has to be specified!",
534 ldb_dn_get_linearized(msg->dn));
535 talloc_free(mem_ctx);
536 return LDB_ERR_CONSTRAINT_VIOLATION;
539 /* Here we do now get the "objectClass" list from the
541 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
542 objectclass_element, &sorted);
543 if (ret != LDB_SUCCESS) {
544 talloc_free(mem_ctx);
548 ldb_msg_remove_element(msg, objectclass_element);
550 /* Well, now we shouldn't find any additional "objectClass"
551 * message element (required by the AD specification). */
552 objectclass_element = ldb_msg_find_element(msg, "objectClass");
553 if (objectclass_element != NULL) {
554 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, only one 'objectclass' attribute specification is allowed!",
555 ldb_dn_get_linearized(msg->dn));
556 talloc_free(mem_ctx);
557 return LDB_ERR_OBJECT_CLASS_VIOLATION;
560 /* We must completely replace the existing objectClass entry,
561 * because we need it sorted. */
562 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
563 if (ret != LDB_SUCCESS) {
564 talloc_free(mem_ctx);
568 /* Move from the linked list back into an ldb msg */
569 for (current = sorted; current; current = current->next) {
570 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
572 talloc_free(mem_ctx);
573 return ldb_module_oom(ac->module);
576 ret = ldb_msg_add_string(msg, "objectClass", value);
577 if (ret != LDB_SUCCESS) {
578 ldb_set_errstring(ldb,
579 "objectclass: could not re-add sorted "
580 "objectclass to modify msg");
581 talloc_free(mem_ctx);
586 talloc_free(mem_ctx);
588 /* Retrive the message again so get_last_structural_class works */
589 objectclass_element = ldb_msg_find_element(msg, "objectClass");
591 /* Make sure its valid to add an object of this type */
592 objectclass = get_last_structural_class(ac->schema,
593 objectclass_element);
594 if(objectclass == NULL) {
595 ldb_asprintf_errstring(ldb,
596 "Failed to find a structural class for %s",
597 ldb_dn_get_linearized(msg->dn));
598 return LDB_ERR_UNWILLING_TO_PERFORM;
601 rdn_name = ldb_dn_get_rdn_name(msg->dn);
602 if (rdn_name == NULL) {
603 return ldb_operr(ldb);
606 for (i = 0; (!found) && (i < objectclass_element->num_values);
608 const struct dsdb_class *tmp_class =
609 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
610 &objectclass_element->values[i]);
612 if (tmp_class == NULL) continue;
614 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
618 ldb_asprintf_errstring(ldb,
619 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
620 rdn_name, objectclass->lDAPDisplayName);
621 return LDB_ERR_NAMING_VIOLATION;
624 if (objectclass->systemOnly &&
625 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) &&
626 !check_rodc_ntdsdsa_add(ac, objectclass)) {
627 ldb_asprintf_errstring(ldb, "objectClass %s is systemOnly, rejecting creation of %s",
628 objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
629 return LDB_ERR_UNWILLING_TO_PERFORM;
632 if (((strcmp(objectclass->lDAPDisplayName, "secret") == 0) ||
633 (strcmp(objectclass->lDAPDisplayName, "trustedDomain") == 0)) &&
634 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
635 ldb_asprintf_errstring(ldb, "objectClass %s is LSA-specific, rejecting creation of %s",
636 objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
637 return LDB_ERR_UNWILLING_TO_PERFORM;
640 if (ac->search_res && ac->search_res->message) {
641 struct ldb_message_element *oc_el
642 = ldb_msg_find_element(ac->search_res->message, "objectClass");
644 bool allowed_class = false;
645 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
646 const struct dsdb_class *sclass;
648 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
651 /* We don't know this class? what is going on? */
654 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
655 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
656 allowed_class = true;
662 if (!allowed_class) {
663 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
664 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
665 return LDB_ERR_NAMING_VIOLATION;
669 objectcategory = ldb_msg_find_attr_as_dn(ldb, ac, msg,
671 if (objectcategory == NULL) {
672 struct dsdb_extended_dn_store_format *dn_format =
673 talloc_get_type(ldb_module_get_private(ac->module),
674 struct dsdb_extended_dn_store_format);
675 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
676 /* Strip off extended components */
677 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
678 objectclass->defaultObjectCategory);
679 value = ldb_dn_alloc_linearized(msg, dn);
682 value = talloc_strdup(msg,
683 objectclass->defaultObjectCategory);
686 return ldb_module_oom(ac->module);
689 ret = ldb_msg_add_string(msg, "objectCategory", value);
690 if (ret != LDB_SUCCESS) {
694 const struct dsdb_class *ocClass =
695 dsdb_class_by_cn_ldb_val(ac->schema,
696 ldb_dn_get_rdn_val(objectcategory));
697 if (ocClass != NULL) {
698 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
699 ocClass->defaultObjectCategory);
700 if (ldb_dn_compare(objectcategory, dn) != 0) {
704 talloc_free(objectcategory);
705 if (ocClass == NULL) {
706 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'objectCategory' attribute invalid!",
707 ldb_dn_get_linearized(msg->dn));
708 return LDB_ERR_OBJECT_CLASS_VIOLATION;
712 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
713 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
717 /* There are very special rules for systemFlags, see MS-ADTS
718 * MS-ADTS 3.1.1.5.2.4 */
720 el = ldb_msg_find_element(msg, "systemFlags");
721 if ((el != NULL) && (el->num_values > 1)) {
722 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'systemFlags' attribute multivalued!",
723 ldb_dn_get_linearized(msg->dn));
724 return LDB_ERR_CONSTRAINT_VIOLATION;
727 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
729 ldb_msg_remove_attr(msg, "systemFlags");
731 /* Only the following flags may be set by a client */
732 if (ldb_request_get_control(ac->req,
733 LDB_CONTROL_RELAX_OID) == NULL) {
734 systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME
735 | SYSTEM_FLAG_CONFIG_ALLOW_MOVE
736 | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE
737 | SYSTEM_FLAG_ATTR_IS_RDN );
740 /* But the last one ("ATTR_IS_RDN") is only allowed on
741 * "attributeSchema" objects. So truncate if it does not fit. */
742 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") != 0) {
743 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
746 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
747 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
748 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
749 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serversContainer") == 0
750 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") == 0) {
751 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
753 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
754 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
755 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
756 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
759 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
761 if (el || systemFlags != 0) {
762 ret = samdb_msg_add_int(ldb, msg, msg, "systemFlags",
764 if (ret != LDB_SUCCESS) {
769 /* make sure that "isCriticalSystemObject" is not specified! */
770 el = ldb_msg_find_element(msg, "isCriticalSystemObject");
772 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
773 ldb_set_errstring(ldb,
774 "objectclass: 'isCriticalSystemObject' must not be specified!");
775 return LDB_ERR_UNWILLING_TO_PERFORM;
779 ret = ldb_msg_sanity_check(ldb, msg);
780 if (ret != LDB_SUCCESS) {
784 ret = ldb_build_add_req(&add_req, ldb, ac,
789 LDB_REQ_SET_LOCATION(add_req);
790 if (ret != LDB_SUCCESS) {
794 /* perform the add */
795 return ldb_next_request(ac->module, add_req);
798 static int oc_modify_callback(struct ldb_request *req,
799 struct ldb_reply *ares);
800 static int objectclass_do_mod(struct oc_context *ac);
802 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
804 struct ldb_context *ldb = ldb_module_get_ctx(module);
805 struct ldb_message_element *objectclass_element;
806 struct ldb_message *msg;
807 struct ldb_request *down_req;
808 struct oc_context *ac;
809 bool oc_changes = false;
812 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
814 /* do not manipulate our control entries */
815 if (ldb_dn_is_special(req->op.mod.message->dn)) {
816 return ldb_next_request(module, req);
819 /* As with the "real" AD we don't accept empty messages */
820 if (req->op.mod.message->num_elements == 0) {
821 ldb_set_errstring(ldb, "objectclass: modify message must have "
822 "elements/attributes!");
823 return LDB_ERR_UNWILLING_TO_PERFORM;
826 ac = oc_init_context(module, req);
828 return ldb_operr(ldb);
831 /* Without schema, there isn't much to do here */
832 if (ac->schema == NULL) {
834 return ldb_next_request(module, req);
837 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
839 return ldb_module_oom(ac->module);
842 /* For now change everything except the objectclasses */
844 objectclass_element = ldb_msg_find_element(msg, "objectClass");
845 if (objectclass_element != NULL) {
846 ldb_msg_remove_attr(msg, "objectClass");
850 /* MS-ADTS 3.1.1.5.3.5 - on a forest level < 2003 we do allow updates
851 * only on application NCs - not on the standard DCs */
853 (dsdb_forest_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
854 struct ldb_dn *nc_root;
856 ret = dsdb_find_nc_root(ldb, ac, req->op.mod.message->dn,
858 if (ret != LDB_SUCCESS) {
862 if ((ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) == 0) ||
863 (ldb_dn_compare(nc_root, ldb_get_config_basedn(ldb)) == 0) ||
864 (ldb_dn_compare(nc_root, ldb_get_schema_basedn(ldb)) == 0)) {
865 ldb_set_errstring(ldb,
866 "objectclass: object class changes on objects under the standard name contexts not allowed!");
867 return LDB_ERR_UNWILLING_TO_PERFORM;
870 talloc_free(nc_root);
873 ret = ldb_build_mod_req(&down_req, ldb, ac,
876 oc_changes ? oc_modify_callback : oc_op_callback,
878 LDB_REQ_SET_LOCATION(down_req);
879 if (ret != LDB_SUCCESS) {
883 return ldb_next_request(module, down_req);
886 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
888 static const char * const attrs[] = { "objectClass", NULL };
889 struct ldb_context *ldb;
890 struct ldb_request *search_req;
891 struct oc_context *ac;
894 ac = talloc_get_type(req->context, struct oc_context);
895 ldb = ldb_module_get_ctx(ac->module);
898 return ldb_module_done(ac->req, NULL, NULL,
899 LDB_ERR_OPERATIONS_ERROR);
902 if (ares->type == LDB_REPLY_REFERRAL) {
903 return ldb_module_send_referral(ac->req, ares->referral);
906 if (ares->error != LDB_SUCCESS) {
907 return ldb_module_done(ac->req, ares->controls,
908 ares->response, ares->error);
911 if (ares->type != LDB_REPLY_DONE) {
913 return ldb_module_done(ac->req, NULL, NULL,
914 LDB_ERR_OPERATIONS_ERROR);
919 /* this looks up the real existing object for fetching some important
920 * informations (objectclasses) */
921 ret = ldb_build_search_req(&search_req, ldb,
922 ac, ac->req->op.mod.message->dn,
926 ac, get_search_callback,
928 LDB_REQ_SET_LOCATION(search_req);
929 if (ret != LDB_SUCCESS) {
930 return ldb_module_done(ac->req, NULL, NULL, ret);
933 ac->step_fn = objectclass_do_mod;
935 ret = ldb_next_request(ac->module, search_req);
936 if (ret != LDB_SUCCESS) {
937 return ldb_module_done(ac->req, NULL, NULL, ret);
943 static int objectclass_do_mod(struct oc_context *ac)
945 struct ldb_context *ldb;
946 struct ldb_request *mod_req;
948 struct ldb_message_element *oc_el_entry, *oc_el_change;
949 struct ldb_val *vals;
950 struct ldb_message *msg;
952 struct class_list *sorted, *current;
953 const struct dsdb_class *objectclass;
954 unsigned int i, j, k;
955 bool found, replace = false;
958 ldb = ldb_module_get_ctx(ac->module);
960 /* we should always have a valid entry when we enter here */
961 if (ac->search_res == NULL) {
962 return ldb_operr(ldb);
965 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
967 if (oc_el_entry == NULL) {
968 /* existing entry without a valid object class? */
969 return ldb_operr(ldb);
972 /* use a new message structure */
973 msg = ldb_msg_new(ac);
975 return ldb_module_oom(ac->module);
978 msg->dn = ac->req->op.mod.message->dn;
980 mem_ctx = talloc_new(ac);
981 if (mem_ctx == NULL) {
982 return ldb_module_oom(ac->module);
985 /* We've to walk over all "objectClass" message elements */
986 for (k = 0; k < ac->req->op.mod.message->num_elements; k++) {
987 if (ldb_attr_cmp(ac->req->op.mod.message->elements[k].name,
988 "objectClass") != 0) {
992 oc_el_change = &ac->req->op.mod.message->elements[k];
994 switch (oc_el_change->flags & LDB_FLAG_MOD_MASK) {
995 case LDB_FLAG_MOD_ADD:
996 /* Merge the two message elements */
997 for (i = 0; i < oc_el_change->num_values; i++) {
998 for (j = 0; j < oc_el_entry->num_values; j++) {
999 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
1000 (char *)oc_el_entry->values[j].data) == 0) {
1001 ldb_asprintf_errstring(ldb,
1002 "objectclass: cannot re-add an existing objectclass: '%.*s'!",
1003 (int)oc_el_change->values[i].length,
1004 (const char *)oc_el_change->values[i].data);
1005 talloc_free(mem_ctx);
1006 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1009 /* append the new object class value - code was
1010 * copied from "ldb_msg_add_value" */
1011 vals = talloc_realloc(oc_el_entry, oc_el_entry->values,
1013 oc_el_entry->num_values + 1);
1015 talloc_free(mem_ctx);
1016 return ldb_module_oom(ac->module);
1018 oc_el_entry->values = vals;
1019 oc_el_entry->values[oc_el_entry->num_values] =
1020 oc_el_change->values[i];
1021 ++(oc_el_entry->num_values);
1024 objectclass = get_last_structural_class(ac->schema,
1026 if (objectclass != NULL) {
1027 ldb_asprintf_errstring(ldb,
1028 "objectclass: cannot add a new top-most structural objectclass '%s'!",
1029 objectclass->lDAPDisplayName);
1030 talloc_free(mem_ctx);
1031 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1034 /* Now do the sorting */
1035 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1036 oc_el_entry, &sorted);
1037 if (ret != LDB_SUCCESS) {
1038 talloc_free(mem_ctx);
1044 case LDB_FLAG_MOD_REPLACE:
1045 /* Do the sorting for the change message element */
1046 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1047 oc_el_change, &sorted);
1048 if (ret != LDB_SUCCESS) {
1049 talloc_free(mem_ctx);
1053 /* this is a replace */
1058 case LDB_FLAG_MOD_DELETE:
1059 /* get the actual top-most structural objectclass */
1060 objectclass = get_last_structural_class(ac->schema,
1062 if (objectclass == NULL) {
1063 /* no structural objectclass? */
1064 talloc_free(mem_ctx);
1065 return ldb_operr(ldb);
1068 /* Merge the two message elements */
1069 for (i = 0; i < oc_el_change->num_values; i++) {
1071 for (j = 0; j < oc_el_entry->num_values; j++) {
1072 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
1073 (char *)oc_el_entry->values[j].data) == 0) {
1075 /* delete the object class value
1076 * - code was copied from
1077 * "ldb_msg_remove_element" */
1078 if (j != oc_el_entry->num_values - 1) {
1079 memmove(&oc_el_entry->values[j],
1080 &oc_el_entry->values[j+1],
1081 ((oc_el_entry->num_values-1) - j)*sizeof(struct ldb_val));
1083 --(oc_el_entry->num_values);
1088 /* we cannot delete a not existing
1090 ldb_asprintf_errstring(ldb,
1091 "objectclass: cannot delete this objectclass: '%.*s'!",
1092 (int)oc_el_change->values[i].length,
1093 (const char *)oc_el_change->values[i].data);
1094 talloc_free(mem_ctx);
1095 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1099 /* Make sure that the top-most structural object class
1100 * hasn't been deleted */
1102 for (i = 0; i < oc_el_entry->num_values; i++) {
1103 if (ldb_attr_cmp(objectclass->lDAPDisplayName,
1104 (char *)oc_el_entry->values[i].data) == 0) {
1110 ldb_asprintf_errstring(ldb,
1111 "objectclass: cannot delete the top-most structural objectclass '%s'!",
1112 objectclass->lDAPDisplayName);
1113 talloc_free(mem_ctx);
1114 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1117 /* Now do the sorting */
1118 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1119 oc_el_entry, &sorted);
1120 if (ret != LDB_SUCCESS) {
1121 talloc_free(mem_ctx);
1128 /* (Re)-add an empty "objectClass" attribute on the object
1129 * classes change message "msg". */
1130 ldb_msg_remove_attr(msg, "objectClass");
1131 ret = ldb_msg_add_empty(msg, "objectClass",
1132 LDB_FLAG_MOD_REPLACE, &oc_el_change);
1133 if (ret != LDB_SUCCESS) {
1134 talloc_free(mem_ctx);
1138 /* Move from the linked list back into an ldb msg */
1139 for (current = sorted; current; current = current->next) {
1140 value = talloc_strdup(msg,
1141 current->objectclass->lDAPDisplayName);
1142 if (value == NULL) {
1143 talloc_free(mem_ctx);
1144 return ldb_module_oom(ac->module);
1146 ret = ldb_msg_add_string(msg, "objectClass", value);
1147 if (ret != LDB_SUCCESS) {
1148 ldb_set_errstring(ldb,
1149 "objectclass: could not re-add sorted objectclasses!");
1150 talloc_free(mem_ctx);
1156 /* Well, on replace we are nearly done: we have to test
1157 * if the change and entry message element are identical
1158 * ly. We can use "ldb_msg_element_compare" since now
1159 * the specified objectclasses match for sure in case.
1161 ret = ldb_msg_element_compare(oc_el_entry,
1164 ret = ldb_msg_element_compare(oc_el_change,
1168 /* they are the same so we are done in this
1170 talloc_free(mem_ctx);
1171 return ldb_module_done(ac->req, NULL, NULL,
1174 ldb_set_errstring(ldb,
1175 "objectclass: the specified objectclasses are not exactly the same as on the entry!");
1176 talloc_free(mem_ctx);
1177 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1181 /* Now we've applied all changes from "oc_el_change" to
1182 * "oc_el_entry" therefore the new "oc_el_entry" will be
1183 * "oc_el_change". */
1184 oc_el_entry = oc_el_change;
1187 talloc_free(mem_ctx);
1189 /* Now we have the real and definitive change left to do */
1191 ret = ldb_build_mod_req(&mod_req, ldb, ac,
1196 LDB_REQ_SET_LOCATION(mod_req);
1197 if (ret != LDB_SUCCESS) {
1201 return ldb_next_request(ac->module, mod_req);
1204 static int objectclass_do_rename(struct oc_context *ac);
1206 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1208 static const char * const attrs[] = { "objectClass", NULL };
1209 struct ldb_context *ldb;
1210 struct ldb_request *search_req;
1211 struct oc_context *ac;
1212 struct ldb_dn *parent_dn;
1215 ldb = ldb_module_get_ctx(module);
1217 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1219 /* do not manipulate our control entries */
1220 if (ldb_dn_is_special(req->op.rename.olddn)) {
1221 return ldb_next_request(module, req);
1224 ac = oc_init_context(module, req);
1226 return ldb_operr(ldb);
1229 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1230 if (parent_dn == NULL) {
1231 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, the parent DN does not exist!",
1232 ldb_dn_get_linearized(req->op.rename.olddn));
1233 return LDB_ERR_NO_SUCH_OBJECT;
1236 /* this looks up the parent object for fetching some important
1237 * informations (objectclasses, DN normalisation...) */
1238 ret = ldb_build_search_req(&search_req, ldb,
1239 ac, parent_dn, LDB_SCOPE_BASE,
1242 ac, get_search_callback,
1244 LDB_REQ_SET_LOCATION(search_req);
1245 if (ret != LDB_SUCCESS) {
1249 /* we have to add the show recycled control, as otherwise DRS
1250 deletes will be refused as we will think the target parent
1252 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
1255 if (ret != LDB_SUCCESS) {
1259 ac->step_fn = objectclass_do_rename;
1261 return ldb_next_request(ac->module, search_req);
1264 static int objectclass_do_rename2(struct oc_context *ac);
1266 static int objectclass_do_rename(struct oc_context *ac)
1268 static const char * const attrs[] = { "objectClass", NULL };
1269 struct ldb_context *ldb;
1270 struct ldb_request *search_req;
1273 ldb = ldb_module_get_ctx(ac->module);
1275 /* Check if we have a valid parent - this check is needed since
1276 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1277 if (ac->search_res == NULL) {
1278 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1279 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1280 return LDB_ERR_OTHER;
1283 /* now assign "search_res2" to the parent entry to have "search_res"
1284 * free for another lookup */
1285 ac->search_res2 = ac->search_res;
1286 ac->search_res = NULL;
1288 /* this looks up the real existing object for fetching some important
1289 * informations (objectclasses) */
1290 ret = ldb_build_search_req(&search_req, ldb,
1291 ac, ac->req->op.rename.olddn,
1295 ac, get_search_callback,
1297 LDB_REQ_SET_LOCATION(search_req);
1298 if (ret != LDB_SUCCESS) {
1302 ac->step_fn = objectclass_do_rename2;
1304 return ldb_next_request(ac->module, search_req);
1307 static int objectclass_do_rename2(struct oc_context *ac)
1309 struct ldb_context *ldb;
1310 struct ldb_request *rename_req;
1311 struct ldb_dn *fixed_dn;
1314 ldb = ldb_module_get_ctx(ac->module);
1316 /* Check if we have a valid entry - this check is needed since
1317 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1318 if (ac->search_res == NULL) {
1319 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, entry does not exist!",
1320 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1321 return LDB_ERR_NO_SUCH_OBJECT;
1324 if (ac->schema != NULL) {
1325 struct ldb_message_element *oc_el_entry, *oc_el_parent;
1326 const struct dsdb_class *objectclass;
1327 const char *rdn_name;
1328 bool allowed_class = false;
1332 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1334 if (oc_el_entry == NULL) {
1335 /* existing entry without a valid object class? */
1336 return ldb_operr(ldb);
1338 objectclass = get_last_structural_class(ac->schema, oc_el_entry);
1339 if (objectclass == NULL) {
1340 /* existing entry without a valid object class? */
1341 return ldb_operr(ldb);
1344 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
1345 if (rdn_name == NULL) {
1346 return ldb_operr(ldb);
1349 for (i = 0; (!found) && (i < oc_el_entry->num_values); i++) {
1350 const struct dsdb_class *tmp_class =
1351 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1352 &oc_el_entry->values[i]);
1354 if (tmp_class == NULL) continue;
1356 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
1360 ldb_asprintf_errstring(ldb,
1361 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
1362 rdn_name, objectclass->lDAPDisplayName);
1363 return LDB_ERR_UNWILLING_TO_PERFORM;
1366 oc_el_parent = ldb_msg_find_element(ac->search_res2->message,
1368 if (oc_el_parent == NULL) {
1369 /* existing entry without a valid object class? */
1370 return ldb_operr(ldb);
1373 for (i=0; allowed_class == false && i < oc_el_parent->num_values; i++) {
1374 const struct dsdb_class *sclass;
1376 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1377 &oc_el_parent->values[i]);
1379 /* We don't know this class? what is going on? */
1382 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
1383 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
1384 allowed_class = true;
1390 if (!allowed_class) {
1391 ldb_asprintf_errstring(ldb,
1392 "objectclass: structural objectClass %s is not a valid child class for %s",
1393 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res2->message->dn));
1394 return LDB_ERR_NAMING_VIOLATION;
1398 /* Ensure we are not trying to rename it to be a child of itself */
1399 if ((ldb_dn_compare_base(ac->req->op.rename.olddn,
1400 ac->req->op.rename.newdn) == 0) &&
1401 (ldb_dn_compare(ac->req->op.rename.olddn,
1402 ac->req->op.rename.newdn) != 0)) {
1403 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s to be a child of itself",
1404 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1405 return LDB_ERR_UNWILLING_TO_PERFORM;
1408 /* Fix up the DN to be in the standard form, taking
1409 * particular care to match the parent DN */
1410 ret = fix_dn(ldb, ac,
1411 ac->req->op.rename.newdn,
1412 ac->search_res2->message->dn,
1414 if (ret != LDB_SUCCESS) {
1415 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
1416 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1421 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1422 ac->req->op.rename.olddn, fixed_dn,
1426 LDB_REQ_SET_LOCATION(rename_req);
1427 if (ret != LDB_SUCCESS) {
1431 /* perform the rename */
1432 return ldb_next_request(ac->module, rename_req);
1435 static int objectclass_do_delete(struct oc_context *ac);
1437 static int objectclass_delete(struct ldb_module *module, struct ldb_request *req)
1439 static const char * const attrs[] = { "nCName", "objectClass",
1441 "isCriticalSystemObject", NULL };
1442 struct ldb_context *ldb;
1443 struct ldb_request *search_req;
1444 struct oc_context *ac;
1447 ldb = ldb_module_get_ctx(module);
1449 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_delete\n");
1451 /* do not manipulate our control entries */
1452 if (ldb_dn_is_special(req->op.del.dn)) {
1453 return ldb_next_request(module, req);
1456 /* Bypass the constraint checks when we do have the "RELAX" control
1458 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) != NULL) {
1459 return ldb_next_request(module, req);
1462 ac = oc_init_context(module, req);
1464 return ldb_operr(ldb);
1467 /* this looks up the entry object for fetching some important
1468 * informations (object classes, system flags...) */
1469 ret = ldb_build_search_req(&search_req, ldb,
1470 ac, req->op.del.dn, LDB_SCOPE_BASE,
1473 ac, get_search_callback,
1475 LDB_REQ_SET_LOCATION(search_req);
1476 if (ret != LDB_SUCCESS) {
1480 ac->step_fn = objectclass_do_delete;
1482 return ldb_next_request(ac->module, search_req);
1485 static int objectclass_do_delete(struct oc_context *ac)
1487 struct ldb_context *ldb;
1489 int32_t systemFlags;
1490 bool isCriticalSystemObject;
1493 ldb = ldb_module_get_ctx(ac->module);
1495 /* Check if we have a valid entry - this check is needed since
1496 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1497 if (ac->search_res == NULL) {
1498 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, entry does not exist!",
1499 ldb_dn_get_linearized(ac->req->op.del.dn));
1500 return LDB_ERR_NO_SUCH_OBJECT;
1503 /* DC's ntDSDSA object */
1504 if (ldb_dn_compare(ac->req->op.del.dn, samdb_ntds_settings_dn(ldb)) == 0) {
1505 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's ntDSDSA object!",
1506 ldb_dn_get_linearized(ac->req->op.del.dn));
1507 return LDB_ERR_UNWILLING_TO_PERFORM;
1510 /* DC's rIDSet object */
1511 /* Perform this check only when it does exist - this is needed in order
1512 * to don't let existing provisions break. */
1513 ret = samdb_rid_set_dn(ldb, ac, &dn);
1514 if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
1517 if (ret == LDB_SUCCESS) {
1518 if (ldb_dn_compare(ac->req->op.del.dn, dn) == 0) {
1520 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's rIDSet object!",
1521 ldb_dn_get_linearized(ac->req->op.del.dn));
1522 return LDB_ERR_UNWILLING_TO_PERFORM;
1527 /* crossRef objects regarding config, schema and default domain NCs */
1528 if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass",
1529 "crossRef") != NULL) {
1530 dn = ldb_msg_find_attr_as_dn(ldb, ac, ac->search_res->message,
1532 if ((ldb_dn_compare(dn, ldb_get_default_basedn(ldb)) == 0) ||
1533 (ldb_dn_compare(dn, ldb_get_config_basedn(ldb)) == 0)) {
1536 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the main or configuration partition!",
1537 ldb_dn_get_linearized(ac->req->op.del.dn));
1538 return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF;
1540 if (ldb_dn_compare(dn, ldb_get_schema_basedn(ldb)) == 0) {
1543 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the schema partition!",
1544 ldb_dn_get_linearized(ac->req->op.del.dn));
1545 return LDB_ERR_UNWILLING_TO_PERFORM;
1552 systemFlags = ldb_msg_find_attr_as_int(ac->search_res->message,
1554 if ((systemFlags & SYSTEM_FLAG_DISALLOW_DELETE) != 0) {
1555 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it isn't permitted!",
1556 ldb_dn_get_linearized(ac->req->op.del.dn));
1557 return LDB_ERR_UNWILLING_TO_PERFORM;
1560 /* isCriticalSystemObject - but this only applies on tree delete
1561 * operations - MS-ADTS 3.1.1.5.5.7.2 */
1562 if (ldb_request_get_control(ac->req, LDB_CONTROL_TREE_DELETE_OID) != NULL) {
1563 isCriticalSystemObject = ldb_msg_find_attr_as_bool(ac->search_res->message,
1564 "isCriticalSystemObject", false);
1565 if (isCriticalSystemObject) {
1566 ldb_asprintf_errstring(ldb,
1567 "objectclass: Cannot tree-delete %s, it's a critical system object!",
1568 ldb_dn_get_linearized(ac->req->op.del.dn));
1569 return LDB_ERR_UNWILLING_TO_PERFORM;
1573 return ldb_next_request(ac->module, ac->req);
1576 static int objectclass_init(struct ldb_module *module)
1578 struct ldb_context *ldb = ldb_module_get_ctx(module);
1581 /* Init everything else */
1582 ret = ldb_next_init(module);
1583 if (ret != LDB_SUCCESS) {
1587 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1588 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1590 ret = ldb_mod_register_control(module, LDB_CONTROL_RODC_DCPROMO_OID);
1591 if (ret != LDB_SUCCESS) {
1592 ldb_debug(ldb, LDB_DEBUG_ERROR,
1593 "objectclass_init: Unable to register control DCPROMO with rootdse\n");
1594 return ldb_operr(ldb);
1600 static const struct ldb_module_ops ldb_objectclass_module_ops = {
1601 .name = "objectclass",
1602 .add = objectclass_add,
1603 .modify = objectclass_modify,
1604 .rename = objectclass_rename,
1605 .del = objectclass_delete,
1606 .init_context = objectclass_init
1609 int ldb_objectclass_module_init(const char *version)
1611 LDB_MODULE_CHECK_VERSION(version);
1612 return ldb_register_module(&ldb_objectclass_module_ops);