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-2011
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"
49 #include "dsdb/samdb/ldb_modules/util.h"
53 struct ldb_module *module;
54 struct ldb_request *req;
55 const struct dsdb_schema *schema;
57 struct ldb_reply *search_res;
58 struct ldb_reply *search_res2;
60 int (*step_fn)(struct oc_context *);
64 struct class_list *prev, *next;
65 const struct dsdb_class *objectclass;
68 static struct oc_context *oc_init_context(struct ldb_module *module,
69 struct ldb_request *req)
71 struct ldb_context *ldb;
72 struct oc_context *ac;
74 ldb = ldb_module_get_ctx(module);
76 ac = talloc_zero(req, struct oc_context);
84 ac->schema = dsdb_get_schema(ldb, ac);
89 static int objectclass_do_add(struct oc_context *ac);
91 /* Sort objectClasses into correct order, and validate that all
92 * objectClasses specified actually exist in the schema
95 static int objectclass_sort(struct ldb_module *module,
96 const struct dsdb_schema *schema,
98 struct ldb_message_element *objectclass_element,
99 struct class_list **sorted_out)
101 struct ldb_context *ldb;
102 unsigned int i, lowest;
103 struct class_list *unsorted = NULL, *sorted = NULL, *current = NULL, *poss_parent = NULL, *new_parent = NULL, *current_lowest = NULL;
105 ldb = ldb_module_get_ctx(module);
109 * We work on 4 different 'bins' (implemented here as linked lists):
111 * * sorted: the eventual list, in the order we wish to push
112 * into the database. This is the only ordered list.
114 * * parent_class: The current parent class 'bin' we are
115 * trying to find subclasses for
117 * * subclass: The subclasses we have found so far
119 * * unsorted: The remaining objectClasses
121 * The process is a matter of filtering objectClasses up from
122 * unsorted into sorted. Order is irrelevent in the later 3 'bins'.
124 * We start with 'top' (found and promoted to parent_class
125 * initially). Then we find (in unsorted) all the direct
126 * subclasses of 'top'. parent_classes is concatenated onto
127 * the end of 'sorted', and subclass becomes the list in
130 * We then repeat, until we find no more subclasses. Any left
131 * over classes are added to the end.
135 /* Firstly, dump all the objectClass elements into the
136 * unsorted bin, except for 'top', which is special */
137 for (i=0; i < objectclass_element->num_values; i++) {
138 current = talloc(mem_ctx, struct class_list);
142 current->objectclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &objectclass_element->values[i]);
143 if (!current->objectclass) {
144 ldb_asprintf_errstring(ldb, "objectclass %.*s is not a valid objectClass in schema",
145 (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
146 /* This looks weird, but windows apparently returns this for invalid objectClass values */
147 return LDB_ERR_NO_SUCH_ATTRIBUTE;
148 } else if (current->objectclass->isDefunct) {
149 ldb_asprintf_errstring(ldb, "objectclass %.*s marked as isDefunct objectClass in schema - not valid for new objects",
150 (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
151 /* This looks weird, but windows apparently returns this for invalid objectClass values */
152 return LDB_ERR_NO_SUCH_ATTRIBUTE;
155 /* Don't add top to list, we will do that later */
156 if (ldb_attr_cmp("top", current->objectclass->lDAPDisplayName) != 0) {
157 DLIST_ADD_END(unsorted, current, struct class_list *);
161 /* Add top here, to prevent duplicates */
162 current = talloc(mem_ctx, struct class_list);
163 current->objectclass = dsdb_class_by_lDAPDisplayName(schema, "top");
164 DLIST_ADD_END(sorted, current, struct class_list *);
167 /* For each object: find parent chain */
168 for (current = unsorted; schema && current; current = current->next) {
169 for (poss_parent = unsorted; poss_parent; poss_parent = poss_parent->next) {
170 if (ldb_attr_cmp(poss_parent->objectclass->lDAPDisplayName, current->objectclass->subClassOf) == 0) {
174 /* If we didn't get to the end of the list, we need to add this parent */
175 if (poss_parent || (ldb_attr_cmp("top", current->objectclass->subClassOf) == 0)) {
179 new_parent = talloc(mem_ctx, struct class_list);
180 new_parent->objectclass = dsdb_class_by_lDAPDisplayName(schema, current->objectclass->subClassOf);
181 DLIST_ADD_END(unsorted, new_parent, struct class_list *);
187 current_lowest = NULL;
188 for (current = unsorted; schema && current; current = current->next) {
189 if(current->objectclass->subClass_order < lowest) {
190 current_lowest = current;
191 lowest = current->objectclass->subClass_order;
195 if(current_lowest != NULL) {
196 DLIST_REMOVE(unsorted,current_lowest);
197 DLIST_ADD_END(sorted,current_lowest, struct class_list *);
203 *sorted_out = sorted;
208 /* If we don't have schema yet, then just merge the lists again */
209 DLIST_CONCATENATE(sorted, unsorted, struct class_list *);
210 *sorted_out = sorted;
214 /* This shouldn't happen, and would break MMC, perhaps there
215 * was no 'top', a conflict in the objectClasses or some other
218 ldb_asprintf_errstring(ldb, "objectclass %s is not a valid objectClass in objectClass chain", unsorted->objectclass->lDAPDisplayName);
219 return LDB_ERR_OBJECT_CLASS_VIOLATION;
222 static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
224 struct ldb_context *ldb;
225 struct oc_context *ac;
228 ac = talloc_get_type(req->context, struct oc_context);
229 ldb = ldb_module_get_ctx(ac->module);
232 return ldb_module_done(ac->req, NULL, NULL,
233 LDB_ERR_OPERATIONS_ERROR);
235 if (ares->error != LDB_SUCCESS &&
236 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
237 return ldb_module_done(ac->req, ares->controls,
238 ares->response, ares->error);
241 ldb_reset_err_string(ldb);
243 switch (ares->type) {
244 case LDB_REPLY_ENTRY:
245 if (ac->search_res != NULL) {
246 ldb_set_errstring(ldb, "Too many results");
248 return ldb_module_done(ac->req, NULL, NULL,
249 LDB_ERR_OPERATIONS_ERROR);
252 ac->search_res = talloc_steal(ac, ares);
255 case LDB_REPLY_REFERRAL:
262 ret = ac->step_fn(ac);
263 if (ret != LDB_SUCCESS) {
264 return ldb_module_done(ac->req, NULL, NULL, ret);
272 static int oc_op_callback(struct ldb_request *req, struct ldb_reply *ares)
274 struct oc_context *ac;
276 ac = talloc_get_type(req->context, struct oc_context);
279 return ldb_module_done(ac->req, NULL, NULL,
280 LDB_ERR_OPERATIONS_ERROR);
283 if (ares->type == LDB_REPLY_REFERRAL) {
284 return ldb_module_send_referral(ac->req, ares->referral);
287 if (ares->error != LDB_SUCCESS) {
288 return ldb_module_done(ac->req, ares->controls,
289 ares->response, ares->error);
292 if (ares->type != LDB_REPLY_DONE) {
294 return ldb_module_done(ac->req, NULL, NULL,
295 LDB_ERR_OPERATIONS_ERROR);
298 return ldb_module_done(ac->req, ares->controls,
299 ares->response, ares->error);
302 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
304 This should mean that if the parent is:
305 CN=Users,DC=samba,DC=example,DC=com
306 and a proposed child is
307 cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
309 The resulting DN should be:
311 CN=Admins,CN=Users,DC=samba,DC=example,DC=com
314 static int fix_dn(struct ldb_context *ldb,
316 struct ldb_dn *newdn, struct ldb_dn *parent_dn,
317 struct ldb_dn **fixed_dn)
319 char *upper_rdn_attr;
320 const struct ldb_val *rdn_val;
322 /* Fix up the DN to be in the standard form, taking particular care to
323 * match the parent DN */
324 *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
325 if (*fixed_dn == NULL) {
329 /* We need the attribute name in upper case */
330 upper_rdn_attr = strupper_talloc(*fixed_dn,
331 ldb_dn_get_rdn_name(newdn));
332 if (upper_rdn_attr == NULL) {
336 /* Create a new child */
337 if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
338 return ldb_operr(ldb);
341 rdn_val = ldb_dn_get_rdn_val(newdn);
342 if (rdn_val == NULL) {
343 return ldb_operr(ldb);
347 /* the rules for rDN length constraints are more complex than
348 this. Until we understand them we need to leave this
349 constraint out. Otherwise we break replication, as windows
350 does sometimes send us rDNs longer than 64 */
351 if (!rdn_val || rdn_val->length > 64) {
352 DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
357 /* And replace it with CN=foo (we need the attribute in upper case) */
358 return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
362 static int objectclass_do_add(struct oc_context *ac);
364 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
366 struct ldb_context *ldb;
367 struct ldb_request *search_req;
368 struct oc_context *ac;
369 struct ldb_dn *parent_dn;
370 const struct ldb_val *val;
372 static const char * const parent_attrs[] = { "objectClass", NULL };
374 ldb = ldb_module_get_ctx(module);
376 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
378 /* do not manipulate our control entries */
379 if (ldb_dn_is_special(req->op.add.message->dn)) {
380 return ldb_next_request(module, req);
383 /* An add operation on the basedn without "NC-add" operation isn't
385 if (ldb_dn_compare(ldb_get_default_basedn(ldb), req->op.add.message->dn) == 0) {
386 unsigned int instanceType;
388 instanceType = ldb_msg_find_attr_as_uint(req->op.add.message,
390 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
392 /* When we are trying to readd the root basedn then
393 * this is denied, but with an interesting mechanism:
394 * there is generated a referral with the last
395 * component value as hostname. */
396 val = ldb_dn_get_component_val(req->op.add.message->dn,
397 ldb_dn_get_comp_num(req->op.add.message->dn) - 1);
399 return ldb_operr(ldb);
401 referral_uri = talloc_asprintf(req, "ldap://%s/%s", val->data,
402 ldb_dn_get_linearized(req->op.add.message->dn));
403 if (referral_uri == NULL) {
404 return ldb_module_oom(module);
407 return ldb_module_send_referral(req, referral_uri);
411 ac = oc_init_context(module, req);
413 return ldb_operr(ldb);
416 /* If there isn't a parent, just go on to the add processing */
417 if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
418 return objectclass_do_add(ac);
421 /* get copy of parent DN */
422 parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
423 if (parent_dn == NULL) {
424 return ldb_operr(ldb);
427 ret = ldb_build_search_req(&search_req, ldb,
428 ac, parent_dn, LDB_SCOPE_BASE,
429 "(objectClass=*)", parent_attrs,
431 ac, get_search_callback,
433 LDB_REQ_SET_LOCATION(search_req);
434 if (ret != LDB_SUCCESS) {
438 ac->step_fn = objectclass_do_add;
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 (ldb_attr_cmp(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 = ldb_module_get_ctx(ac->module);
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 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
483 return ldb_module_oom(ac->module);
486 /* Check if we have a valid parent - this check is needed since
487 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
488 if (ac->search_res == NULL) {
489 unsigned int instanceType;
491 /* An add operation on partition DNs without "NC-add" operation
493 instanceType = ldb_msg_find_attr_as_uint(msg, "instanceType",
495 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
496 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!",
497 ldb_dn_get_linearized(msg->dn));
498 return LDB_ERR_NO_SUCH_OBJECT;
501 /* Don't keep any error messages - we've to add a partition */
502 ldb_set_errstring(ldb, NULL);
504 /* Fix up the DN to be in the standard form, taking
505 * particular care to match the parent DN */
506 ret = fix_dn(ldb, msg,
507 ac->req->op.add.message->dn,
508 ac->search_res->message->dn,
510 if (ret != LDB_SUCCESS) {
511 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
512 ldb_dn_get_linearized(ac->req->op.add.message->dn));
517 if (ac->schema != NULL) {
518 objectclass_element = ldb_msg_find_element(msg, "objectClass");
519 if (!objectclass_element) {
520 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, no objectclass specified!",
521 ldb_dn_get_linearized(msg->dn));
522 return LDB_ERR_OBJECT_CLASS_VIOLATION;
524 if (objectclass_element->num_values == 0) {
525 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, at least one (structural) objectclass has to be specified!",
526 ldb_dn_get_linearized(msg->dn));
527 return LDB_ERR_CONSTRAINT_VIOLATION;
530 mem_ctx = talloc_new(ac);
531 if (mem_ctx == NULL) {
532 return ldb_module_oom(ac->module);
535 /* Here we do now get the "objectClass" list from the
537 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
538 objectclass_element, &sorted);
539 if (ret != LDB_SUCCESS) {
540 talloc_free(mem_ctx);
544 ldb_msg_remove_element(msg, objectclass_element);
546 /* Well, now we shouldn't find any additional "objectClass"
547 * message element (required by the AD specification). */
548 objectclass_element = ldb_msg_find_element(msg, "objectClass");
549 if (objectclass_element != NULL) {
550 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, only one 'objectclass' attribute specification is allowed!",
551 ldb_dn_get_linearized(msg->dn));
552 talloc_free(mem_ctx);
553 return LDB_ERR_OBJECT_CLASS_VIOLATION;
556 /* We must completely replace the existing objectClass entry,
557 * because we need it sorted. */
558 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
559 if (ret != LDB_SUCCESS) {
560 talloc_free(mem_ctx);
564 /* Move from the linked list back into an ldb msg */
565 for (current = sorted; current; current = current->next) {
566 const char *objectclass_name = current->objectclass->lDAPDisplayName;
568 ret = ldb_msg_add_string(msg, "objectClass", objectclass_name);
569 if (ret != LDB_SUCCESS) {
570 ldb_set_errstring(ldb,
571 "objectclass: could not re-add sorted "
572 "objectclass to modify msg");
573 talloc_free(mem_ctx);
578 talloc_free(mem_ctx);
580 /* Retrive the message again so get_last_structural_class works */
581 objectclass_element = ldb_msg_find_element(msg, "objectClass");
583 /* Make sure its valid to add an object of this type */
584 objectclass = get_last_structural_class(ac->schema,
585 objectclass_element, ac->req);
586 if(objectclass == NULL) {
587 ldb_asprintf_errstring(ldb,
588 "Failed to find a structural class for %s",
589 ldb_dn_get_linearized(msg->dn));
590 return LDB_ERR_UNWILLING_TO_PERFORM;
593 rdn_name = ldb_dn_get_rdn_name(msg->dn);
594 if (rdn_name == NULL) {
595 return ldb_operr(ldb);
598 for (i = 0; (!found) && (i < objectclass_element->num_values);
600 const struct dsdb_class *tmp_class =
601 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
602 &objectclass_element->values[i]);
604 if (tmp_class == NULL) continue;
606 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
610 ldb_asprintf_errstring(ldb,
611 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
612 rdn_name, objectclass->lDAPDisplayName);
613 return LDB_ERR_NAMING_VIOLATION;
616 if (objectclass->systemOnly &&
617 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) &&
618 !check_rodc_ntdsdsa_add(ac, objectclass)) {
619 ldb_asprintf_errstring(ldb,
620 "objectclass: object class '%s' is system-only, rejecting creation of '%s'!",
621 objectclass->lDAPDisplayName,
622 ldb_dn_get_linearized(msg->dn));
623 return LDB_ERR_UNWILLING_TO_PERFORM;
626 if (ac->search_res && ac->search_res->message) {
627 struct ldb_message_element *oc_el
628 = ldb_msg_find_element(ac->search_res->message, "objectClass");
630 bool allowed_class = false;
631 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
632 const struct dsdb_class *sclass;
634 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
637 /* We don't know this class? what is going on? */
640 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
641 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
642 allowed_class = true;
648 if (!allowed_class) {
649 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
650 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
651 return LDB_ERR_NAMING_VIOLATION;
655 objectcategory = ldb_msg_find_attr_as_dn(ldb, ac, msg,
657 if (objectcategory == NULL) {
658 struct dsdb_extended_dn_store_format *dn_format =
659 talloc_get_type(ldb_module_get_private(ac->module),
660 struct dsdb_extended_dn_store_format);
661 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
662 /* Strip off extended components */
663 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
664 objectclass->defaultObjectCategory);
665 value = ldb_dn_alloc_linearized(msg, dn);
668 value = talloc_strdup(msg,
669 objectclass->defaultObjectCategory);
672 return ldb_module_oom(ac->module);
675 ret = ldb_msg_add_string(msg, "objectCategory", value);
676 if (ret != LDB_SUCCESS) {
680 const struct dsdb_class *ocClass =
681 dsdb_class_by_cn_ldb_val(ac->schema,
682 ldb_dn_get_rdn_val(objectcategory));
683 if (ocClass != NULL) {
684 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
685 ocClass->defaultObjectCategory);
686 if (ldb_dn_compare(objectcategory, dn) != 0) {
690 talloc_free(objectcategory);
691 if (ocClass == NULL) {
692 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'objectCategory' attribute invalid!",
693 ldb_dn_get_linearized(msg->dn));
694 return LDB_ERR_OBJECT_CLASS_VIOLATION;
698 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
699 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
703 /* There are very special rules for systemFlags, see MS-ADTS
704 * MS-ADTS 3.1.1.5.2.4 */
706 el = ldb_msg_find_element(msg, "systemFlags");
707 if ((el != NULL) && (el->num_values > 1)) {
708 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'systemFlags' attribute multivalued!",
709 ldb_dn_get_linearized(msg->dn));
710 return LDB_ERR_CONSTRAINT_VIOLATION;
713 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
715 ldb_msg_remove_attr(msg, "systemFlags");
717 /* Only the following flags may be set by a client */
718 if (ldb_request_get_control(ac->req,
719 LDB_CONTROL_RELAX_OID) == NULL) {
720 systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME
721 | SYSTEM_FLAG_CONFIG_ALLOW_MOVE
722 | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE
723 | SYSTEM_FLAG_ATTR_IS_RDN );
726 /* But the last one ("ATTR_IS_RDN") is only allowed on
727 * "attributeSchema" objects. So truncate if it does not fit. */
728 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") != 0) {
729 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
732 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
733 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
734 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
735 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serversContainer") == 0
736 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") == 0) {
737 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0)
738 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
739 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
740 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
741 || ldb_attr_cmp(objectclass->lDAPDisplayName, "subnet") == 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);
746 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
748 if (el || systemFlags != 0) {
749 ret = samdb_msg_add_int(ldb, msg, msg, "systemFlags",
751 if (ret != LDB_SUCCESS) {
756 /* make sure that "isCriticalSystemObject" is not specified! */
757 el = ldb_msg_find_element(msg, "isCriticalSystemObject");
759 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
760 ldb_set_errstring(ldb,
761 "objectclass: 'isCriticalSystemObject' must not be specified!");
762 return LDB_ERR_UNWILLING_TO_PERFORM;
766 ret = ldb_build_add_req(&add_req, ldb, ac,
771 LDB_REQ_SET_LOCATION(add_req);
772 if (ret != LDB_SUCCESS) {
776 /* perform the add */
777 return ldb_next_request(ac->module, add_req);
780 static int oc_modify_callback(struct ldb_request *req,
781 struct ldb_reply *ares);
782 static int objectclass_do_mod(struct oc_context *ac);
784 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
786 struct ldb_context *ldb = ldb_module_get_ctx(module);
787 struct ldb_message_element *objectclass_element;
788 struct ldb_message *msg;
789 struct ldb_request *down_req;
790 struct oc_context *ac;
791 bool oc_changes = false;
794 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
796 /* do not manipulate our control entries */
797 if (ldb_dn_is_special(req->op.mod.message->dn)) {
798 return ldb_next_request(module, req);
801 /* As with the "real" AD we don't accept empty messages */
802 if (req->op.mod.message->num_elements == 0) {
803 ldb_set_errstring(ldb, "objectclass: modify message must have "
804 "elements/attributes!");
805 return LDB_ERR_UNWILLING_TO_PERFORM;
808 ac = oc_init_context(module, req);
810 return ldb_operr(ldb);
813 /* Without schema, there isn't much to do here */
814 if (ac->schema == NULL) {
816 return ldb_next_request(module, req);
819 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
821 return ldb_module_oom(ac->module);
824 /* For now change everything except the objectclasses */
826 objectclass_element = ldb_msg_find_element(msg, "objectClass");
827 if (objectclass_element != NULL) {
828 ldb_msg_remove_attr(msg, "objectClass");
832 /* MS-ADTS 3.1.1.5.3.5 - on a forest level < 2003 we do allow updates
833 * only on application NCs - not on the default ones */
835 (dsdb_forest_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
836 struct ldb_dn *nc_root;
838 ret = dsdb_find_nc_root(ldb, ac, req->op.mod.message->dn,
840 if (ret != LDB_SUCCESS) {
844 if ((ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) == 0) ||
845 (ldb_dn_compare(nc_root, ldb_get_config_basedn(ldb)) == 0) ||
846 (ldb_dn_compare(nc_root, ldb_get_schema_basedn(ldb)) == 0)) {
847 ldb_set_errstring(ldb,
848 "objectclass: object class changes on objects under the standard name contexts not allowed!");
849 return LDB_ERR_UNWILLING_TO_PERFORM;
852 talloc_free(nc_root);
855 ret = ldb_build_mod_req(&down_req, ldb, ac,
858 oc_changes ? oc_modify_callback : oc_op_callback,
860 LDB_REQ_SET_LOCATION(down_req);
861 if (ret != LDB_SUCCESS) {
865 return ldb_next_request(module, down_req);
868 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
870 static const char * const attrs[] = { "objectClass", NULL };
871 struct ldb_context *ldb;
872 struct ldb_request *search_req;
873 struct oc_context *ac;
876 ac = talloc_get_type(req->context, struct oc_context);
877 ldb = ldb_module_get_ctx(ac->module);
880 return ldb_module_done(ac->req, NULL, NULL,
881 LDB_ERR_OPERATIONS_ERROR);
884 if (ares->type == LDB_REPLY_REFERRAL) {
885 return ldb_module_send_referral(ac->req, ares->referral);
888 if (ares->error != LDB_SUCCESS) {
889 return ldb_module_done(ac->req, ares->controls,
890 ares->response, ares->error);
893 if (ares->type != LDB_REPLY_DONE) {
895 return ldb_module_done(ac->req, NULL, NULL,
896 LDB_ERR_OPERATIONS_ERROR);
901 /* this looks up the real existing object for fetching some important
902 * information (objectclasses) */
903 ret = ldb_build_search_req(&search_req, ldb,
904 ac, ac->req->op.mod.message->dn,
908 ac, get_search_callback,
910 LDB_REQ_SET_LOCATION(search_req);
911 if (ret != LDB_SUCCESS) {
912 return ldb_module_done(ac->req, NULL, NULL, ret);
915 ac->step_fn = objectclass_do_mod;
917 ret = ldb_next_request(ac->module, search_req);
918 if (ret != LDB_SUCCESS) {
919 return ldb_module_done(ac->req, NULL, NULL, ret);
925 static int objectclass_do_mod(struct oc_context *ac)
927 struct ldb_context *ldb;
928 struct ldb_request *mod_req;
930 struct ldb_message_element *oc_el_entry, *oc_el_change;
931 struct ldb_val *vals;
932 struct ldb_message *msg;
934 struct class_list *sorted, *current;
935 const struct dsdb_class *objectclass;
936 unsigned int i, j, k;
937 bool found, replace = false;
940 ldb = ldb_module_get_ctx(ac->module);
942 /* we should always have a valid entry when we enter here */
943 if (ac->search_res == NULL) {
944 return ldb_operr(ldb);
947 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
949 if (oc_el_entry == NULL) {
950 /* existing entry without a valid object class? */
951 return ldb_operr(ldb);
954 /* use a new message structure */
955 msg = ldb_msg_new(ac);
957 return ldb_module_oom(ac->module);
960 msg->dn = ac->req->op.mod.message->dn;
962 mem_ctx = talloc_new(ac);
963 if (mem_ctx == NULL) {
964 return ldb_module_oom(ac->module);
967 /* We've to walk over all "objectClass" message elements */
968 for (k = 0; k < ac->req->op.mod.message->num_elements; k++) {
969 if (ldb_attr_cmp(ac->req->op.mod.message->elements[k].name,
970 "objectClass") != 0) {
974 oc_el_change = &ac->req->op.mod.message->elements[k];
976 switch (oc_el_change->flags & LDB_FLAG_MOD_MASK) {
977 case LDB_FLAG_MOD_ADD:
978 /* Merge the two message elements */
979 for (i = 0; i < oc_el_change->num_values; i++) {
980 for (j = 0; j < oc_el_entry->num_values; j++) {
981 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
982 (char *)oc_el_entry->values[j].data) == 0) {
983 ldb_asprintf_errstring(ldb,
984 "objectclass: cannot re-add an existing objectclass: '%.*s'!",
985 (int)oc_el_change->values[i].length,
986 (const char *)oc_el_change->values[i].data);
987 talloc_free(mem_ctx);
988 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
991 /* append the new object class value - code was
992 * copied from "ldb_msg_add_value" */
993 vals = talloc_realloc(oc_el_entry, oc_el_entry->values,
995 oc_el_entry->num_values + 1);
997 talloc_free(mem_ctx);
998 return ldb_module_oom(ac->module);
1000 oc_el_entry->values = vals;
1001 oc_el_entry->values[oc_el_entry->num_values] =
1002 oc_el_change->values[i];
1003 ++(oc_el_entry->num_values);
1006 objectclass = get_last_structural_class(ac->schema,
1007 oc_el_change, ac->req);
1008 if (objectclass != NULL) {
1009 ldb_asprintf_errstring(ldb,
1010 "objectclass: cannot add a new top-most structural objectclass '%s'!",
1011 objectclass->lDAPDisplayName);
1012 talloc_free(mem_ctx);
1013 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1016 /* Now do the sorting */
1017 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1018 oc_el_entry, &sorted);
1019 if (ret != LDB_SUCCESS) {
1020 talloc_free(mem_ctx);
1026 case LDB_FLAG_MOD_REPLACE:
1027 /* Do the sorting for the change message element */
1028 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1029 oc_el_change, &sorted);
1030 if (ret != LDB_SUCCESS) {
1031 talloc_free(mem_ctx);
1035 /* this is a replace */
1040 case LDB_FLAG_MOD_DELETE:
1041 /* get the actual top-most structural objectclass */
1042 objectclass = get_last_structural_class(ac->schema,
1043 oc_el_entry, ac->req);
1044 if (objectclass == NULL) {
1045 /* no structural objectclass? */
1046 talloc_free(mem_ctx);
1047 return ldb_operr(ldb);
1050 /* Merge the two message elements */
1051 for (i = 0; i < oc_el_change->num_values; i++) {
1053 for (j = 0; j < oc_el_entry->num_values; j++) {
1054 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
1055 (char *)oc_el_entry->values[j].data) == 0) {
1057 /* delete the object class value
1058 * - code was copied from
1059 * "ldb_msg_remove_element" */
1060 if (j != oc_el_entry->num_values - 1) {
1061 memmove(&oc_el_entry->values[j],
1062 &oc_el_entry->values[j+1],
1063 ((oc_el_entry->num_values-1) - j)*sizeof(struct ldb_val));
1065 --(oc_el_entry->num_values);
1070 /* we cannot delete a not existing
1072 ldb_asprintf_errstring(ldb,
1073 "objectclass: cannot delete this objectclass: '%.*s'!",
1074 (int)oc_el_change->values[i].length,
1075 (const char *)oc_el_change->values[i].data);
1076 talloc_free(mem_ctx);
1077 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1081 /* Make sure that the top-most structural object class
1082 * hasn't been deleted */
1084 for (i = 0; i < oc_el_entry->num_values; i++) {
1085 if (ldb_attr_cmp(objectclass->lDAPDisplayName,
1086 (char *)oc_el_entry->values[i].data) == 0) {
1092 ldb_asprintf_errstring(ldb,
1093 "objectclass: cannot delete the top-most structural objectclass '%s'!",
1094 objectclass->lDAPDisplayName);
1095 talloc_free(mem_ctx);
1096 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1099 /* Now do the sorting */
1100 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1101 oc_el_entry, &sorted);
1102 if (ret != LDB_SUCCESS) {
1103 talloc_free(mem_ctx);
1110 /* (Re)-add an empty "objectClass" attribute on the object
1111 * classes change message "msg". */
1112 ldb_msg_remove_attr(msg, "objectClass");
1113 ret = ldb_msg_add_empty(msg, "objectClass",
1114 LDB_FLAG_MOD_REPLACE, &oc_el_change);
1115 if (ret != LDB_SUCCESS) {
1116 talloc_free(mem_ctx);
1120 /* Move from the linked list back into an ldb msg */
1121 for (current = sorted; current; current = current->next) {
1122 value = talloc_strdup(msg,
1123 current->objectclass->lDAPDisplayName);
1124 if (value == NULL) {
1125 talloc_free(mem_ctx);
1126 return ldb_module_oom(ac->module);
1128 ret = ldb_msg_add_string(msg, "objectClass", value);
1129 if (ret != LDB_SUCCESS) {
1130 ldb_set_errstring(ldb,
1131 "objectclass: could not re-add sorted objectclasses!");
1132 talloc_free(mem_ctx);
1138 /* Well, on replace we are nearly done: we have to test
1139 * if the change and entry message element are identical
1140 * ly. We can use "ldb_msg_element_compare" since now
1141 * the specified objectclasses match for sure in case.
1143 ret = ldb_msg_element_compare(oc_el_entry,
1146 ret = ldb_msg_element_compare(oc_el_change,
1150 /* they are the same so we are done in this
1152 talloc_free(mem_ctx);
1153 return ldb_module_done(ac->req, NULL, NULL,
1156 ldb_set_errstring(ldb,
1157 "objectclass: the specified objectclasses are not exactly the same as on the entry!");
1158 talloc_free(mem_ctx);
1159 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1163 /* Now we've applied all changes from "oc_el_change" to
1164 * "oc_el_entry" therefore the new "oc_el_entry" will be
1165 * "oc_el_change". */
1166 oc_el_entry = oc_el_change;
1169 talloc_free(mem_ctx);
1171 /* Now we have the real and definitive change left to do */
1173 ret = ldb_build_mod_req(&mod_req, ldb, ac,
1178 LDB_REQ_SET_LOCATION(mod_req);
1179 if (ret != LDB_SUCCESS) {
1183 return ldb_next_request(ac->module, mod_req);
1186 static int objectclass_do_rename(struct oc_context *ac);
1188 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1190 static const char * const attrs[] = { "objectClass", NULL };
1191 struct ldb_context *ldb;
1192 struct ldb_request *search_req;
1193 struct oc_context *ac;
1194 struct ldb_dn *parent_dn;
1197 ldb = ldb_module_get_ctx(module);
1199 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1201 /* do not manipulate our control entries */
1202 if (ldb_dn_is_special(req->op.rename.olddn)) {
1203 return ldb_next_request(module, req);
1206 ac = oc_init_context(module, req);
1208 return ldb_operr(ldb);
1211 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1212 if (parent_dn == NULL) {
1213 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, the parent DN does not exist!",
1214 ldb_dn_get_linearized(req->op.rename.olddn));
1215 return LDB_ERR_NO_SUCH_OBJECT;
1218 /* this looks up the parent object for fetching some important
1219 * information (objectclasses, DN normalisation...) */
1220 ret = ldb_build_search_req(&search_req, ldb,
1221 ac, parent_dn, LDB_SCOPE_BASE,
1224 ac, get_search_callback,
1226 LDB_REQ_SET_LOCATION(search_req);
1227 if (ret != LDB_SUCCESS) {
1231 /* we have to add the show recycled control, as otherwise DRS
1232 deletes will be refused as we will think the target parent
1234 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
1237 if (ret != LDB_SUCCESS) {
1241 ac->step_fn = objectclass_do_rename;
1243 return ldb_next_request(ac->module, search_req);
1246 static int objectclass_do_rename2(struct oc_context *ac);
1248 static int objectclass_do_rename(struct oc_context *ac)
1250 static const char * const attrs[] = { "objectClass", NULL };
1251 struct ldb_context *ldb;
1252 struct ldb_request *search_req;
1255 ldb = ldb_module_get_ctx(ac->module);
1257 /* Check if we have a valid parent - this check is needed since
1258 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1259 if (ac->search_res == NULL) {
1260 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1261 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1262 return LDB_ERR_OTHER;
1265 /* now assign "search_res2" to the parent entry to have "search_res"
1266 * free for another lookup */
1267 ac->search_res2 = ac->search_res;
1268 ac->search_res = NULL;
1270 /* this looks up the real existing object for fetching some important
1271 * information (objectclasses) */
1272 ret = ldb_build_search_req(&search_req, ldb,
1273 ac, ac->req->op.rename.olddn,
1277 ac, get_search_callback,
1279 LDB_REQ_SET_LOCATION(search_req);
1280 if (ret != LDB_SUCCESS) {
1284 ac->step_fn = objectclass_do_rename2;
1286 return ldb_next_request(ac->module, search_req);
1289 static int objectclass_do_rename2(struct oc_context *ac)
1291 struct ldb_context *ldb;
1292 struct ldb_request *rename_req;
1293 struct ldb_dn *fixed_dn;
1296 ldb = ldb_module_get_ctx(ac->module);
1298 /* Check if we have a valid entry - this check is needed since
1299 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1300 if (ac->search_res == NULL) {
1301 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, entry does not exist!",
1302 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1303 return LDB_ERR_NO_SUCH_OBJECT;
1306 if (ac->schema != NULL) {
1307 struct ldb_message_element *oc_el_entry, *oc_el_parent;
1308 const struct dsdb_class *objectclass;
1309 const char *rdn_name;
1310 bool allowed_class = false;
1314 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1316 if (oc_el_entry == NULL) {
1317 /* existing entry without a valid object class? */
1318 return ldb_operr(ldb);
1320 objectclass = get_last_structural_class(ac->schema, oc_el_entry, ac->req);
1321 if (objectclass == NULL) {
1322 /* existing entry without a valid object class? */
1323 return ldb_operr(ldb);
1326 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
1327 if (rdn_name == NULL) {
1328 return ldb_operr(ldb);
1331 for (i = 0; (!found) && (i < oc_el_entry->num_values); i++) {
1332 const struct dsdb_class *tmp_class =
1333 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1334 &oc_el_entry->values[i]);
1336 if (tmp_class == NULL) continue;
1338 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
1342 ldb_asprintf_errstring(ldb,
1343 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
1344 rdn_name, objectclass->lDAPDisplayName);
1345 return LDB_ERR_UNWILLING_TO_PERFORM;
1348 oc_el_parent = ldb_msg_find_element(ac->search_res2->message,
1350 if (oc_el_parent == NULL) {
1351 /* existing entry without a valid object class? */
1352 return ldb_operr(ldb);
1355 for (i=0; allowed_class == false && i < oc_el_parent->num_values; i++) {
1356 const struct dsdb_class *sclass;
1358 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1359 &oc_el_parent->values[i]);
1361 /* We don't know this class? what is going on? */
1364 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
1365 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
1366 allowed_class = true;
1372 if (!allowed_class) {
1373 ldb_asprintf_errstring(ldb,
1374 "objectclass: structural objectClass %s is not a valid child class for %s",
1375 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res2->message->dn));
1376 return LDB_ERR_NAMING_VIOLATION;
1380 /* Ensure we are not trying to rename it to be a child of itself */
1381 if ((ldb_dn_compare_base(ac->req->op.rename.olddn,
1382 ac->req->op.rename.newdn) == 0) &&
1383 (ldb_dn_compare(ac->req->op.rename.olddn,
1384 ac->req->op.rename.newdn) != 0)) {
1385 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s to be a child of itself",
1386 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1387 return LDB_ERR_UNWILLING_TO_PERFORM;
1390 /* Fix up the DN to be in the standard form, taking
1391 * particular care to match the parent DN */
1392 ret = fix_dn(ldb, ac,
1393 ac->req->op.rename.newdn,
1394 ac->search_res2->message->dn,
1396 if (ret != LDB_SUCCESS) {
1397 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
1398 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1403 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1404 ac->req->op.rename.olddn, fixed_dn,
1408 LDB_REQ_SET_LOCATION(rename_req);
1409 if (ret != LDB_SUCCESS) {
1413 /* perform the rename */
1414 return ldb_next_request(ac->module, rename_req);
1417 static int objectclass_do_delete(struct oc_context *ac);
1419 static int objectclass_delete(struct ldb_module *module, struct ldb_request *req)
1421 static const char * const attrs[] = { "nCName", "objectClass",
1424 "isCriticalSystemObject", NULL };
1425 struct ldb_context *ldb;
1426 struct ldb_request *search_req;
1427 struct oc_context *ac;
1430 ldb = ldb_module_get_ctx(module);
1432 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_delete\n");
1434 /* do not manipulate our control entries */
1435 if (ldb_dn_is_special(req->op.del.dn)) {
1436 return ldb_next_request(module, req);
1439 /* Bypass the constraint checks when we do have the "RELAX" control
1441 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) != NULL) {
1442 return ldb_next_request(module, req);
1445 ac = oc_init_context(module, req);
1447 return ldb_operr(ldb);
1450 /* this looks up the entry object for fetching some important
1451 * information (object classes, system flags...) */
1452 ret = ldb_build_search_req(&search_req, ldb,
1453 ac, req->op.del.dn, LDB_SCOPE_BASE,
1455 attrs, req->controls,
1456 ac, get_search_callback,
1458 LDB_REQ_SET_LOCATION(search_req);
1459 if (ret != LDB_SUCCESS) {
1463 ac->step_fn = objectclass_do_delete;
1465 return ldb_next_request(ac->module, search_req);
1468 static int objectclass_do_delete(struct oc_context *ac)
1470 struct ldb_context *ldb;
1472 int32_t systemFlags;
1473 bool isCriticalSystemObject;
1476 ldb = ldb_module_get_ctx(ac->module);
1478 /* Check if we have a valid entry - this check is needed since
1479 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1480 if (ac->search_res == NULL) {
1481 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, entry does not exist!",
1482 ldb_dn_get_linearized(ac->req->op.del.dn));
1483 return LDB_ERR_NO_SUCH_OBJECT;
1486 /* DC's ntDSDSA object */
1487 if (ldb_dn_compare(ac->req->op.del.dn, samdb_ntds_settings_dn(ldb)) == 0) {
1488 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's ntDSDSA object!",
1489 ldb_dn_get_linearized(ac->req->op.del.dn));
1490 return LDB_ERR_UNWILLING_TO_PERFORM;
1493 /* DC's rIDSet object */
1494 /* Perform this check only when it does exist - this is needed in order
1495 * to don't let existing provisions break. */
1496 ret = samdb_rid_set_dn(ldb, ac, &dn);
1497 if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
1500 if (ret == LDB_SUCCESS) {
1501 if (ldb_dn_compare(ac->req->op.del.dn, dn) == 0) {
1503 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's rIDSet object!",
1504 ldb_dn_get_linearized(ac->req->op.del.dn));
1505 return LDB_ERR_UNWILLING_TO_PERFORM;
1510 /* Only trusted request from system account are allowed to delete
1513 if (ldb_msg_check_string_attribute(ac->search_res->message, "isDeleted", "TRUE") &&
1514 (ldb_req_is_untrusted(ac->req) ||
1515 !dsdb_module_am_system(ac->module))) {
1516 ldb_asprintf_errstring(ldb, "Delete of '%s' failed",
1517 ldb_dn_get_linearized(ac->req->op.del.dn));
1518 return LDB_ERR_UNWILLING_TO_PERFORM;
1521 /* crossRef objects regarding config, schema and default domain NCs */
1522 if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass",
1523 "crossRef") != NULL) {
1524 dn = ldb_msg_find_attr_as_dn(ldb, ac, ac->search_res->message,
1526 if ((ldb_dn_compare(dn, ldb_get_default_basedn(ldb)) == 0) ||
1527 (ldb_dn_compare(dn, ldb_get_config_basedn(ldb)) == 0)) {
1530 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the main or configuration partition!",
1531 ldb_dn_get_linearized(ac->req->op.del.dn));
1532 return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF;
1534 if (ldb_dn_compare(dn, ldb_get_schema_basedn(ldb)) == 0) {
1537 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the schema partition!",
1538 ldb_dn_get_linearized(ac->req->op.del.dn));
1539 return LDB_ERR_UNWILLING_TO_PERFORM;
1546 systemFlags = ldb_msg_find_attr_as_int(ac->search_res->message,
1548 if ((systemFlags & SYSTEM_FLAG_DISALLOW_DELETE) != 0) {
1549 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it isn't permitted!",
1550 ldb_dn_get_linearized(ac->req->op.del.dn));
1551 return LDB_ERR_UNWILLING_TO_PERFORM;
1554 /* isCriticalSystemObject - but this only applies on tree delete
1555 * operations - MS-ADTS 3.1.1.5.5.7.2 */
1556 if (ldb_request_get_control(ac->req, LDB_CONTROL_TREE_DELETE_OID) != NULL) {
1557 isCriticalSystemObject = ldb_msg_find_attr_as_bool(ac->search_res->message,
1558 "isCriticalSystemObject", false);
1559 if (isCriticalSystemObject) {
1560 ldb_asprintf_errstring(ldb,
1561 "objectclass: Cannot tree-delete %s, it's a critical system object!",
1562 ldb_dn_get_linearized(ac->req->op.del.dn));
1563 return LDB_ERR_UNWILLING_TO_PERFORM;
1567 return ldb_next_request(ac->module, ac->req);
1570 static int objectclass_init(struct ldb_module *module)
1572 struct ldb_context *ldb = ldb_module_get_ctx(module);
1575 /* Init everything else */
1576 ret = ldb_next_init(module);
1577 if (ret != LDB_SUCCESS) {
1581 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1582 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1584 ret = ldb_mod_register_control(module, LDB_CONTROL_RODC_DCPROMO_OID);
1585 if (ret != LDB_SUCCESS) {
1586 ldb_debug(ldb, LDB_DEBUG_ERROR,
1587 "objectclass_init: Unable to register control DCPROMO with rootdse\n");
1588 return ldb_operr(ldb);
1594 static const struct ldb_module_ops ldb_objectclass_module_ops = {
1595 .name = "objectclass",
1596 .add = objectclass_add,
1597 .modify = objectclass_modify,
1598 .rename = objectclass_rename,
1599 .del = objectclass_delete,
1600 .init_context = objectclass_init
1603 int ldb_objectclass_module_init(const char *version)
1605 LDB_MODULE_CHECK_VERSION(version);
1606 return ldb_register_module(&ldb_objectclass_module_ops);