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,
571 current->objectclass->lDAPDisplayName);
573 talloc_free(mem_ctx);
574 return ldb_module_oom(ac->module);
577 /* LSA-specific objectclasses per default not allowed */
578 if (((strcmp(value, "secret") == 0) ||
579 (strcmp(value, "trustedDomain") == 0)) &&
580 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
581 ldb_asprintf_errstring(ldb,
582 "objectclass: object class '%s' is LSA-specific, rejecting creation of '%s'!",
584 ldb_dn_get_linearized(msg->dn));
585 return LDB_ERR_UNWILLING_TO_PERFORM;
588 ret = ldb_msg_add_string(msg, "objectClass", value);
589 if (ret != LDB_SUCCESS) {
590 ldb_set_errstring(ldb,
591 "objectclass: could not re-add sorted "
592 "objectclass to modify msg");
593 talloc_free(mem_ctx);
598 talloc_free(mem_ctx);
600 /* Retrive the message again so get_last_structural_class works */
601 objectclass_element = ldb_msg_find_element(msg, "objectClass");
603 /* Make sure its valid to add an object of this type */
604 objectclass = get_last_structural_class(ac->schema,
605 objectclass_element);
606 if(objectclass == NULL) {
607 ldb_asprintf_errstring(ldb,
608 "Failed to find a structural class for %s",
609 ldb_dn_get_linearized(msg->dn));
610 return LDB_ERR_UNWILLING_TO_PERFORM;
613 rdn_name = ldb_dn_get_rdn_name(msg->dn);
614 if (rdn_name == NULL) {
615 return ldb_operr(ldb);
618 for (i = 0; (!found) && (i < objectclass_element->num_values);
620 const struct dsdb_class *tmp_class =
621 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
622 &objectclass_element->values[i]);
624 if (tmp_class == NULL) continue;
626 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
630 ldb_asprintf_errstring(ldb,
631 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
632 rdn_name, objectclass->lDAPDisplayName);
633 return LDB_ERR_NAMING_VIOLATION;
636 if (objectclass->systemOnly &&
637 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) &&
638 !check_rodc_ntdsdsa_add(ac, objectclass)) {
639 ldb_asprintf_errstring(ldb,
640 "objectclass: object class '%s' is system-only, rejecting creation of '%s'!",
641 objectclass->lDAPDisplayName,
642 ldb_dn_get_linearized(msg->dn));
643 return LDB_ERR_UNWILLING_TO_PERFORM;
646 if (ac->search_res && ac->search_res->message) {
647 struct ldb_message_element *oc_el
648 = ldb_msg_find_element(ac->search_res->message, "objectClass");
650 bool allowed_class = false;
651 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
652 const struct dsdb_class *sclass;
654 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
657 /* We don't know this class? what is going on? */
660 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
661 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
662 allowed_class = true;
668 if (!allowed_class) {
669 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
670 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
671 return LDB_ERR_NAMING_VIOLATION;
675 objectcategory = ldb_msg_find_attr_as_dn(ldb, ac, msg,
677 if (objectcategory == NULL) {
678 struct dsdb_extended_dn_store_format *dn_format =
679 talloc_get_type(ldb_module_get_private(ac->module),
680 struct dsdb_extended_dn_store_format);
681 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
682 /* Strip off extended components */
683 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
684 objectclass->defaultObjectCategory);
685 value = ldb_dn_alloc_linearized(msg, dn);
688 value = talloc_strdup(msg,
689 objectclass->defaultObjectCategory);
692 return ldb_module_oom(ac->module);
695 ret = ldb_msg_add_string(msg, "objectCategory", value);
696 if (ret != LDB_SUCCESS) {
700 const struct dsdb_class *ocClass =
701 dsdb_class_by_cn_ldb_val(ac->schema,
702 ldb_dn_get_rdn_val(objectcategory));
703 if (ocClass != NULL) {
704 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
705 ocClass->defaultObjectCategory);
706 if (ldb_dn_compare(objectcategory, dn) != 0) {
710 talloc_free(objectcategory);
711 if (ocClass == NULL) {
712 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'objectCategory' attribute invalid!",
713 ldb_dn_get_linearized(msg->dn));
714 return LDB_ERR_OBJECT_CLASS_VIOLATION;
718 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
719 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
723 /* There are very special rules for systemFlags, see MS-ADTS
724 * MS-ADTS 3.1.1.5.2.4 */
726 el = ldb_msg_find_element(msg, "systemFlags");
727 if ((el != NULL) && (el->num_values > 1)) {
728 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'systemFlags' attribute multivalued!",
729 ldb_dn_get_linearized(msg->dn));
730 return LDB_ERR_CONSTRAINT_VIOLATION;
733 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
735 ldb_msg_remove_attr(msg, "systemFlags");
737 /* Only the following flags may be set by a client */
738 if (ldb_request_get_control(ac->req,
739 LDB_CONTROL_RELAX_OID) == NULL) {
740 systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME
741 | SYSTEM_FLAG_CONFIG_ALLOW_MOVE
742 | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE
743 | SYSTEM_FLAG_ATTR_IS_RDN );
746 /* But the last one ("ATTR_IS_RDN") is only allowed on
747 * "attributeSchema" objects. So truncate if it does not fit. */
748 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") != 0) {
749 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
752 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
753 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
754 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
755 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serversContainer") == 0
756 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") == 0) {
757 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
759 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
760 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
761 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
762 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
765 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
767 if (el || systemFlags != 0) {
768 ret = samdb_msg_add_int(ldb, msg, msg, "systemFlags",
770 if (ret != LDB_SUCCESS) {
775 /* make sure that "isCriticalSystemObject" is not specified! */
776 el = ldb_msg_find_element(msg, "isCriticalSystemObject");
778 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
779 ldb_set_errstring(ldb,
780 "objectclass: 'isCriticalSystemObject' must not be specified!");
781 return LDB_ERR_UNWILLING_TO_PERFORM;
785 ret = ldb_msg_sanity_check(ldb, msg);
786 if (ret != LDB_SUCCESS) {
790 ret = ldb_build_add_req(&add_req, ldb, ac,
795 LDB_REQ_SET_LOCATION(add_req);
796 if (ret != LDB_SUCCESS) {
800 /* perform the add */
801 return ldb_next_request(ac->module, add_req);
804 static int oc_modify_callback(struct ldb_request *req,
805 struct ldb_reply *ares);
806 static int objectclass_do_mod(struct oc_context *ac);
808 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
810 struct ldb_context *ldb = ldb_module_get_ctx(module);
811 struct ldb_message_element *objectclass_element;
812 struct ldb_message *msg;
813 struct ldb_request *down_req;
814 struct oc_context *ac;
815 bool oc_changes = false;
818 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
820 /* do not manipulate our control entries */
821 if (ldb_dn_is_special(req->op.mod.message->dn)) {
822 return ldb_next_request(module, req);
825 /* As with the "real" AD we don't accept empty messages */
826 if (req->op.mod.message->num_elements == 0) {
827 ldb_set_errstring(ldb, "objectclass: modify message must have "
828 "elements/attributes!");
829 return LDB_ERR_UNWILLING_TO_PERFORM;
832 ac = oc_init_context(module, req);
834 return ldb_operr(ldb);
837 /* Without schema, there isn't much to do here */
838 if (ac->schema == NULL) {
840 return ldb_next_request(module, req);
843 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
845 return ldb_module_oom(ac->module);
848 /* For now change everything except the objectclasses */
850 objectclass_element = ldb_msg_find_element(msg, "objectClass");
851 if (objectclass_element != NULL) {
852 ldb_msg_remove_attr(msg, "objectClass");
856 /* MS-ADTS 3.1.1.5.3.5 - on a forest level < 2003 we do allow updates
857 * only on application NCs - not on the standard DCs */
859 (dsdb_forest_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
860 struct ldb_dn *nc_root;
862 ret = dsdb_find_nc_root(ldb, ac, req->op.mod.message->dn,
864 if (ret != LDB_SUCCESS) {
868 if ((ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) == 0) ||
869 (ldb_dn_compare(nc_root, ldb_get_config_basedn(ldb)) == 0) ||
870 (ldb_dn_compare(nc_root, ldb_get_schema_basedn(ldb)) == 0)) {
871 ldb_set_errstring(ldb,
872 "objectclass: object class changes on objects under the standard name contexts not allowed!");
873 return LDB_ERR_UNWILLING_TO_PERFORM;
876 talloc_free(nc_root);
879 ret = ldb_build_mod_req(&down_req, ldb, ac,
882 oc_changes ? oc_modify_callback : oc_op_callback,
884 LDB_REQ_SET_LOCATION(down_req);
885 if (ret != LDB_SUCCESS) {
889 return ldb_next_request(module, down_req);
892 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
894 static const char * const attrs[] = { "objectClass", NULL };
895 struct ldb_context *ldb;
896 struct ldb_request *search_req;
897 struct oc_context *ac;
900 ac = talloc_get_type(req->context, struct oc_context);
901 ldb = ldb_module_get_ctx(ac->module);
904 return ldb_module_done(ac->req, NULL, NULL,
905 LDB_ERR_OPERATIONS_ERROR);
908 if (ares->type == LDB_REPLY_REFERRAL) {
909 return ldb_module_send_referral(ac->req, ares->referral);
912 if (ares->error != LDB_SUCCESS) {
913 return ldb_module_done(ac->req, ares->controls,
914 ares->response, ares->error);
917 if (ares->type != LDB_REPLY_DONE) {
919 return ldb_module_done(ac->req, NULL, NULL,
920 LDB_ERR_OPERATIONS_ERROR);
925 /* this looks up the real existing object for fetching some important
926 * informations (objectclasses) */
927 ret = ldb_build_search_req(&search_req, ldb,
928 ac, ac->req->op.mod.message->dn,
932 ac, get_search_callback,
934 LDB_REQ_SET_LOCATION(search_req);
935 if (ret != LDB_SUCCESS) {
936 return ldb_module_done(ac->req, NULL, NULL, ret);
939 ac->step_fn = objectclass_do_mod;
941 ret = ldb_next_request(ac->module, search_req);
942 if (ret != LDB_SUCCESS) {
943 return ldb_module_done(ac->req, NULL, NULL, ret);
949 static int objectclass_do_mod(struct oc_context *ac)
951 struct ldb_context *ldb;
952 struct ldb_request *mod_req;
954 struct ldb_message_element *oc_el_entry, *oc_el_change;
955 struct ldb_val *vals;
956 struct ldb_message *msg;
958 struct class_list *sorted, *current;
959 const struct dsdb_class *objectclass;
960 unsigned int i, j, k;
961 bool found, replace = false;
964 ldb = ldb_module_get_ctx(ac->module);
966 /* we should always have a valid entry when we enter here */
967 if (ac->search_res == NULL) {
968 return ldb_operr(ldb);
971 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
973 if (oc_el_entry == NULL) {
974 /* existing entry without a valid object class? */
975 return ldb_operr(ldb);
978 /* use a new message structure */
979 msg = ldb_msg_new(ac);
981 return ldb_module_oom(ac->module);
984 msg->dn = ac->req->op.mod.message->dn;
986 mem_ctx = talloc_new(ac);
987 if (mem_ctx == NULL) {
988 return ldb_module_oom(ac->module);
991 /* We've to walk over all "objectClass" message elements */
992 for (k = 0; k < ac->req->op.mod.message->num_elements; k++) {
993 if (ldb_attr_cmp(ac->req->op.mod.message->elements[k].name,
994 "objectClass") != 0) {
998 oc_el_change = &ac->req->op.mod.message->elements[k];
1000 switch (oc_el_change->flags & LDB_FLAG_MOD_MASK) {
1001 case LDB_FLAG_MOD_ADD:
1002 /* Merge the two message elements */
1003 for (i = 0; i < oc_el_change->num_values; i++) {
1004 for (j = 0; j < oc_el_entry->num_values; j++) {
1005 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
1006 (char *)oc_el_entry->values[j].data) == 0) {
1007 ldb_asprintf_errstring(ldb,
1008 "objectclass: cannot re-add an existing objectclass: '%.*s'!",
1009 (int)oc_el_change->values[i].length,
1010 (const char *)oc_el_change->values[i].data);
1011 talloc_free(mem_ctx);
1012 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1015 /* append the new object class value - code was
1016 * copied from "ldb_msg_add_value" */
1017 vals = talloc_realloc(oc_el_entry, oc_el_entry->values,
1019 oc_el_entry->num_values + 1);
1021 talloc_free(mem_ctx);
1022 return ldb_module_oom(ac->module);
1024 oc_el_entry->values = vals;
1025 oc_el_entry->values[oc_el_entry->num_values] =
1026 oc_el_change->values[i];
1027 ++(oc_el_entry->num_values);
1030 objectclass = get_last_structural_class(ac->schema,
1032 if (objectclass != NULL) {
1033 ldb_asprintf_errstring(ldb,
1034 "objectclass: cannot add a new top-most structural objectclass '%s'!",
1035 objectclass->lDAPDisplayName);
1036 talloc_free(mem_ctx);
1037 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1040 /* Now do the sorting */
1041 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1042 oc_el_entry, &sorted);
1043 if (ret != LDB_SUCCESS) {
1044 talloc_free(mem_ctx);
1050 case LDB_FLAG_MOD_REPLACE:
1051 /* Do the sorting for the change message element */
1052 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1053 oc_el_change, &sorted);
1054 if (ret != LDB_SUCCESS) {
1055 talloc_free(mem_ctx);
1059 /* this is a replace */
1064 case LDB_FLAG_MOD_DELETE:
1065 /* get the actual top-most structural objectclass */
1066 objectclass = get_last_structural_class(ac->schema,
1068 if (objectclass == NULL) {
1069 /* no structural objectclass? */
1070 talloc_free(mem_ctx);
1071 return ldb_operr(ldb);
1074 /* Merge the two message elements */
1075 for (i = 0; i < oc_el_change->num_values; i++) {
1077 for (j = 0; j < oc_el_entry->num_values; j++) {
1078 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
1079 (char *)oc_el_entry->values[j].data) == 0) {
1081 /* delete the object class value
1082 * - code was copied from
1083 * "ldb_msg_remove_element" */
1084 if (j != oc_el_entry->num_values - 1) {
1085 memmove(&oc_el_entry->values[j],
1086 &oc_el_entry->values[j+1],
1087 ((oc_el_entry->num_values-1) - j)*sizeof(struct ldb_val));
1089 --(oc_el_entry->num_values);
1094 /* we cannot delete a not existing
1096 ldb_asprintf_errstring(ldb,
1097 "objectclass: cannot delete this objectclass: '%.*s'!",
1098 (int)oc_el_change->values[i].length,
1099 (const char *)oc_el_change->values[i].data);
1100 talloc_free(mem_ctx);
1101 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1105 /* Make sure that the top-most structural object class
1106 * hasn't been deleted */
1108 for (i = 0; i < oc_el_entry->num_values; i++) {
1109 if (ldb_attr_cmp(objectclass->lDAPDisplayName,
1110 (char *)oc_el_entry->values[i].data) == 0) {
1116 ldb_asprintf_errstring(ldb,
1117 "objectclass: cannot delete the top-most structural objectclass '%s'!",
1118 objectclass->lDAPDisplayName);
1119 talloc_free(mem_ctx);
1120 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1123 /* Now do the sorting */
1124 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1125 oc_el_entry, &sorted);
1126 if (ret != LDB_SUCCESS) {
1127 talloc_free(mem_ctx);
1134 /* (Re)-add an empty "objectClass" attribute on the object
1135 * classes change message "msg". */
1136 ldb_msg_remove_attr(msg, "objectClass");
1137 ret = ldb_msg_add_empty(msg, "objectClass",
1138 LDB_FLAG_MOD_REPLACE, &oc_el_change);
1139 if (ret != LDB_SUCCESS) {
1140 talloc_free(mem_ctx);
1144 /* Move from the linked list back into an ldb msg */
1145 for (current = sorted; current; current = current->next) {
1146 value = talloc_strdup(msg,
1147 current->objectclass->lDAPDisplayName);
1148 if (value == NULL) {
1149 talloc_free(mem_ctx);
1150 return ldb_module_oom(ac->module);
1152 ret = ldb_msg_add_string(msg, "objectClass", value);
1153 if (ret != LDB_SUCCESS) {
1154 ldb_set_errstring(ldb,
1155 "objectclass: could not re-add sorted objectclasses!");
1156 talloc_free(mem_ctx);
1162 /* Well, on replace we are nearly done: we have to test
1163 * if the change and entry message element are identical
1164 * ly. We can use "ldb_msg_element_compare" since now
1165 * the specified objectclasses match for sure in case.
1167 ret = ldb_msg_element_compare(oc_el_entry,
1170 ret = ldb_msg_element_compare(oc_el_change,
1174 /* they are the same so we are done in this
1176 talloc_free(mem_ctx);
1177 return ldb_module_done(ac->req, NULL, NULL,
1180 ldb_set_errstring(ldb,
1181 "objectclass: the specified objectclasses are not exactly the same as on the entry!");
1182 talloc_free(mem_ctx);
1183 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1187 /* Now we've applied all changes from "oc_el_change" to
1188 * "oc_el_entry" therefore the new "oc_el_entry" will be
1189 * "oc_el_change". */
1190 oc_el_entry = oc_el_change;
1193 talloc_free(mem_ctx);
1195 /* Now we have the real and definitive change left to do */
1197 ret = ldb_build_mod_req(&mod_req, ldb, ac,
1202 LDB_REQ_SET_LOCATION(mod_req);
1203 if (ret != LDB_SUCCESS) {
1207 return ldb_next_request(ac->module, mod_req);
1210 static int objectclass_do_rename(struct oc_context *ac);
1212 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1214 static const char * const attrs[] = { "objectClass", NULL };
1215 struct ldb_context *ldb;
1216 struct ldb_request *search_req;
1217 struct oc_context *ac;
1218 struct ldb_dn *parent_dn;
1221 ldb = ldb_module_get_ctx(module);
1223 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1225 /* do not manipulate our control entries */
1226 if (ldb_dn_is_special(req->op.rename.olddn)) {
1227 return ldb_next_request(module, req);
1230 ac = oc_init_context(module, req);
1232 return ldb_operr(ldb);
1235 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1236 if (parent_dn == NULL) {
1237 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, the parent DN does not exist!",
1238 ldb_dn_get_linearized(req->op.rename.olddn));
1239 return LDB_ERR_NO_SUCH_OBJECT;
1242 /* this looks up the parent object for fetching some important
1243 * informations (objectclasses, DN normalisation...) */
1244 ret = ldb_build_search_req(&search_req, ldb,
1245 ac, parent_dn, LDB_SCOPE_BASE,
1248 ac, get_search_callback,
1250 LDB_REQ_SET_LOCATION(search_req);
1251 if (ret != LDB_SUCCESS) {
1255 /* we have to add the show recycled control, as otherwise DRS
1256 deletes will be refused as we will think the target parent
1258 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
1261 if (ret != LDB_SUCCESS) {
1265 ac->step_fn = objectclass_do_rename;
1267 return ldb_next_request(ac->module, search_req);
1270 static int objectclass_do_rename2(struct oc_context *ac);
1272 static int objectclass_do_rename(struct oc_context *ac)
1274 static const char * const attrs[] = { "objectClass", NULL };
1275 struct ldb_context *ldb;
1276 struct ldb_request *search_req;
1279 ldb = ldb_module_get_ctx(ac->module);
1281 /* Check if we have a valid parent - this check is needed since
1282 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1283 if (ac->search_res == NULL) {
1284 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1285 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1286 return LDB_ERR_OTHER;
1289 /* now assign "search_res2" to the parent entry to have "search_res"
1290 * free for another lookup */
1291 ac->search_res2 = ac->search_res;
1292 ac->search_res = NULL;
1294 /* this looks up the real existing object for fetching some important
1295 * informations (objectclasses) */
1296 ret = ldb_build_search_req(&search_req, ldb,
1297 ac, ac->req->op.rename.olddn,
1301 ac, get_search_callback,
1303 LDB_REQ_SET_LOCATION(search_req);
1304 if (ret != LDB_SUCCESS) {
1308 ac->step_fn = objectclass_do_rename2;
1310 return ldb_next_request(ac->module, search_req);
1313 static int objectclass_do_rename2(struct oc_context *ac)
1315 struct ldb_context *ldb;
1316 struct ldb_request *rename_req;
1317 struct ldb_dn *fixed_dn;
1320 ldb = ldb_module_get_ctx(ac->module);
1322 /* Check if we have a valid entry - this check is needed since
1323 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1324 if (ac->search_res == NULL) {
1325 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, entry does not exist!",
1326 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1327 return LDB_ERR_NO_SUCH_OBJECT;
1330 if (ac->schema != NULL) {
1331 struct ldb_message_element *oc_el_entry, *oc_el_parent;
1332 const struct dsdb_class *objectclass;
1333 const char *rdn_name;
1334 bool allowed_class = false;
1338 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1340 if (oc_el_entry == NULL) {
1341 /* existing entry without a valid object class? */
1342 return ldb_operr(ldb);
1344 objectclass = get_last_structural_class(ac->schema, oc_el_entry);
1345 if (objectclass == NULL) {
1346 /* existing entry without a valid object class? */
1347 return ldb_operr(ldb);
1350 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
1351 if (rdn_name == NULL) {
1352 return ldb_operr(ldb);
1355 for (i = 0; (!found) && (i < oc_el_entry->num_values); i++) {
1356 const struct dsdb_class *tmp_class =
1357 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1358 &oc_el_entry->values[i]);
1360 if (tmp_class == NULL) continue;
1362 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
1366 ldb_asprintf_errstring(ldb,
1367 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
1368 rdn_name, objectclass->lDAPDisplayName);
1369 return LDB_ERR_UNWILLING_TO_PERFORM;
1372 oc_el_parent = ldb_msg_find_element(ac->search_res2->message,
1374 if (oc_el_parent == NULL) {
1375 /* existing entry without a valid object class? */
1376 return ldb_operr(ldb);
1379 for (i=0; allowed_class == false && i < oc_el_parent->num_values; i++) {
1380 const struct dsdb_class *sclass;
1382 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1383 &oc_el_parent->values[i]);
1385 /* We don't know this class? what is going on? */
1388 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
1389 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
1390 allowed_class = true;
1396 if (!allowed_class) {
1397 ldb_asprintf_errstring(ldb,
1398 "objectclass: structural objectClass %s is not a valid child class for %s",
1399 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res2->message->dn));
1400 return LDB_ERR_NAMING_VIOLATION;
1404 /* Ensure we are not trying to rename it to be a child of itself */
1405 if ((ldb_dn_compare_base(ac->req->op.rename.olddn,
1406 ac->req->op.rename.newdn) == 0) &&
1407 (ldb_dn_compare(ac->req->op.rename.olddn,
1408 ac->req->op.rename.newdn) != 0)) {
1409 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s to be a child of itself",
1410 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1411 return LDB_ERR_UNWILLING_TO_PERFORM;
1414 /* Fix up the DN to be in the standard form, taking
1415 * particular care to match the parent DN */
1416 ret = fix_dn(ldb, ac,
1417 ac->req->op.rename.newdn,
1418 ac->search_res2->message->dn,
1420 if (ret != LDB_SUCCESS) {
1421 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
1422 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1427 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1428 ac->req->op.rename.olddn, fixed_dn,
1432 LDB_REQ_SET_LOCATION(rename_req);
1433 if (ret != LDB_SUCCESS) {
1437 /* perform the rename */
1438 return ldb_next_request(ac->module, rename_req);
1441 static int objectclass_do_delete(struct oc_context *ac);
1443 static int objectclass_delete(struct ldb_module *module, struct ldb_request *req)
1445 static const char * const attrs[] = { "nCName", "objectClass",
1447 "isCriticalSystemObject", NULL };
1448 struct ldb_context *ldb;
1449 struct ldb_request *search_req;
1450 struct oc_context *ac;
1453 ldb = ldb_module_get_ctx(module);
1455 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_delete\n");
1457 /* do not manipulate our control entries */
1458 if (ldb_dn_is_special(req->op.del.dn)) {
1459 return ldb_next_request(module, req);
1462 /* Bypass the constraint checks when we do have the "RELAX" control
1464 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) != NULL) {
1465 return ldb_next_request(module, req);
1468 ac = oc_init_context(module, req);
1470 return ldb_operr(ldb);
1473 /* this looks up the entry object for fetching some important
1474 * informations (object classes, system flags...) */
1475 ret = ldb_build_search_req(&search_req, ldb,
1476 ac, req->op.del.dn, LDB_SCOPE_BASE,
1479 ac, get_search_callback,
1481 LDB_REQ_SET_LOCATION(search_req);
1482 if (ret != LDB_SUCCESS) {
1486 ac->step_fn = objectclass_do_delete;
1488 return ldb_next_request(ac->module, search_req);
1491 static int objectclass_do_delete(struct oc_context *ac)
1493 struct ldb_context *ldb;
1495 int32_t systemFlags;
1496 bool isCriticalSystemObject;
1499 ldb = ldb_module_get_ctx(ac->module);
1501 /* Check if we have a valid entry - this check is needed since
1502 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1503 if (ac->search_res == NULL) {
1504 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, entry does not exist!",
1505 ldb_dn_get_linearized(ac->req->op.del.dn));
1506 return LDB_ERR_NO_SUCH_OBJECT;
1509 /* DC's ntDSDSA object */
1510 if (ldb_dn_compare(ac->req->op.del.dn, samdb_ntds_settings_dn(ldb)) == 0) {
1511 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's ntDSDSA object!",
1512 ldb_dn_get_linearized(ac->req->op.del.dn));
1513 return LDB_ERR_UNWILLING_TO_PERFORM;
1516 /* DC's rIDSet object */
1517 /* Perform this check only when it does exist - this is needed in order
1518 * to don't let existing provisions break. */
1519 ret = samdb_rid_set_dn(ldb, ac, &dn);
1520 if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
1523 if (ret == LDB_SUCCESS) {
1524 if (ldb_dn_compare(ac->req->op.del.dn, dn) == 0) {
1526 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's rIDSet object!",
1527 ldb_dn_get_linearized(ac->req->op.del.dn));
1528 return LDB_ERR_UNWILLING_TO_PERFORM;
1533 /* crossRef objects regarding config, schema and default domain NCs */
1534 if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass",
1535 "crossRef") != NULL) {
1536 dn = ldb_msg_find_attr_as_dn(ldb, ac, ac->search_res->message,
1538 if ((ldb_dn_compare(dn, ldb_get_default_basedn(ldb)) == 0) ||
1539 (ldb_dn_compare(dn, ldb_get_config_basedn(ldb)) == 0)) {
1542 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the main or configuration partition!",
1543 ldb_dn_get_linearized(ac->req->op.del.dn));
1544 return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF;
1546 if (ldb_dn_compare(dn, ldb_get_schema_basedn(ldb)) == 0) {
1549 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the schema partition!",
1550 ldb_dn_get_linearized(ac->req->op.del.dn));
1551 return LDB_ERR_UNWILLING_TO_PERFORM;
1558 systemFlags = ldb_msg_find_attr_as_int(ac->search_res->message,
1560 if ((systemFlags & SYSTEM_FLAG_DISALLOW_DELETE) != 0) {
1561 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it isn't permitted!",
1562 ldb_dn_get_linearized(ac->req->op.del.dn));
1563 return LDB_ERR_UNWILLING_TO_PERFORM;
1566 /* isCriticalSystemObject - but this only applies on tree delete
1567 * operations - MS-ADTS 3.1.1.5.5.7.2 */
1568 if (ldb_request_get_control(ac->req, LDB_CONTROL_TREE_DELETE_OID) != NULL) {
1569 isCriticalSystemObject = ldb_msg_find_attr_as_bool(ac->search_res->message,
1570 "isCriticalSystemObject", false);
1571 if (isCriticalSystemObject) {
1572 ldb_asprintf_errstring(ldb,
1573 "objectclass: Cannot tree-delete %s, it's a critical system object!",
1574 ldb_dn_get_linearized(ac->req->op.del.dn));
1575 return LDB_ERR_UNWILLING_TO_PERFORM;
1579 return ldb_next_request(ac->module, ac->req);
1582 static int objectclass_init(struct ldb_module *module)
1584 struct ldb_context *ldb = ldb_module_get_ctx(module);
1587 /* Init everything else */
1588 ret = ldb_next_init(module);
1589 if (ret != LDB_SUCCESS) {
1593 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1594 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1596 ret = ldb_mod_register_control(module, LDB_CONTROL_RODC_DCPROMO_OID);
1597 if (ret != LDB_SUCCESS) {
1598 ldb_debug(ldb, LDB_DEBUG_ERROR,
1599 "objectclass_init: Unable to register control DCPROMO with rootdse\n");
1600 return ldb_operr(ldb);
1606 static const struct ldb_module_ops ldb_objectclass_module_ops = {
1607 .name = "objectclass",
1608 .add = objectclass_add,
1609 .modify = objectclass_modify,
1610 .rename = objectclass_rename,
1611 .del = objectclass_delete,
1612 .init_context = objectclass_init
1615 int ldb_objectclass_module_init(const char *version)
1617 LDB_MODULE_CHECK_VERSION(version);
1618 return ldb_register_module(&ldb_objectclass_module_ops);