4 Copyright (C) Simo Sorce 2006-2008
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
6 Copyright (C) Matthias Dieter Wallnöfer 2010
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 * Component: objectClass sorting and constraint checking module
28 * - sort the objectClass attribute into the class
29 * hierarchy and perform constraint checks (correct RDN name,
31 * - fix DNs into 'standard' case
32 * - Add objectCategory and some other attribute defaults
34 * Author: Andrew Bartlett
39 #include "ldb_module.h"
40 #include "util/dlinklist.h"
41 #include "dsdb/samdb/samdb.h"
42 #include "librpc/ndr/libndr.h"
43 #include "librpc/gen_ndr/ndr_security.h"
44 #include "libcli/security/security.h"
45 #include "auth/auth.h"
46 #include "param/param.h"
47 #include "../libds/common/flags.h"
48 #include "dsdb/samdb/ldb_modules/schema.h"
53 struct ldb_module *module;
54 struct ldb_request *req;
55 const struct dsdb_schema *schema;
57 struct ldb_reply *search_res;
58 struct ldb_reply *search_res2;
60 int (*step_fn)(struct oc_context *);
64 struct class_list *prev, *next;
65 const struct dsdb_class *objectclass;
68 static struct oc_context *oc_init_context(struct ldb_module *module,
69 struct ldb_request *req)
71 struct ldb_context *ldb;
72 struct oc_context *ac;
74 ldb = ldb_module_get_ctx(module);
76 ac = talloc_zero(req, struct oc_context);
84 ac->schema = dsdb_get_schema(ldb, ac);
89 static int objectclass_do_add(struct oc_context *ac);
91 /* Sort objectClasses into correct order, and validate that all
92 * objectClasses specified actually exist in the schema
95 static int objectclass_sort(struct ldb_module *module,
96 const struct dsdb_schema *schema,
98 struct ldb_message_element *objectclass_element,
99 struct class_list **sorted_out)
101 struct ldb_context *ldb;
102 unsigned int i, lowest;
103 struct class_list *unsorted = NULL, *sorted = NULL, *current = NULL, *poss_parent = NULL, *new_parent = NULL, *current_lowest = NULL;
105 ldb = ldb_module_get_ctx(module);
109 * We work on 4 different 'bins' (implemented here as linked lists):
111 * * sorted: the eventual list, in the order we wish to push
112 * into the database. This is the only ordered list.
114 * * parent_class: The current parent class 'bin' we are
115 * trying to find subclasses for
117 * * subclass: The subclasses we have found so far
119 * * unsorted: The remaining objectClasses
121 * The process is a matter of filtering objectClasses up from
122 * unsorted into sorted. Order is irrelevent in the later 3 'bins'.
124 * We start with 'top' (found and promoted to parent_class
125 * initially). Then we find (in unsorted) all the direct
126 * subclasses of 'top'. parent_classes is concatenated onto
127 * the end of 'sorted', and subclass becomes the list in
130 * We then repeat, until we find no more subclasses. Any left
131 * over classes are added to the end.
135 /* Firstly, dump all the objectClass elements into the
136 * unsorted bin, except for 'top', which is special */
137 for (i=0; i < objectclass_element->num_values; i++) {
138 current = talloc(mem_ctx, struct class_list);
142 current->objectclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &objectclass_element->values[i]);
143 if (!current->objectclass) {
144 ldb_asprintf_errstring(ldb, "objectclass %.*s is not a valid objectClass in schema",
145 (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
146 /* This looks weird, but windows apparently returns this for invalid objectClass values */
147 return LDB_ERR_NO_SUCH_ATTRIBUTE;
148 } else if (current->objectclass->isDefunct) {
149 ldb_asprintf_errstring(ldb, "objectclass %.*s marked as isDefunct objectClass in schema - not valid for new objects",
150 (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
151 /* This looks weird, but windows apparently returns this for invalid objectClass values */
152 return LDB_ERR_NO_SUCH_ATTRIBUTE;
155 /* Don't add top to list, we will do that later */
156 if (ldb_attr_cmp("top", current->objectclass->lDAPDisplayName) != 0) {
157 DLIST_ADD_END(unsorted, current, struct class_list *);
161 /* Add top here, to prevent duplicates */
162 current = talloc(mem_ctx, struct class_list);
163 current->objectclass = dsdb_class_by_lDAPDisplayName(schema, "top");
164 DLIST_ADD_END(sorted, current, struct class_list *);
167 /* For each object: find parent chain */
168 for (current = unsorted; schema && current; current = current->next) {
169 for (poss_parent = unsorted; poss_parent; poss_parent = poss_parent->next) {
170 if (ldb_attr_cmp(poss_parent->objectclass->lDAPDisplayName, current->objectclass->subClassOf) == 0) {
174 /* If we didn't get to the end of the list, we need to add this parent */
175 if (poss_parent || (ldb_attr_cmp("top", current->objectclass->subClassOf) == 0)) {
179 new_parent = talloc(mem_ctx, struct class_list);
180 new_parent->objectclass = dsdb_class_by_lDAPDisplayName(schema, current->objectclass->subClassOf);
181 DLIST_ADD_END(unsorted, new_parent, struct class_list *);
187 current_lowest = NULL;
188 for (current = unsorted; schema && current; current = current->next) {
189 if(current->objectclass->subClass_order < lowest) {
190 current_lowest = current;
191 lowest = current->objectclass->subClass_order;
195 if(current_lowest != NULL) {
196 DLIST_REMOVE(unsorted,current_lowest);
197 DLIST_ADD_END(sorted,current_lowest, struct class_list *);
203 *sorted_out = sorted;
208 /* If we don't have schema yet, then just merge the lists again */
209 DLIST_CONCATENATE(sorted, unsorted, struct class_list *);
210 *sorted_out = sorted;
214 /* This shouldn't happen, and would break MMC, perhaps there
215 * was no 'top', a conflict in the objectClasses or some other
218 ldb_asprintf_errstring(ldb, "objectclass %s is not a valid objectClass in objectClass chain", unsorted->objectclass->lDAPDisplayName);
219 return LDB_ERR_OBJECT_CLASS_VIOLATION;
222 static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
224 struct ldb_context *ldb;
225 struct oc_context *ac;
228 ac = talloc_get_type(req->context, struct oc_context);
229 ldb = ldb_module_get_ctx(ac->module);
232 return ldb_module_done(ac->req, NULL, NULL,
233 LDB_ERR_OPERATIONS_ERROR);
235 if (ares->error != LDB_SUCCESS &&
236 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
237 return ldb_module_done(ac->req, ares->controls,
238 ares->response, ares->error);
241 ldb_reset_err_string(ldb);
243 switch (ares->type) {
244 case LDB_REPLY_ENTRY:
245 if (ac->search_res != NULL) {
246 ldb_set_errstring(ldb, "Too many results");
248 return ldb_module_done(ac->req, NULL, NULL,
249 LDB_ERR_OPERATIONS_ERROR);
252 ac->search_res = talloc_steal(ac, ares);
255 case LDB_REPLY_REFERRAL:
262 ret = ac->step_fn(ac);
263 if (ret != LDB_SUCCESS) {
264 return ldb_module_done(ac->req, NULL, NULL, ret);
272 static int oc_op_callback(struct ldb_request *req, struct ldb_reply *ares)
274 struct oc_context *ac;
276 ac = talloc_get_type(req->context, struct oc_context);
279 return ldb_module_done(ac->req, NULL, NULL,
280 LDB_ERR_OPERATIONS_ERROR);
283 if (ares->type == LDB_REPLY_REFERRAL) {
284 return ldb_module_send_referral(ac->req, ares->referral);
287 if (ares->error != LDB_SUCCESS) {
288 return ldb_module_done(ac->req, ares->controls,
289 ares->response, ares->error);
292 if (ares->type != LDB_REPLY_DONE) {
294 return ldb_module_done(ac->req, NULL, NULL,
295 LDB_ERR_OPERATIONS_ERROR);
298 return ldb_module_done(ac->req, ares->controls,
299 ares->response, ares->error);
302 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
304 This should mean that if the parent is:
305 CN=Users,DC=samba,DC=example,DC=com
306 and a proposed child is
307 cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
309 The resulting DN should be:
311 CN=Admins,CN=Users,DC=samba,DC=example,DC=com
314 static int fix_dn(struct ldb_context *ldb,
316 struct ldb_dn *newdn, struct ldb_dn *parent_dn,
317 struct ldb_dn **fixed_dn)
319 char *upper_rdn_attr;
320 const struct ldb_val *rdn_val;
322 /* Fix up the DN to be in the standard form, taking particular care to
323 * match the parent DN */
324 *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
325 if (*fixed_dn == NULL) {
329 /* We need the attribute name in upper case */
330 upper_rdn_attr = strupper_talloc(*fixed_dn,
331 ldb_dn_get_rdn_name(newdn));
332 if (upper_rdn_attr == NULL) {
336 /* Create a new child */
337 if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
338 return ldb_operr(ldb);
341 rdn_val = ldb_dn_get_rdn_val(newdn);
342 if (rdn_val == NULL) {
343 return ldb_operr(ldb);
347 /* the rules for rDN length constraints are more complex than
348 this. Until we understand them we need to leave this
349 constraint out. Otherwise we break replication, as windows
350 does sometimes send us rDNs longer than 64 */
351 if (!rdn_val || rdn_val->length > 64) {
352 DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
357 /* And replace it with CN=foo (we need the attribute in upper case */
358 return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
362 static int objectclass_do_add(struct oc_context *ac);
364 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
366 struct ldb_context *ldb;
367 struct ldb_request *search_req;
368 struct oc_context *ac;
369 struct ldb_dn *parent_dn;
370 const struct ldb_val *val;
372 static const char * const parent_attrs[] = { "objectClass", NULL };
374 ldb = ldb_module_get_ctx(module);
376 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
378 /* do not manipulate our control entries */
379 if (ldb_dn_is_special(req->op.add.message->dn)) {
380 return ldb_next_request(module, req);
383 /* An add operation on the basedn without "NC-add" operation isn't
385 if (ldb_dn_compare(ldb_get_default_basedn(ldb), req->op.add.message->dn) == 0) {
386 unsigned int instanceType;
388 instanceType = ldb_msg_find_attr_as_uint(req->op.add.message,
390 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
392 /* When we are trying to readd the root basedn then
393 * this is denied, but with an interesting mechanism:
394 * there is generated a referral with the last
395 * component value as hostname. */
396 val = ldb_dn_get_component_val(req->op.add.message->dn,
397 ldb_dn_get_comp_num(req->op.add.message->dn) - 1);
399 return ldb_operr(ldb);
401 referral_uri = talloc_asprintf(req, "ldap://%s/%s", val->data,
402 ldb_dn_get_linearized(req->op.add.message->dn));
403 if (referral_uri == NULL) {
404 return ldb_module_oom(module);
407 return ldb_module_send_referral(req, referral_uri);
411 ac = oc_init_context(module, req);
413 return ldb_operr(ldb);
416 /* If there isn't a parent, just go on to the add processing */
417 if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
418 return objectclass_do_add(ac);
421 /* get copy of parent DN */
422 parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
423 if (parent_dn == NULL) {
424 /* the DN itself might be wrong - therefore
425 * "ERR_INVALID_DN_SYNTAX" fits better here. */
426 return LDB_ERR_INVALID_DN_SYNTAX;
429 ret = ldb_build_search_req(&search_req, ldb,
430 ac, parent_dn, LDB_SCOPE_BASE,
431 "(objectClass=*)", parent_attrs,
433 ac, get_search_callback,
435 LDB_REQ_SET_LOCATION(search_req);
436 if (ret != LDB_SUCCESS) {
440 ac->step_fn = objectclass_do_add;
442 return ldb_next_request(ac->module, search_req);
447 check if this is a special RODC nTDSDSA add
449 static bool check_rodc_ntdsdsa_add(struct oc_context *ac,
450 const struct dsdb_class *objectclass)
452 struct ldb_control *rodc_control;
454 if (strcasecmp(objectclass->lDAPDisplayName, "nTDSDSA") != 0) {
457 rodc_control = ldb_request_get_control(ac->req, LDB_CONTROL_RODC_DCPROMO_OID);
462 rodc_control->critical = false;
466 static int objectclass_do_add(struct oc_context *ac)
468 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
469 struct ldb_request *add_req;
470 struct ldb_message_element *objectclass_element, *el;
471 struct ldb_message *msg;
473 struct class_list *sorted, *current;
474 const char *rdn_name = NULL;
476 const struct dsdb_class *objectclass;
477 struct ldb_dn *objectcategory;
478 int32_t systemFlags = 0;
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(msg, "instanceType",
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 if (ac->schema != NULL) {
520 objectclass_element = ldb_msg_find_element(msg, "objectClass");
521 if (!objectclass_element) {
522 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, no objectclass specified!",
523 ldb_dn_get_linearized(msg->dn));
524 return LDB_ERR_OBJECT_CLASS_VIOLATION;
526 if (objectclass_element->num_values == 0) {
527 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, at least one (structural) objectclass has to be specified!",
528 ldb_dn_get_linearized(msg->dn));
529 return LDB_ERR_CONSTRAINT_VIOLATION;
532 mem_ctx = talloc_new(ac);
533 if (mem_ctx == NULL) {
534 return ldb_module_oom(ac->module);
537 /* Here we do now get the "objectClass" list from the
539 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
540 objectclass_element, &sorted);
541 if (ret != LDB_SUCCESS) {
542 talloc_free(mem_ctx);
546 ldb_msg_remove_element(msg, objectclass_element);
548 /* Well, now we shouldn't find any additional "objectClass"
549 * message element (required by the AD specification). */
550 objectclass_element = ldb_msg_find_element(msg, "objectClass");
551 if (objectclass_element != NULL) {
552 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, only one 'objectclass' attribute specification is allowed!",
553 ldb_dn_get_linearized(msg->dn));
554 talloc_free(mem_ctx);
555 return LDB_ERR_OBJECT_CLASS_VIOLATION;
558 /* We must completely replace the existing objectClass entry,
559 * because we need it sorted. */
560 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
561 if (ret != LDB_SUCCESS) {
562 talloc_free(mem_ctx);
566 /* Move from the linked list back into an ldb msg */
567 for (current = sorted; current; current = current->next) {
568 const char *objectclass_name = current->objectclass->lDAPDisplayName;
570 ret = ldb_msg_add_string(msg, "objectClass", objectclass_name);
571 if (ret != LDB_SUCCESS) {
572 ldb_set_errstring(ldb,
573 "objectclass: could not re-add sorted "
574 "objectclass to modify msg");
575 talloc_free(mem_ctx);
580 talloc_free(mem_ctx);
582 /* Retrive the message again so get_last_structural_class works */
583 objectclass_element = ldb_msg_find_element(msg, "objectClass");
585 /* Make sure its valid to add an object of this type */
586 objectclass = get_last_structural_class(ac->schema,
587 objectclass_element, ac->req);
588 if(objectclass == NULL) {
589 ldb_asprintf_errstring(ldb,
590 "Failed to find a structural class for %s",
591 ldb_dn_get_linearized(msg->dn));
592 return LDB_ERR_UNWILLING_TO_PERFORM;
595 rdn_name = ldb_dn_get_rdn_name(msg->dn);
596 if (rdn_name == NULL) {
597 return ldb_operr(ldb);
600 for (i = 0; (!found) && (i < objectclass_element->num_values);
602 const struct dsdb_class *tmp_class =
603 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
604 &objectclass_element->values[i]);
606 if (tmp_class == NULL) continue;
608 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
612 ldb_asprintf_errstring(ldb,
613 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
614 rdn_name, objectclass->lDAPDisplayName);
615 return LDB_ERR_NAMING_VIOLATION;
618 if (objectclass->systemOnly &&
619 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) &&
620 !check_rodc_ntdsdsa_add(ac, objectclass)) {
621 ldb_asprintf_errstring(ldb,
622 "objectclass: object class '%s' is system-only, rejecting creation of '%s'!",
623 objectclass->lDAPDisplayName,
624 ldb_dn_get_linearized(msg->dn));
625 return LDB_ERR_UNWILLING_TO_PERFORM;
628 if (ac->search_res && ac->search_res->message) {
629 struct ldb_message_element *oc_el
630 = ldb_msg_find_element(ac->search_res->message, "objectClass");
632 bool allowed_class = false;
633 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
634 const struct dsdb_class *sclass;
636 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
639 /* We don't know this class? what is going on? */
642 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
643 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
644 allowed_class = true;
650 if (!allowed_class) {
651 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
652 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
653 return LDB_ERR_NAMING_VIOLATION;
657 objectcategory = ldb_msg_find_attr_as_dn(ldb, ac, msg,
659 if (objectcategory == NULL) {
660 struct dsdb_extended_dn_store_format *dn_format =
661 talloc_get_type(ldb_module_get_private(ac->module),
662 struct dsdb_extended_dn_store_format);
663 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
664 /* Strip off extended components */
665 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
666 objectclass->defaultObjectCategory);
667 value = ldb_dn_alloc_linearized(msg, dn);
670 value = talloc_strdup(msg,
671 objectclass->defaultObjectCategory);
674 return ldb_module_oom(ac->module);
677 ret = ldb_msg_add_string(msg, "objectCategory", value);
678 if (ret != LDB_SUCCESS) {
682 const struct dsdb_class *ocClass =
683 dsdb_class_by_cn_ldb_val(ac->schema,
684 ldb_dn_get_rdn_val(objectcategory));
685 if (ocClass != NULL) {
686 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
687 ocClass->defaultObjectCategory);
688 if (ldb_dn_compare(objectcategory, dn) != 0) {
692 talloc_free(objectcategory);
693 if (ocClass == NULL) {
694 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'objectCategory' attribute invalid!",
695 ldb_dn_get_linearized(msg->dn));
696 return LDB_ERR_OBJECT_CLASS_VIOLATION;
700 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
701 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
705 /* There are very special rules for systemFlags, see MS-ADTS
706 * MS-ADTS 3.1.1.5.2.4 */
708 el = ldb_msg_find_element(msg, "systemFlags");
709 if ((el != NULL) && (el->num_values > 1)) {
710 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'systemFlags' attribute multivalued!",
711 ldb_dn_get_linearized(msg->dn));
712 return LDB_ERR_CONSTRAINT_VIOLATION;
715 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
717 ldb_msg_remove_attr(msg, "systemFlags");
719 /* Only the following flags may be set by a client */
720 if (ldb_request_get_control(ac->req,
721 LDB_CONTROL_RELAX_OID) == NULL) {
722 systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME
723 | SYSTEM_FLAG_CONFIG_ALLOW_MOVE
724 | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE
725 | SYSTEM_FLAG_ATTR_IS_RDN );
728 /* But the last one ("ATTR_IS_RDN") is only allowed on
729 * "attributeSchema" objects. So truncate if it does not fit. */
730 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") != 0) {
731 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
734 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
735 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
736 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
737 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serversContainer") == 0
738 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") == 0) {
739 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
741 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
742 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
743 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
744 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
747 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
749 if (el || systemFlags != 0) {
750 ret = samdb_msg_add_int(ldb, msg, msg, "systemFlags",
752 if (ret != LDB_SUCCESS) {
757 /* make sure that "isCriticalSystemObject" is not specified! */
758 el = ldb_msg_find_element(msg, "isCriticalSystemObject");
760 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
761 ldb_set_errstring(ldb,
762 "objectclass: 'isCriticalSystemObject' must not be specified!");
763 return LDB_ERR_UNWILLING_TO_PERFORM;
767 ret = ldb_msg_sanity_check(ldb, msg);
768 if (ret != LDB_SUCCESS) {
772 ret = ldb_build_add_req(&add_req, ldb, ac,
777 LDB_REQ_SET_LOCATION(add_req);
778 if (ret != LDB_SUCCESS) {
782 /* perform the add */
783 return ldb_next_request(ac->module, add_req);
786 static int oc_modify_callback(struct ldb_request *req,
787 struct ldb_reply *ares);
788 static int objectclass_do_mod(struct oc_context *ac);
790 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
792 struct ldb_context *ldb = ldb_module_get_ctx(module);
793 struct ldb_message_element *objectclass_element;
794 struct ldb_message *msg;
795 struct ldb_request *down_req;
796 struct oc_context *ac;
797 bool oc_changes = false;
800 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
802 /* do not manipulate our control entries */
803 if (ldb_dn_is_special(req->op.mod.message->dn)) {
804 return ldb_next_request(module, req);
807 /* As with the "real" AD we don't accept empty messages */
808 if (req->op.mod.message->num_elements == 0) {
809 ldb_set_errstring(ldb, "objectclass: modify message must have "
810 "elements/attributes!");
811 return LDB_ERR_UNWILLING_TO_PERFORM;
814 ac = oc_init_context(module, req);
816 return ldb_operr(ldb);
819 /* Without schema, there isn't much to do here */
820 if (ac->schema == NULL) {
822 return ldb_next_request(module, req);
825 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
827 return ldb_module_oom(ac->module);
830 /* For now change everything except the objectclasses */
832 objectclass_element = ldb_msg_find_element(msg, "objectClass");
833 if (objectclass_element != NULL) {
834 ldb_msg_remove_attr(msg, "objectClass");
838 /* MS-ADTS 3.1.1.5.3.5 - on a forest level < 2003 we do allow updates
839 * only on application NCs - not on the standard DCs */
841 (dsdb_forest_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
842 struct ldb_dn *nc_root;
844 ret = dsdb_find_nc_root(ldb, ac, req->op.mod.message->dn,
846 if (ret != LDB_SUCCESS) {
850 if ((ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) == 0) ||
851 (ldb_dn_compare(nc_root, ldb_get_config_basedn(ldb)) == 0) ||
852 (ldb_dn_compare(nc_root, ldb_get_schema_basedn(ldb)) == 0)) {
853 ldb_set_errstring(ldb,
854 "objectclass: object class changes on objects under the standard name contexts not allowed!");
855 return LDB_ERR_UNWILLING_TO_PERFORM;
858 talloc_free(nc_root);
861 ret = ldb_build_mod_req(&down_req, ldb, ac,
864 oc_changes ? oc_modify_callback : oc_op_callback,
866 LDB_REQ_SET_LOCATION(down_req);
867 if (ret != LDB_SUCCESS) {
871 return ldb_next_request(module, down_req);
874 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
876 static const char * const attrs[] = { "objectClass", NULL };
877 struct ldb_context *ldb;
878 struct ldb_request *search_req;
879 struct oc_context *ac;
882 ac = talloc_get_type(req->context, struct oc_context);
883 ldb = ldb_module_get_ctx(ac->module);
886 return ldb_module_done(ac->req, NULL, NULL,
887 LDB_ERR_OPERATIONS_ERROR);
890 if (ares->type == LDB_REPLY_REFERRAL) {
891 return ldb_module_send_referral(ac->req, ares->referral);
894 if (ares->error != LDB_SUCCESS) {
895 return ldb_module_done(ac->req, ares->controls,
896 ares->response, ares->error);
899 if (ares->type != LDB_REPLY_DONE) {
901 return ldb_module_done(ac->req, NULL, NULL,
902 LDB_ERR_OPERATIONS_ERROR);
907 /* this looks up the real existing object for fetching some important
908 * information (objectclasses) */
909 ret = ldb_build_search_req(&search_req, ldb,
910 ac, ac->req->op.mod.message->dn,
914 ac, get_search_callback,
916 LDB_REQ_SET_LOCATION(search_req);
917 if (ret != LDB_SUCCESS) {
918 return ldb_module_done(ac->req, NULL, NULL, ret);
921 ac->step_fn = objectclass_do_mod;
923 ret = ldb_next_request(ac->module, search_req);
924 if (ret != LDB_SUCCESS) {
925 return ldb_module_done(ac->req, NULL, NULL, ret);
931 static int objectclass_do_mod(struct oc_context *ac)
933 struct ldb_context *ldb;
934 struct ldb_request *mod_req;
936 struct ldb_message_element *oc_el_entry, *oc_el_change;
937 struct ldb_val *vals;
938 struct ldb_message *msg;
940 struct class_list *sorted, *current;
941 const struct dsdb_class *objectclass;
942 unsigned int i, j, k;
943 bool found, replace = false;
946 ldb = ldb_module_get_ctx(ac->module);
948 /* we should always have a valid entry when we enter here */
949 if (ac->search_res == NULL) {
950 return ldb_operr(ldb);
953 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
955 if (oc_el_entry == NULL) {
956 /* existing entry without a valid object class? */
957 return ldb_operr(ldb);
960 /* use a new message structure */
961 msg = ldb_msg_new(ac);
963 return ldb_module_oom(ac->module);
966 msg->dn = ac->req->op.mod.message->dn;
968 mem_ctx = talloc_new(ac);
969 if (mem_ctx == NULL) {
970 return ldb_module_oom(ac->module);
973 /* We've to walk over all "objectClass" message elements */
974 for (k = 0; k < ac->req->op.mod.message->num_elements; k++) {
975 if (ldb_attr_cmp(ac->req->op.mod.message->elements[k].name,
976 "objectClass") != 0) {
980 oc_el_change = &ac->req->op.mod.message->elements[k];
982 switch (oc_el_change->flags & LDB_FLAG_MOD_MASK) {
983 case LDB_FLAG_MOD_ADD:
984 /* Merge the two message elements */
985 for (i = 0; i < oc_el_change->num_values; i++) {
986 for (j = 0; j < oc_el_entry->num_values; j++) {
987 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
988 (char *)oc_el_entry->values[j].data) == 0) {
989 ldb_asprintf_errstring(ldb,
990 "objectclass: cannot re-add an existing objectclass: '%.*s'!",
991 (int)oc_el_change->values[i].length,
992 (const char *)oc_el_change->values[i].data);
993 talloc_free(mem_ctx);
994 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
997 /* append the new object class value - code was
998 * copied from "ldb_msg_add_value" */
999 vals = talloc_realloc(oc_el_entry, oc_el_entry->values,
1001 oc_el_entry->num_values + 1);
1003 talloc_free(mem_ctx);
1004 return ldb_module_oom(ac->module);
1006 oc_el_entry->values = vals;
1007 oc_el_entry->values[oc_el_entry->num_values] =
1008 oc_el_change->values[i];
1009 ++(oc_el_entry->num_values);
1012 objectclass = get_last_structural_class(ac->schema,
1013 oc_el_change, ac->req);
1014 if (objectclass != NULL) {
1015 ldb_asprintf_errstring(ldb,
1016 "objectclass: cannot add a new top-most structural objectclass '%s'!",
1017 objectclass->lDAPDisplayName);
1018 talloc_free(mem_ctx);
1019 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1022 /* Now do the sorting */
1023 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1024 oc_el_entry, &sorted);
1025 if (ret != LDB_SUCCESS) {
1026 talloc_free(mem_ctx);
1032 case LDB_FLAG_MOD_REPLACE:
1033 /* Do the sorting for the change message element */
1034 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1035 oc_el_change, &sorted);
1036 if (ret != LDB_SUCCESS) {
1037 talloc_free(mem_ctx);
1041 /* this is a replace */
1046 case LDB_FLAG_MOD_DELETE:
1047 /* get the actual top-most structural objectclass */
1048 objectclass = get_last_structural_class(ac->schema,
1049 oc_el_entry, ac->req);
1050 if (objectclass == NULL) {
1051 /* no structural objectclass? */
1052 talloc_free(mem_ctx);
1053 return ldb_operr(ldb);
1056 /* Merge the two message elements */
1057 for (i = 0; i < oc_el_change->num_values; i++) {
1059 for (j = 0; j < oc_el_entry->num_values; j++) {
1060 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
1061 (char *)oc_el_entry->values[j].data) == 0) {
1063 /* delete the object class value
1064 * - code was copied from
1065 * "ldb_msg_remove_element" */
1066 if (j != oc_el_entry->num_values - 1) {
1067 memmove(&oc_el_entry->values[j],
1068 &oc_el_entry->values[j+1],
1069 ((oc_el_entry->num_values-1) - j)*sizeof(struct ldb_val));
1071 --(oc_el_entry->num_values);
1076 /* we cannot delete a not existing
1078 ldb_asprintf_errstring(ldb,
1079 "objectclass: cannot delete this objectclass: '%.*s'!",
1080 (int)oc_el_change->values[i].length,
1081 (const char *)oc_el_change->values[i].data);
1082 talloc_free(mem_ctx);
1083 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1087 /* Make sure that the top-most structural object class
1088 * hasn't been deleted */
1090 for (i = 0; i < oc_el_entry->num_values; i++) {
1091 if (ldb_attr_cmp(objectclass->lDAPDisplayName,
1092 (char *)oc_el_entry->values[i].data) == 0) {
1098 ldb_asprintf_errstring(ldb,
1099 "objectclass: cannot delete the top-most structural objectclass '%s'!",
1100 objectclass->lDAPDisplayName);
1101 talloc_free(mem_ctx);
1102 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1105 /* Now do the sorting */
1106 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1107 oc_el_entry, &sorted);
1108 if (ret != LDB_SUCCESS) {
1109 talloc_free(mem_ctx);
1116 /* (Re)-add an empty "objectClass" attribute on the object
1117 * classes change message "msg". */
1118 ldb_msg_remove_attr(msg, "objectClass");
1119 ret = ldb_msg_add_empty(msg, "objectClass",
1120 LDB_FLAG_MOD_REPLACE, &oc_el_change);
1121 if (ret != LDB_SUCCESS) {
1122 talloc_free(mem_ctx);
1126 /* Move from the linked list back into an ldb msg */
1127 for (current = sorted; current; current = current->next) {
1128 value = talloc_strdup(msg,
1129 current->objectclass->lDAPDisplayName);
1130 if (value == NULL) {
1131 talloc_free(mem_ctx);
1132 return ldb_module_oom(ac->module);
1134 ret = ldb_msg_add_string(msg, "objectClass", value);
1135 if (ret != LDB_SUCCESS) {
1136 ldb_set_errstring(ldb,
1137 "objectclass: could not re-add sorted objectclasses!");
1138 talloc_free(mem_ctx);
1144 /* Well, on replace we are nearly done: we have to test
1145 * if the change and entry message element are identical
1146 * ly. We can use "ldb_msg_element_compare" since now
1147 * the specified objectclasses match for sure in case.
1149 ret = ldb_msg_element_compare(oc_el_entry,
1152 ret = ldb_msg_element_compare(oc_el_change,
1156 /* they are the same so we are done in this
1158 talloc_free(mem_ctx);
1159 return ldb_module_done(ac->req, NULL, NULL,
1162 ldb_set_errstring(ldb,
1163 "objectclass: the specified objectclasses are not exactly the same as on the entry!");
1164 talloc_free(mem_ctx);
1165 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1169 /* Now we've applied all changes from "oc_el_change" to
1170 * "oc_el_entry" therefore the new "oc_el_entry" will be
1171 * "oc_el_change". */
1172 oc_el_entry = oc_el_change;
1175 talloc_free(mem_ctx);
1177 /* Now we have the real and definitive change left to do */
1179 ret = ldb_build_mod_req(&mod_req, ldb, ac,
1184 LDB_REQ_SET_LOCATION(mod_req);
1185 if (ret != LDB_SUCCESS) {
1189 return ldb_next_request(ac->module, mod_req);
1192 static int objectclass_do_rename(struct oc_context *ac);
1194 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1196 static const char * const attrs[] = { "objectClass", NULL };
1197 struct ldb_context *ldb;
1198 struct ldb_request *search_req;
1199 struct oc_context *ac;
1200 struct ldb_dn *parent_dn;
1203 ldb = ldb_module_get_ctx(module);
1205 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1207 /* do not manipulate our control entries */
1208 if (ldb_dn_is_special(req->op.rename.olddn)) {
1209 return ldb_next_request(module, req);
1212 ac = oc_init_context(module, req);
1214 return ldb_operr(ldb);
1217 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1218 if (parent_dn == NULL) {
1219 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, the parent DN does not exist!",
1220 ldb_dn_get_linearized(req->op.rename.olddn));
1221 return LDB_ERR_NO_SUCH_OBJECT;
1224 /* this looks up the parent object for fetching some important
1225 * information (objectclasses, DN normalisation...) */
1226 ret = ldb_build_search_req(&search_req, ldb,
1227 ac, parent_dn, LDB_SCOPE_BASE,
1230 ac, get_search_callback,
1232 LDB_REQ_SET_LOCATION(search_req);
1233 if (ret != LDB_SUCCESS) {
1237 /* we have to add the show recycled control, as otherwise DRS
1238 deletes will be refused as we will think the target parent
1240 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
1243 if (ret != LDB_SUCCESS) {
1247 ac->step_fn = objectclass_do_rename;
1249 return ldb_next_request(ac->module, search_req);
1252 static int objectclass_do_rename2(struct oc_context *ac);
1254 static int objectclass_do_rename(struct oc_context *ac)
1256 static const char * const attrs[] = { "objectClass", NULL };
1257 struct ldb_context *ldb;
1258 struct ldb_request *search_req;
1261 ldb = ldb_module_get_ctx(ac->module);
1263 /* Check if we have a valid parent - this check is needed since
1264 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1265 if (ac->search_res == NULL) {
1266 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1267 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1268 return LDB_ERR_OTHER;
1271 /* now assign "search_res2" to the parent entry to have "search_res"
1272 * free for another lookup */
1273 ac->search_res2 = ac->search_res;
1274 ac->search_res = NULL;
1276 /* this looks up the real existing object for fetching some important
1277 * information (objectclasses) */
1278 ret = ldb_build_search_req(&search_req, ldb,
1279 ac, ac->req->op.rename.olddn,
1283 ac, get_search_callback,
1285 LDB_REQ_SET_LOCATION(search_req);
1286 if (ret != LDB_SUCCESS) {
1290 ac->step_fn = objectclass_do_rename2;
1292 return ldb_next_request(ac->module, search_req);
1295 static int objectclass_do_rename2(struct oc_context *ac)
1297 struct ldb_context *ldb;
1298 struct ldb_request *rename_req;
1299 struct ldb_dn *fixed_dn;
1302 ldb = ldb_module_get_ctx(ac->module);
1304 /* Check if we have a valid entry - this check is needed since
1305 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1306 if (ac->search_res == NULL) {
1307 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, entry does not exist!",
1308 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1309 return LDB_ERR_NO_SUCH_OBJECT;
1312 if (ac->schema != NULL) {
1313 struct ldb_message_element *oc_el_entry, *oc_el_parent;
1314 const struct dsdb_class *objectclass;
1315 const char *rdn_name;
1316 bool allowed_class = false;
1320 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1322 if (oc_el_entry == NULL) {
1323 /* existing entry without a valid object class? */
1324 return ldb_operr(ldb);
1326 objectclass = get_last_structural_class(ac->schema, oc_el_entry, ac->req);
1327 if (objectclass == NULL) {
1328 /* existing entry without a valid object class? */
1329 return ldb_operr(ldb);
1332 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
1333 if (rdn_name == NULL) {
1334 return ldb_operr(ldb);
1337 for (i = 0; (!found) && (i < oc_el_entry->num_values); i++) {
1338 const struct dsdb_class *tmp_class =
1339 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1340 &oc_el_entry->values[i]);
1342 if (tmp_class == NULL) continue;
1344 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
1348 ldb_asprintf_errstring(ldb,
1349 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
1350 rdn_name, objectclass->lDAPDisplayName);
1351 return LDB_ERR_UNWILLING_TO_PERFORM;
1354 oc_el_parent = ldb_msg_find_element(ac->search_res2->message,
1356 if (oc_el_parent == NULL) {
1357 /* existing entry without a valid object class? */
1358 return ldb_operr(ldb);
1361 for (i=0; allowed_class == false && i < oc_el_parent->num_values; i++) {
1362 const struct dsdb_class *sclass;
1364 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1365 &oc_el_parent->values[i]);
1367 /* We don't know this class? what is going on? */
1370 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
1371 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
1372 allowed_class = true;
1378 if (!allowed_class) {
1379 ldb_asprintf_errstring(ldb,
1380 "objectclass: structural objectClass %s is not a valid child class for %s",
1381 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res2->message->dn));
1382 return LDB_ERR_NAMING_VIOLATION;
1386 /* Ensure we are not trying to rename it to be a child of itself */
1387 if ((ldb_dn_compare_base(ac->req->op.rename.olddn,
1388 ac->req->op.rename.newdn) == 0) &&
1389 (ldb_dn_compare(ac->req->op.rename.olddn,
1390 ac->req->op.rename.newdn) != 0)) {
1391 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s to be a child of itself",
1392 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1393 return LDB_ERR_UNWILLING_TO_PERFORM;
1396 /* Fix up the DN to be in the standard form, taking
1397 * particular care to match the parent DN */
1398 ret = fix_dn(ldb, ac,
1399 ac->req->op.rename.newdn,
1400 ac->search_res2->message->dn,
1402 if (ret != LDB_SUCCESS) {
1403 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
1404 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1409 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1410 ac->req->op.rename.olddn, fixed_dn,
1414 LDB_REQ_SET_LOCATION(rename_req);
1415 if (ret != LDB_SUCCESS) {
1419 /* perform the rename */
1420 return ldb_next_request(ac->module, rename_req);
1423 static int objectclass_do_delete(struct oc_context *ac);
1425 static int objectclass_delete(struct ldb_module *module, struct ldb_request *req)
1427 static const char * const attrs[] = { "nCName", "objectClass",
1429 "isCriticalSystemObject", NULL };
1430 struct ldb_context *ldb;
1431 struct ldb_request *search_req;
1432 struct oc_context *ac;
1435 ldb = ldb_module_get_ctx(module);
1437 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_delete\n");
1439 /* do not manipulate our control entries */
1440 if (ldb_dn_is_special(req->op.del.dn)) {
1441 return ldb_next_request(module, req);
1444 /* Bypass the constraint checks when we do have the "RELAX" control
1446 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) != NULL) {
1447 return ldb_next_request(module, req);
1450 ac = oc_init_context(module, req);
1452 return ldb_operr(ldb);
1455 /* this looks up the entry object for fetching some important
1456 * information (object classes, system flags...) */
1457 ret = ldb_build_search_req(&search_req, ldb,
1458 ac, req->op.del.dn, LDB_SCOPE_BASE,
1461 ac, get_search_callback,
1463 LDB_REQ_SET_LOCATION(search_req);
1464 if (ret != LDB_SUCCESS) {
1468 ac->step_fn = objectclass_do_delete;
1470 return ldb_next_request(ac->module, search_req);
1473 static int objectclass_do_delete(struct oc_context *ac)
1475 struct ldb_context *ldb;
1477 int32_t systemFlags;
1478 bool isCriticalSystemObject;
1481 ldb = ldb_module_get_ctx(ac->module);
1483 /* Check if we have a valid entry - this check is needed since
1484 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1485 if (ac->search_res == NULL) {
1486 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, entry does not exist!",
1487 ldb_dn_get_linearized(ac->req->op.del.dn));
1488 return LDB_ERR_NO_SUCH_OBJECT;
1491 /* DC's ntDSDSA object */
1492 if (ldb_dn_compare(ac->req->op.del.dn, samdb_ntds_settings_dn(ldb)) == 0) {
1493 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's ntDSDSA object!",
1494 ldb_dn_get_linearized(ac->req->op.del.dn));
1495 return LDB_ERR_UNWILLING_TO_PERFORM;
1498 /* DC's rIDSet object */
1499 /* Perform this check only when it does exist - this is needed in order
1500 * to don't let existing provisions break. */
1501 ret = samdb_rid_set_dn(ldb, ac, &dn);
1502 if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
1505 if (ret == LDB_SUCCESS) {
1506 if (ldb_dn_compare(ac->req->op.del.dn, dn) == 0) {
1508 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's rIDSet object!",
1509 ldb_dn_get_linearized(ac->req->op.del.dn));
1510 return LDB_ERR_UNWILLING_TO_PERFORM;
1515 /* crossRef objects regarding config, schema and default domain NCs */
1516 if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass",
1517 "crossRef") != NULL) {
1518 dn = ldb_msg_find_attr_as_dn(ldb, ac, ac->search_res->message,
1520 if ((ldb_dn_compare(dn, ldb_get_default_basedn(ldb)) == 0) ||
1521 (ldb_dn_compare(dn, ldb_get_config_basedn(ldb)) == 0)) {
1524 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the main or configuration partition!",
1525 ldb_dn_get_linearized(ac->req->op.del.dn));
1526 return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF;
1528 if (ldb_dn_compare(dn, ldb_get_schema_basedn(ldb)) == 0) {
1531 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the schema partition!",
1532 ldb_dn_get_linearized(ac->req->op.del.dn));
1533 return LDB_ERR_UNWILLING_TO_PERFORM;
1540 systemFlags = ldb_msg_find_attr_as_int(ac->search_res->message,
1542 if ((systemFlags & SYSTEM_FLAG_DISALLOW_DELETE) != 0) {
1543 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it isn't permitted!",
1544 ldb_dn_get_linearized(ac->req->op.del.dn));
1545 return LDB_ERR_UNWILLING_TO_PERFORM;
1548 /* isCriticalSystemObject - but this only applies on tree delete
1549 * operations - MS-ADTS 3.1.1.5.5.7.2 */
1550 if (ldb_request_get_control(ac->req, LDB_CONTROL_TREE_DELETE_OID) != NULL) {
1551 isCriticalSystemObject = ldb_msg_find_attr_as_bool(ac->search_res->message,
1552 "isCriticalSystemObject", false);
1553 if (isCriticalSystemObject) {
1554 ldb_asprintf_errstring(ldb,
1555 "objectclass: Cannot tree-delete %s, it's a critical system object!",
1556 ldb_dn_get_linearized(ac->req->op.del.dn));
1557 return LDB_ERR_UNWILLING_TO_PERFORM;
1561 return ldb_next_request(ac->module, ac->req);
1564 static int objectclass_init(struct ldb_module *module)
1566 struct ldb_context *ldb = ldb_module_get_ctx(module);
1569 /* Init everything else */
1570 ret = ldb_next_init(module);
1571 if (ret != LDB_SUCCESS) {
1575 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1576 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1578 ret = ldb_mod_register_control(module, LDB_CONTROL_RODC_DCPROMO_OID);
1579 if (ret != LDB_SUCCESS) {
1580 ldb_debug(ldb, LDB_DEBUG_ERROR,
1581 "objectclass_init: Unable to register control DCPROMO with rootdse\n");
1582 return ldb_operr(ldb);
1588 static const struct ldb_module_ops ldb_objectclass_module_ops = {
1589 .name = "objectclass",
1590 .add = objectclass_add,
1591 .modify = objectclass_modify,
1592 .rename = objectclass_rename,
1593 .del = objectclass_delete,
1594 .init_context = objectclass_init
1597 int ldb_objectclass_module_init(const char *version)
1599 LDB_MODULE_CHECK_VERSION(version);
1600 return ldb_register_module(&ldb_objectclass_module_ops);